본문 바로가기
대학생활/수업

게임그래픽프로그래밍심화 4주차 - 그래픽스 API와 조명, 텍스처

by se.jeon 2023. 9. 18.
728x90
반응형

Effect 프레임워크의 이해

셰이더 프로그램들과 렌더 상태들을 “Effect”라고 부르는 단위로 조직화하고 관리하는 틀을 제공하는 코드 집합을 의미한다. 빌드 후 디버그용과 릴리즈용으로 생성하여 사용한다.

 

https://github.com/microsoft/FX11

 

GitHub - microsoft/FX11: Effects for Direct3D 11 (FX11) is a management runtime for authoring HLSL shaders, render state, and ru

Effects for Direct3D 11 (FX11) is a management runtime for authoring HLSL shaders, render state, and runtime variables together. - GitHub - microsoft/FX11: Effects for Direct3D 11 (FX11) is a manag...

github.com

 

Effect 구성 요소

- 정적 셰이더, 픽셀 셰이더 하나씩 필수로 구성된다.

- Effect를 구현 하는데 필요한 렌더 상태들

 

Effect 파일
- 파일 확장자 fx파일로 셰이더 코드들, 상수 버퍼의 내용들로 구성된다.
- 적어도 하나의 기법 (technique)을 정의한다.
- 기법(technique) 안에는 적어도 하나의 패스(pass) 포함한다.

 

Effect 파일의 기법(technique)
- fx 파일에서 식별자 technique1로 시작하는 섹션은 하나의 기법으로 정의한다.
- 특정 렌더링 기법을 구현하는 하나 이상의 패스들로 구성된다.

 

Effect 파일의 패스(pass)
- 기법안에 pass로 시작하는 섹션은 하나의 패스로 정의한다.
- 하나의 정점, 픽셀 셰이더, 렌더 상태들로 구성, 셰이더들 추가 가능

조명의 이해

조명(Lighting)

현실감 있게 화면에 존재하는 3D 객체들과 빛들과의 상호작용을 표현하는 핵심 요소이다.

3D 객체들의 표면은 재질의 특성과 광원 특성을 기반으로 조명 방정식을 통해서 최종 색깔이 결정된다.

 

조명방정식(Lighting Equation)

물체의 특정 지점에서의 색을 계산하기 위해 사용 되는 방정식

 

재질(Material)

빛이 물체의 표면과 상호작용하는 방식을 결정하는 속성들의 집합 (반사율, 투명도, 색상) 

 

Lighting Model or Illumination Model (조명 모델)

3D 장면 렌더링 시 빛과 객체에 대한 상호작용을 과학적으로 설명한다.

공간상에서 빛에 따라 물체의 색상, 밝기를 어떻게 계산할지를 결정한다.

 

조명 모델의 분류

- Local Lighting Model

- Global Lighting Model

 

Local Illumination Model (지역 조명 모델)

계산속도가 빨라서 일반적으로 실시간 렌더링에 많이 사용한다.

직접적으로 광원에서 나오는 빛 과의 상호작용만 처리한다.

다른 객체로부터의 반사되거나 투과된 간접적인 빛들은 무시한다.

- Phong, Blinn-Phong, Lambert 

 

(이 구간 다시 봐야 함)

 

Global Illumination Model (전역 조명 모델)

모든 객체들 사이의 빛의 상호작용을 고려하여 처리한다.

실사적인 장면의 처리가 가능하지만, 계산 속도는 느리다.

다른 객체로부터의 반사되거나 투과된 간접적인 빛들도 처리한다.

GPU 성능 향상 전까지는 게임 개발에 많이 사용하지 않았지만 GPU의 발달로 게임 개발에서도 사용 확대되었다.

- Ray Tracing, Radiosity , Path Tracing

 

(영상 시청 - Minecraft with RTX | Official GeForce RTX Ray Tracing Reveal Trailer)

https://youtu.be/91kxRGeg9wQ?si=ED7Yz3WbfZah68RS&t=40 

기본 조명모델의 이해

Ambient Lighting (주변광) : 주변에서 존재하는 여러 객체들과의 상호작용하는 빛
Diffuse Lighting (분산광) : 빛이 표면에 닿으면 모든 방향으로 균등하게 흩어지는 빛
Specular Lighting (반사광) : 객체의 표면에서 빛이 특정 방향으로 반사되는 빛

