- Deferred Rendering : Lighting을 제외한 랜더링을 마친 후 필요한 데이터를 임시로 저장 후, 남은 랜더링(Lighting)을 진행
- 이렇게 하는 이유는 렌더링 과정에서 생성된 임시데이터를 재사용이 가능하다(Depth, Normal, Color)
- 그 임시 데이터를 어디쓰냐? 물어보면 사용할 곳은 다양함 예를들어 Normal을 이용해 새로운 데이터를 생성한다든지 만들기 나름이다.
- 대표적인 예시는 Lighting을 모든 object에 적용하지 않아도 되기에 성능에 유리하다가 있겠지?
UI를 그릴때는 아래의 쉐이더를 쓴다.(빛연산을 무시하려고)
// [Texture Shader]
// g_tex_0 : Output Texture
// AlphaBlend : true
struct VS_TEX_IN
{
float3 pos : POSITION;
float2 uv : TEXCOORD;
};
struct VS_TEX_OUT
{
float4 pos : SV_Position;
float2 uv : TEXCOORD;
};
VS_TEX_OUT VS_Tex(VS_TEX_IN input)
{
VS_TEX_OUT output = (VS_TEX_OUT)0;
output.pos = mul(float4(input.pos, 1.f), g_matWVP);
output.uv = input.uv;
return output;
}
float4 PS_Tex(VS_TEX_OUT input) : SV_Target
{
float4 color = float4(1.f, 1.f, 1.f, 1.f);
if (g_tex_on_0)
color = g_tex_0.Sample(g_sam_0, input.uv);
return color;
}
라이팅 쉐이더
#ifndef _LIGHTING_FX_
#define _LIGHTING_FX_
#include "params.fx"
#include "utils.fx"
struct VS_IN
{
float3 pos : POSITION;
float2 uv : TEXCOORD;
};
struct VS_OUT
{
float4 pos : SV_Position;
float2 uv : TEXCOORD;
};
struct PS_OUT
{
float4 diffuse : SV_Target0;
float4 specular : SV_Target1;
};
// [Directional Light]
// g_int_0 : Light index
// g_tex_0 : Position RT
// g_tex_1 : Normal RT
// Mesh : Rectangle
VS_OUT VS_DirLight(VS_IN input)
{
VS_OUT output = (VS_OUT)0;
output.pos = float4(input.pos * 2.f, 1.f);
output.uv = input.uv;
return output;
}
PS_OUT PS_DirLight(VS_OUT input)
{
PS_OUT output = (PS_OUT)0;
// Position Texture에 데이터가 있는지 확인
float3 viewPos = g_tex_0.Sample(g_sam_0, input.uv).xyz;
if (viewPos.z <= 0.f)
clip(-1); // z가 0일시(카메라 뒤) : clip(-1) = return 0와 동일
// g_tex_1 : Normal RT
float3 viewNormal = g_tex_1.Sample(g_sam_0, input.uv).xyz;
LightColor color = CalculateLightColor(g_int_0, viewNormal, viewPos);
output.diffuse = color.diffuse + color.ambient;
output.specular = color.specular;
return output;
}
// [Point Light]
// g_int_0 : Light index
// g_tex_0 : Position RT
// g_tex_1 : Normal RT
// g_vec2_0 : RenderTarget Resolution
// Mesh : Sphere
VS_OUT VS_PointLight(VS_IN input)
{
VS_OUT output = (VS_OUT)0;
output.pos = mul(float4(input.pos, 1.f), g_matWVP);
output.uv = input.uv;
return output;
}
PS_OUT PS_PointLight(VS_OUT input)
{
PS_OUT output = (PS_OUT)0;
// input.pos = SV_Position = Screen 좌표
float2 uv = float2(input.pos.x / g_vec2_0.x, input.pos.y / g_vec2_0.y);
float3 viewPos = g_tex_0.Sample(g_sam_0, uv).xyz;
if (viewPos.z <= 0.f)
clip(-1);
// 광원과 물체의 거리 구해서 광원밖에 있을시 무시
int lightIndex = g_int_0;
float3 viewLightPos = mul(float4(g_light[lightIndex].position.xyz, 1.f), g_matView).xyz;
float distance = length(viewPos - viewLightPos);
if (distance > g_light[lightIndex].range)
clip(-1);
float3 viewNormal = g_tex_1.Sample(g_sam_0, uv).xyz;
LightColor color = CalculateLightColor(g_int_0, viewNormal, viewPos);
output.diffuse = color.diffuse + color.ambient;
output.specular = color.specular;
return output;
}
// [Final]
// g_tex_0 : Diffuse Color Target
// g_tex_1 : Diffuse Light Target
// g_tex_2 : Specular Light Target
// Mesh : Rectangle
VS_OUT VS_Final(VS_IN input)
{
VS_OUT output = (VS_OUT)0;
output.pos = float4(input.pos * 2.f, 1.f);
output.uv = input.uv;
return output;
}
float4 PS_Final(VS_OUT input) : SV_Target
{
float4 output = (float4)0;
float4 lightPower = g_tex_1.Sample(g_sam_0, input.uv);
if (lightPower.x == 0.f && lightPower.y == 0.f && lightPower.z == 0.f)
clip(-1);
float4 color = g_tex_0.Sample(g_sam_0, input.uv);
float4 specular = g_tex_2.Sample(g_sam_0, input.uv);
output = (color * lightPower) + specular;
return output;
}
#endif
이게 동작하게 코드 수정
class Shader : public Object
{
public:
Shader();
virtual ~Shader();
// 이제 init에서 Main의 어떤 쉐이더함수에 접근할지 지정
void Init(const wstring& path, ShaderInfo info = ShaderInfo(), const string& vs = "VS_Main", const string& ps = "PS_Main");
void Update();
// ...
void Engine::CreateRenderTargetGroups()
{
// ...
// 라이팅 그룹 생성
// Lighting Group
{
vector<RenderTarget> rtVec(RENDER_TARGET_LIGHTING_GROUP_MEMBER_COUNT);
rtVec[0].target = GET_SINGLE(Resources)->CreateTexture(L"DiffuseLightTarget",
DXGI_FORMAT_R8G8B8A8_UNORM, _window.width, _window.height,
CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT),
D3D12_HEAP_FLAG_NONE, D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET);
rtVec[1].target = GET_SINGLE(Resources)->CreateTexture(L"SpecularLightTarget",
DXGI_FORMAT_R8G8B8A8_UNORM, _window.width, _window.height,
CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT),
D3D12_HEAP_FLAG_NONE, D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET);
_rtGroups[static_cast<uint8>(RENDER_TARGET_GROUP_TYPE::LIGHTING)] = make_shared<RenderTargetGroup>();
_rtGroups[static_cast<uint8>(RENDER_TARGET_GROUP_TYPE::LIGHTING)]->Create(RENDER_TARGET_GROUP_TYPE::LIGHTING, rtVec, dsTexture);
}
}