enum class SHADER_DOMAIN
{
// Deferred
DOMAIN_DEFERRED, // 지연 렌더링
DOMAIN_DECAL,
DOMAIN_LIGHTING, // 광원 연산
// Forward
DOMAIN_OPAQUE, // 불투명
DOMAIN_MASKED, // 불투명 or 투명
DOMAIN_TRANSPARENT, // 반투명
DOMAIN_POSTPROCESS, // 후처리
DOMAIN_DEBUG,
};
Deferred 단계에서 그려질 물체를 분류할 목적으로 SHADER_DOMAIN에 deferred 도메인을 추가하고 카메라는 domain에 맞춰서 물체를 분류한다.
void CCamera::render()
{
// 계산한 view 행렬과 proj 행렬을 전역변수에 담아둔다.
g_Transform.matView = m_matView;
g_Transform.matProj = m_matProj;
// Domain 순서대로 렌더링
CRenderMgr::GetInst()->GetMRT(MRT_TYPE::DEFERRED)->OMSet();
render(m_vecDeferred);
CRenderMgr::GetInst()->GetMRT(MRT_TYPE::SWAPCHAIN)->OMSet();
render(m_vecOpaque);
render(m_vecMaked);
render(m_vecTransparent);
// 후처리 작업
render_postprocess();
}
그리고 render 함수에서 deferred 물체를 그리기전에 MRT를 deferred MRT로 교체한 뒤 물체를 그리게한다.
#ifndef _STD_DEFERED
#define _STD_DEFERED
#include "value.fx"
// ======================
// Std3D_Deferred Shader
// MRT : Deferred MRT
#define ColorTexture g_tex_0
#define NormalMap g_tex_1
#define ColorTextureCheck g_btex_0
#define NormalMapCheck g_btex_1
// ======================
struct VS_IN
{
float3 vPos : POSITION;
float2 vUV : TEXCOORD;
float3 vTangent : TANGENT;
float3 vNormal : NORMAL;
float3 vBinormal : BINORMAL;
};
struct VS_OUT
{
float4 vPosition : SV_Position;
float2 vUV : TEXCOORD;
float3 vViewPos : POSITION;
float3 vViewTangent : TANGENT;
float3 vViewNormal : NORMAL;
float3 vViewBinormal : BINORMAL;
};
VS_OUT VS_Std3D_Deferred(VS_IN _in)
{
VS_OUT output = (VS_OUT) 0.f;
output.vPosition = mul(float4(_in.vPos, 1.f), g_matWVP);
output.vUV = _in.vUV;
output.vViewPos = mul(float4(_in.vPos, 1.f), g_matWV);
output.vViewTangent = normalize(mul(float4(_in.vTangent, 0.f), g_matWV));
output.vViewNormal = normalize(mul(float4(_in.vNormal, 0.f), g_matWV));
output.vViewBinormal = normalize(mul(float4(_in.vBinormal, 0.f), g_matWV));
return output;
}
struct PS_OUT
{
float4 vColor : SV_Target0;
float4 vPosition : SV_Target1;
float4 vNormal : SV_Target2;
float4 vData : SV_Target3;
};
PS_OUT PS_Std3D_Deferred(VS_OUT _in) : SV_Target
{
PS_OUT output = (PS_OUT) 0.f;
float4 vOutColor = float4(1.f, 0.f, 1.f, 1.f);
if (ColorTextureCheck)
{
vOutColor = ColorTexture.Sample(g_sam_0, _in.vUV);
}
output.vColor = vOutColor;
output.vPosition = float4(_in.vViewPos, 1.f);
float3 vViewNormal = _in.vViewNormal;
if (NormalMapCheck)
{
float3 vNormal = NormalMap.Sample(g_sam_0, _in.vUV).rgb;
vNormal = vNormal * 2.f - 1.f;
float3x3 matRot =
{
_in.vViewTangent,
_in.vViewBinormal,
_in.vViewNormal,
};
vViewNormal = normalize(mul(vNormal, matRot));
}
output.vNormal = float4(vViewNormal, 1.f);
output.vData = float4(0.f, 0.f, 0.f, 1.f);
return output;
}
#endif
vertex shader 단계에서는 물체에 대한 Position과 UV를 계산하여 넘겨주고, 라이팅 단계에서 필요한 view space에서의 정보를 같이 넘겨준다.
pixel shader단계에서는 넘겨 받은 값과 노멀 맵, color texture의 유무를 판단하여 각각의 정보를 계산하여 다른 렌더타겟에 나누어 담아준다.
enum class SHADER_DOMAIN
{
// Deferred
DOMAIN_DEFERRED, // 지연 렌더링
DOMAIN_DECAL,
DOMAIN_LIGHTING, // 광원 연산
// Merge
DOMAIN_MERGE, // Deferred 정보를 SwapChain 타겟으로 이동
// Forward
DOMAIN_OPAQUE, // 불투명
DOMAIN_MASKED, // 불투명 or 투명
DOMAIN_TRANSPARENT, // 반투명
DOMAIN_POSTPROCESS, // 후처리
DOMAIN_DEBUG,
};
Deferred 물체가 모두 그려진 뒤 merge하기 위해 DOMAIN_MERGE를 추가한다.
void CCamera::render()
{
// 계산한 view 행렬과 proj 행렬을 전역변수에 담아둔다.
g_Transform.matView = m_matView;
g_Transform.matProj = m_matProj;
// Domain 순서대로 렌더링
// Deferred 물체 렌더링
CRenderMgr::GetInst()->GetMRT(MRT_TYPE::DEFERRED)->OMSet();
render(m_vecDeferred);
// Deferred 정보를 SwapChain 으로 병함
CRenderMgr::GetInst()->GetMRT(MRT_TYPE::SWAPCHAIN)->OMSet();
Ptr<CMesh> pRectMesh = CAssetMgr::GetInst()->FindAsset<CMesh>(L"RectMesh");
Ptr<CMaterial> pMergeMtrl = CAssetMgr::GetInst()->FindAsset<CMaterial>(L"MergeMtrl");
pMergeMtrl->SetTexParam(TEX_PARAM::TEX_0, CAssetMgr::GetInst()->FindAsset<CTexture>(L"NormalTargetTex"));
pMergeMtrl->UpdateData();
pRectMesh->render();
// Foward 렌더링
render(m_vecOpaque);
render(m_vecMaked);
render(m_vecTransparent);
// 후처리 작업
render_postprocess();
}
Camera Render에서 Deferred 물체 랜더링 이후 MRT를 스왚체인 MRT로 변경하여 Merge 단계를 수행하도록 한다.
#ifndef _MERGE
#define _MERGE
#include "value.fx"
// ===============
// Merge Shader
// MRT : SwapChain
// Mesh : RectMesh
#define ColorTargetTex g_tex_0
#define ColorTargetCheck g_btex_0
// ===============
struct VS_IN
{
float3 vPos : POSITION;
float2 vUV : TEXCOORD;
};
struct VS_OUT
{
float4 vPosition : SV_Position;
float2 vUV : TEXCOORD;
};
VS_OUT VS_Merge(VS_IN _in)
{
VS_OUT output = (VS_OUT) 0.f;
output.vPosition = float4(_in.vPos * 2.f, 1.f);
output.vUV = _in.vUV;
return output;
}
float4 PS_Merge(VS_OUT _in) : SV_Target
{
float4 vOutColor = (float4) 0.f;
if (ColorTargetCheck)
{
vOutColor = ColorTargetTex.Sample(g_sam_0, _in.vUV);
}
return vOutColor;
}
#endif
Merge 단계에서는 화면에 출력되는 모든 픽셀당 한번씩만 계산되면 되므로 vertex shader에서는 로컬좌표를 2배로 늘려(로컬에서 rect매쉬의 크기가 0.5이기 때문에 NDC 좌표계랑 사이즈를 맞추기 위해 2배 해야함) 그대로 출력하고, pixel shader 단계에서는 deferred 단계에서 저장해놓은 여러가지 값들을 이용해 화면에 출력될 픽셀의 색을 결정한다. 우선은 Color를 그대로 출력하도록 했다.