Ambient Lighting (주변광)

광원으로부터 직접 비추지 않아도 표면에 존재하는 방향성이 없는 빛
▪ 주변에 존재하는 여러 물체와의 상호작용하는 빛의 효과를 단순화
→ A = 𝐿𝑎 ∗ 𝑀𝑎 (𝐿𝑎 : 간접적으로 도달하는 빛의 양, 𝑀𝑎 : 재질의 주변광 색상)
▪ 𝑀𝑎 는 표면이 주변광을 얼마나 흡수하고 반사하는지를 결정
▪ 가상의 빛인 주변광은 장면 전체에 반사,분사 되어 최종적으로 객체의
표면에 도달한 간접광으로 물체의 모든 방향에서 고르게 비춘다는 가정

Diffuse Lighting (분산광)

객체의 표면이 거칠다고 가정하고 빛이 표면에 닿으면 모든 방향으로
균등하게 흩어지는 빛
▪ 분산광 계산은 객체의 표면을 바라보는 시점과 상관없이 독립적

이미지 출처 : LearnWebGL (http://learnwebgl.brown37.net/09_lights/lights_diffuse.html)

과제

//***************************************************************************************
// LightHelper.fx by Frank Luna (C) 2011 All Rights Reserved.
//
// Structures and functions for lighting calculations.
//***************************************************************************************

struct DirectionalLight
{
	float4 Ambient;
	float4 Diffuse;
	float4 Specular;
	float3 Direction;
	float pad;
};

struct PointLight
{ 
	float4 Ambient;
	float4 Diffuse;
	float4 Specular;

	float3 Position;
	float Range;

	float3 Att;
	float pad;
};

struct SpotLight
{
	float4 Ambient;
	float4 Diffuse;
	float4 Specular;

	float3 Position;
	float Range;

	float3 Direction;
	float Spot;

	float3 Att;
	float pad;
};

struct Material
{
	float4 Ambient;
	float4 Diffuse;
	float4 Specular; // w = SpecPower
	float4 Reflect;
};

//---------------------------------------------------------------------------------------
// Computes the ambient, diffuse, and specular terms in the lighting equation
// from a directional light.  We need to output the terms separately because
// later we will modify the individual terms.
//---------------------------------------------------------------------------------------
void ComputeDirectionalLight(Material mat, DirectionalLight L, 
                             float3 normal, float3 toEye,
					         out float4 ambient,
						     out float4 diffuse,
						     out float4 spec)
{
	// Initialize outputs.
	ambient = float4(0.0f, 0.0f, 0.0f, 0.0f);
	diffuse = float4(0.0f, 0.0f, 0.0f, 0.0f);
	spec    = float4(0.0f, 0.0f, 0.0f, 0.0f);

	// The light vector aims opposite the direction the light rays travel.
	float3 lightVec = -L.Direction;

	// Add ambient term.
	ambient = mat.Ambient * L.Ambient;	

	// Add diffuse and specular term, provided the surface is in 
	// the line of site of the light.
	
	float diffuseFactor = dot(lightVec, normal);

	// Flatten to avoid dynamic branching.
	[flatten]
	if( diffuseFactor > 0.0f )
	{
		float3 v         = reflect(-lightVec, normal);
		float specFactor = pow(max(dot(v, toEye), 0.0f), mat.Specular.w);
					
		diffuse = diffuseFactor * mat.Diffuse * L.Diffuse;
		spec    = specFactor * mat.Specular * L.Specular;
	}
}

//---------------------------------------------------------------------------------------
// Computes the ambient, diffuse, and specular terms in the lighting equation
// from a point light.  We need to output the terms separately because
// later we will modify the individual terms.
//---------------------------------------------------------------------------------------
void ComputePointLight(Material mat, PointLight L, float3 pos, float3 normal, float3 toEye,
				   out float4 ambient, out float4 diffuse, out float4 spec)
{
	// Initialize outputs.
	ambient = float4(0.0f, 0.0f, 0.0f, 0.0f);
	diffuse = float4(0.0f, 0.0f, 0.0f, 0.0f);
	spec    = float4(0.0f, 0.0f, 0.0f, 0.0f);

	// The vector from the surface to the light.
	float3 lightVec = L.Position - pos;
		
	// The distance from surface to light.
	float d = length(lightVec);
	
	// Range test.
	if( d > L.Range )
		return;
		
	// Normalize the light vector.
	lightVec /= d; 
	
	// Ambient term.
	ambient = mat.Ambient * L.Ambient;	

	// Add diffuse and specular term, provided the surface is in 
	// the line of site of the light.

	float diffuseFactor = dot(lightVec, normal);

	// Flatten to avoid dynamic branching.
	[flatten]
	if( diffuseFactor > 0.0f )
	{
		float3 v         = reflect(-lightVec, normal);
		float specFactor = pow(max(dot(v, toEye), 0.0f), mat.Specular.w);
					
		diffuse = diffuseFactor * mat.Diffuse * L.Diffuse;
		spec    = specFactor * mat.Specular * L.Specular;
	}

	// Attenuate
	float att = 1.0f / dot(L.Att, float3(1.0f, d, d*d));

	diffuse *= att;
	spec    *= att;
}

//---------------------------------------------------------------------------------------
// Computes the ambient, diffuse, and specular terms in the lighting equation
// from a spotlight.  We need to output the terms separately because
// later we will modify the individual terms.
//---------------------------------------------------------------------------------------
void ComputeSpotLight(Material mat, SpotLight L, float3 pos, float3 normal, float3 toEye,
				  out float4 ambient, out float4 diffuse, out float4 spec)
{
	// Initialize outputs.
	ambient = float4(0.0f, 0.0f, 0.0f, 0.0f);
	diffuse = float4(0.0f, 0.0f, 0.0f, 0.0f);
	spec    = float4(0.0f, 0.0f, 0.0f, 0.0f);

	// The vector from the surface to the light.
	float3 lightVec = L.Position - pos;
		
	// The distance from surface to light.
	float d = length(lightVec);
	
	// Range test.
	if( d > L.Range )
		return;
		
	// Normalize the light vector.
	lightVec /= d; 
	
	// Ambient term.
	ambient = mat.Ambient * L.Ambient;	

	// Add diffuse and specular term, provided the surface is in 
	// the line of site of the light.

	float diffuseFactor = dot(lightVec, normal);

	// Flatten to avoid dynamic branching.
	[flatten]
	if( diffuseFactor > 0.0f )
	{
		float3 v         = reflect(-lightVec, normal);
		float specFactor = pow(max(dot(v, toEye), 0.0f), mat.Specular.w);
					
		diffuse = diffuseFactor * mat.Diffuse * L.Diffuse;
		spec    = specFactor * mat.Specular * L.Specular;
	}
	
	// Scale by spotlight factor and attenuate.
	float spot = pow(max(dot(-lightVec, L.Direction), 0.0f), L.Spot);

	// Scale by spotlight factor and attenuate.
	float att = spot / dot(L.Att, float3(1.0f, d, d*d));

	ambient *= spot;
	diffuse *= att;
	spec    *= att;
}
//=============================================================================
// Basic.fx by Frank Luna (C) 2011 All Rights Reserved.
//
// Basic effect that currently supports transformations, lighting, and texturing.
//=============================================================================

#include "LightHelper.fx"
 


cbuffer cbPerFrame
{
	DirectionalLight gDirLights[3];
	float3 gEyePosW;

	float  gFogStart;
	float  gFogRange;
	float4 gFogColor;
};

cbuffer cbPerObject
{
	float4x4 gWorld;
	float4x4 gWorldInvTranspose;
	float4x4 gWorldViewProj;
	float4x4 gTexTransform;
	Material gMaterial;
}; 

// Nonnumeric values cannot be added to a cbuffer.
Texture2D gDiffuseMap;

SamplerState samAnisotropic
{
	Filter = ANISOTROPIC;
	MaxAnisotropy = 4;

	AddressU = WRAP;
	AddressV = WRAP;
};

struct VertexIn
{
	float3 PosL    : POSITION;
	float3 NormalL : NORMAL;
	float2 Tex     : TEXCOORD;
};

struct VertexOut
{
	float4 PosH    : SV_POSITION;
    float3 PosW    : POSITION;
    float3 NormalW : NORMAL;
	float2 Tex     : TEXCOORD;
};



VertexOut VS(VertexIn vin)
{
	VertexOut vout;
	
	// Transform to world space space.
	vout.PosW    = mul(float4(vin.PosL, 1.0f), gWorld).xyz;
	vout.NormalW = mul(vin.NormalL, (float3x3)gWorldInvTranspose);
		
	// Transform to homogeneous clip space.
	vout.PosH = mul(float4(vin.PosL, 1.0f), gWorldViewProj);
	
	// Output vertex attributes for interpolation across triangle.
	vout.Tex = mul(float4(vin.Tex, 0.0f, 1.0f), gTexTransform).xy;

	return vout;
}
 


float4 PS(VertexOut pin, uniform int gLightCount, uniform bool gUseTexure) : SV_Target
{
	// Interpolating normal can unnormalize it, so normalize it.
    pin.NormalW = normalize(pin.NormalW);

	// The toEye vector is used in lighting.
	float3 toEye = gEyePosW - pin.PosW;

	// Cache the distance to the eye from this surface point.
	float distToEye = length(toEye); 

	// Normalize.
	toEye /= distToEye;
	
    // Default to multiplicative identity.
    float4 texColor = float4(1, 1, 1, 1);
    if(gUseTexure)
	{
		// Sample texture.
		texColor = gDiffuseMap.Sample( samAnisotropic, pin.Tex );
	}
	 
	//
	// Lighting.
	//

	float4 litColor = texColor;
	if( gLightCount > 0  )
	{  
		// Start with a sum of zero. 
		float4 ambient = float4(0.0f, 0.0f, 0.0f, 0.0f);
		float4 diffuse = float4(0.0f, 0.0f, 0.0f, 0.0f);
		float4 spec    = float4(0.0f, 0.0f, 0.0f, 0.0f);

		// Sum the light contribution from each light source.  
		[unroll]
		for(int i = 0; i < gLightCount; ++i)
		{
			float4 A, D, S;
			ComputeDirectionalLight(gMaterial, gDirLights[i], pin.NormalW, toEye, 
				A, D, S);

			ambient += A;
			diffuse += D;
			spec    += S;
		}

		// Modulate with late add.
		litColor = texColor*(ambient + diffuse) + spec;
	}

	// Common to take alpha from diffuse material and texture.
	litColor.a = gMaterial.Diffuse.a * texColor.a;

    return litColor;
}




technique11 Light1
{
    pass P0
    {
        SetVertexShader( CompileShader( vs_5_0, VS() ) );
		SetGeometryShader( NULL );
        SetPixelShader( CompileShader( ps_5_0, PS(1, false) ) );
    }
}

technique11 Light2
{
    pass P0
    {
        SetVertexShader( CompileShader( vs_5_0, VS() ) );
		SetGeometryShader( NULL );
        SetPixelShader( CompileShader( ps_5_0, PS(2, false) ) );
    }
}

technique11 Light3
{
    pass P0
    {
        SetVertexShader( CompileShader( vs_5_0, VS() ) );
		SetGeometryShader( NULL );
        SetPixelShader( CompileShader( ps_5_0, PS(3, false) ) );
    }
}

technique11 Light0Tex
{
    pass P0
    {
        SetVertexShader( CompileShader( vs_5_0, VS() ) );
		SetGeometryShader( NULL );
        SetPixelShader( CompileShader( ps_5_0, PS(0, true) ) );
    }
}

technique11 Light1Tex
{
    pass P0
    {
        SetVertexShader( CompileShader( vs_5_0, VS() ) );
		SetGeometryShader( NULL );
        SetPixelShader( CompileShader( ps_5_0, PS(1, true) ) );
    }
}

technique11 Light2Tex
{
    pass P0
    {
        SetVertexShader( CompileShader( vs_5_0, VS() ) );
		SetGeometryShader( NULL );
        SetPixelShader( CompileShader( ps_5_0, PS(2, true) ) );
    }
}

technique11 Light3Tex
{
    pass P0
    {
        SetVertexShader( CompileShader( vs_5_0, VS() ) );
		SetGeometryShader( NULL );
        SetPixelShader( CompileShader( ps_5_0, PS(3, true) ) );
    }
}

728x90
반응형