RunTime Compile Shader
Binary File Load
- 해당 Shader File을 Compile 해둔 파일을 Binary로 읽어들여 사용하는 방식.
- 이미 Compile 된 Shader를 사용하기 때문에 원본 Shader는 필요가 없으며, Compile 된 파일만 필요하다.
- RunTime Compile시에 사용할 수 있는 Macro, EntryPoint, Shader Model Version 설정은 불가능.
- Shader File Compile 시 Shader Model Version, EntryPoint 설정 후 Compile 해야하는 불편함이 있다.
RunTime Compile
- 해당 Shader File을 RunTime에 Compile 하는 방식, Shader File을 Compile 해둘 필요가 없다.
- RunTime시 Compile을 할 경우 Macro, EntryPoint Shader Model Version을 설정 할 수 있다.
- 같은 Shader File이여도 다른 버전과 다른 코드의 방식으로 Compile이 가능하다.
Shader Macro
- RunTime Compile시에 사용되는 Shader Macro struct.- 해당 struct에 Define 하고싶은 Define Name과 Value를 넣어 Compile 시 해당 Shader에 Macro를 추가 할 수 있다.
float4 Light_PS(VertexIn pin) : SV_TARGET
{
float4 albedo = gAlbedoRT.Sample(gSamWrapLinear, pin.Tex);
float4 normal = gNormalRT.Sample(gSamWrapLinear, pin.Tex);
float4 position = gPositionRT.Sample(gSamWrapLinear, pin.Tex);
float4 shadow = gShadowRT.Sample(gSamWrapLinear, pin.Tex);
float4 ssao = mul(gViewProjTex, float4(position.xyz, 1.0f));
// Gamma Correction
// Gamma Space -> Linear Space
// 모든 라이팅 연산은 선형 공간에서 이루어져야 한다..
#ifdef GAMMA_CORRECTION
albedo.rgb = pow(albedo.rgb, 2.2f);
#endif
float4 litColor = albedo;
// 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);
// View Direction
float3 ViewDirection = gEyePosW - position.xyz;
ViewDirection = normalize(ViewDirection);
// 현재 픽셀의 Shadow 값..
float shadows = 1.0f;
#ifdef SHADOW
shadows = CalcShadowFactor(gSamBorderComparisonLinearPoint, gShadowMap, float3(shadow.xyz));
#endif
// 현재 픽셀의 SSAO 값..
float ambientAccess = 1.0f;
#ifdef SSAO
ssao /= ssao.w;
ambientAccess = gSsaoMap.SampleLevel(gSamWrapLinear, ssao.xy, 0.0f).r;
#endif
// 현재 픽셀의 Material ID..
uint matID = round(position.w);
float4 A, D, S;
if (shadow.w < 1.0f)
{
// Directional Light
ComputeDirectionalLight(gMaterials[matID], gDirLights, float3(normal.xyz), ViewDirection,
A, D, S);
ambient += ambientAccess * A;
diffuse += shadows * D;
spec += shadows * S;
// Point Light
if (gPointLightCount > 0)
{
for (uint i = 0; i < gPointLightCount; ++i)
{
ComputePointLight(gMaterials[matID], gPointLights[i], float3(position.xyz), float3(normal.xyz), ViewDirection,
A, D, S);
ambient += A;
diffuse += D;
spec += S;
}
}
// Spot Light
if (gSpotLightCount > 0)
{
[unroll]
for (uint i = 0; i < gSpotLightCount; ++i)
{
ComputeSpotLight(gMaterials[matID], gSpotLights[i], float3(position.xyz), float3(normal.xyz), ViewDirection,
A, D, S);
ambient += A;
diffuse += D;
spec += S;
}
}
// Modulate with late add.
litColor = albedo * (ambient + diffuse) + spec;
}
// Common to take alpha from diffuse material and texture.
litColor.a = gMaterials[matID].Diffuse.a * albedo.a;
// Gamma Correction
// Normal Map은 선형공간에서 출력..
// Diffuse Map은 감마공간에서 출력..
#ifdef GAMMA_CORRECTION
if (normal.w < 1.0f)
litColor.rgb = pow(litColor.rgb, 1.0f / 2.2f);
#endif
return litColor;
}
위의 코드와 같이 #ifdef 로 코드 분기를 넣어 둘 수 있는데 이 Define은 Compile시 추가할 수 있으므로 여러개의 Shader File을
만들 필요가 없다.
// Shader Macro
D3D_SHADER_MACRO light0_macro[] = { {"GAMMA_CORRECTION"}, {"SHADOW"}, {"SSAO"}, {NULL, NULL} };
D3D_SHADER_MACRO light1_macro[] = { {"SHADOW"}, {"SSAO"}, {NULL, NULL} };
D3D_SHADER_MACRO light2_macro[] = { {"GAMMA_CORRECTION"}, {"SSAO"}, {NULL, NULL} };
D3D_SHADER_MACRO light3_macro[] = { {"GAMMA_CORRECTION"}, {"SHADOW"}, {NULL, NULL} };
D3D_SHADER_MACRO light4_macro[] = { {"GAMMA_CORRECTION"}, {NULL, NULL} };
D3D_SHADER_MACRO light5_macro[] = { {"SHADOW"}, {NULL, NULL} };
D3D_SHADER_MACRO light6_macro[] = { {"SSAO"}, {NULL, NULL} };
// Light Shader
LoadShader(SHADER_TYPE::VERTEX_SHADER, "LightVS.hlsl", "Light_VS", "Light_VS");
LoadShader(SHADER_TYPE::PIXEL_SHADER, "LightPS.hlsl", "Light_PS", "Light_PS_Option0" ,light0_macro);
LoadShader(SHADER_TYPE::PIXEL_SHADER, "LightPS.hlsl", "Light_PS", "Light_PS_Option1" ,light1_macro);
LoadShader(SHADER_TYPE::PIXEL_SHADER, "LightPS.hlsl", "Light_PS", "Light_PS_Option2" ,light2_macro);
LoadShader(SHADER_TYPE::PIXEL_SHADER, "LightPS.hlsl", "Light_PS", "Light_PS_Option3" ,light3_macro);
LoadShader(SHADER_TYPE::PIXEL_SHADER, "LightPS.hlsl", "Light_PS", "Light_PS_Option4" ,light4_macro);
LoadShader(SHADER_TYPE::PIXEL_SHADER, "LightPS.hlsl", "Light_PS", "Light_PS_Option5" ,light5_macro);
LoadShader(SHADER_TYPE::PIXEL_SHADER, "LightPS.hlsl", "Light_PS", "Light_PS_Option6" ,light6_macro);
LoadShader(SHADER_TYPE::PIXEL_SHADER, "LightPS.hlsl", "Light_PS", "Light_PS_Option7");
D3D_SHADER_MACRO terrain_macro[] = { {"TERRAIN_MESH"}, {NULL, NULL} };
// Object Shader
LoadShader(SHADER_TYPE::VERTEX_SHADER, "ObjectVS.hlsl", "Mesh_VS", "Mesh_VS");
LoadShader(SHADER_TYPE::VERTEX_SHADER, "ObjectVS.hlsl", "Skin_VS", "Skin_VS");
LoadShader(SHADER_TYPE::VERTEX_SHADER, "ObjectVS.hlsl", "Mesh_VS", "Terrain_VS", terrain_macro);
위의 코드에서 LightPS.hlsl 에서는 같은 진입점이지만 Define을 다르게 주어 여러가지 버전의 Shader File을 Compile
할 수 있으며, ObjectVS.hlsl 에서는 같은 진입점이지만 Define은 다르게하고 다른 진입점을 통해 Shader File을 Compile
할 수 있다는 이점이 있다.