Physically Based Rendering
BRDF ( Bidirectional Reflectance Distribution Function )
- "양방향 반사율 분포 함수" 라고 하며, Diffuse BRDF와 Specular BRDF로 나뉜다.
- BRDF의 조건
1) 반사율 분포를 출력으로 내뱉는다.
2) 양방향성을 가진다. 광원과 관찰자의 관계가 동일하다면 반사율 분포가 변하지 않는다.
3) 광원과 관찰자를 입력 파라미터로 받는다.
4) 같은 입력에는 항상 하나의 같은 결과가 나와야한다.
- BRDF의 모델
1) Cook-Torrance
2) Oren-Nayar
3) Phong
4) Blinn
Diffuse BRDF
- 광원이 어떻게 반사할지는 물체의 성분과 밀도에 따라 달라지기 때문에 한정된 자원을 가진 컴퓨터로 이를 정확하게 표현하는 것은
힘들기에 전방향으로 균일하게 반사한다고 가정하는 것이 램버트 반사율이다.
- 램버트 모델에서는 관찰자의 위치에 따라 반사율이 달라지진 않지만 조도가 다르기 때문에 기울기가 커지면 점점 어두워 보이게
된다.
- 기울기가 작아지면 같은 면적이라고 할지라도 더 적은 양의 빛이 들어오게 되는데, 이것을 수학적으로 정리한 사람이 Lambert이고
이에 대한 결과가 Cosine 법칙과 같기 때문에, 이를 램버트 코사인 법칙이라고 부른다.
- 빛을 향하는 벡터와 표면의 노멀을 내적하면 N과 L은 정규화된 벡터이므로 그 결과는 Cosine과 같아집니다.
에너지 보존 법칙 ( Energy Conservation )
- 빛이 들어오면 모든 방향으로 빛이 나가기 때문에 다른 방향으로 가고 있는 빛은 관찰자에게 도달할 수 없습니다. 그런데 N·L은 다른
방향으로 가고 있는 빛을 고려하고 있지 않고 빛의 표면과 노멀과의 관계만을 고려하기에 나가는 빛의 양을 모두 합산한 다음에
그것으로 나누어 에너지 보존법칙을 적용한다.
float3 Disney_Diffuse(in float roughnessPercent, in float3 diffuseColor, in float NdotL, in float NdotV, in float LdotH)
{
float energyBias = lerp(0.0f, 0.5f, roughnessPercent);
float energyFactor = lerp(1.0f, 1.0f / 1.51f, roughnessPercent);
float fd90 = energyBias + 2.0f * roughnessPercent * LdotH * LdotH;
float lightScatter = 1.0f + (fd90 - 1.0f) * pow(1.0f - NdotL, 5.0f);
float viewScatter = 1.0f + (fd90 - 1.0f) * pow(1.0f - NdotV, 5.0f);
return diffuseColor * lightScatter * viewScatter * energyFactor;
}
- 에너지 보존 법칙을 적용한 Diffuse BRDF.
Specular BRDF
- Specular의 경우 물체가 어떤 재질로 구성되어 있느냐에 따라 달라진다. Specular는 물체의 재질 특성을 보여주는 매우 중요한
요소이므로 조금 비용이 들더라도 재질 차이를 확실하게 보여 줄 만한 모델을 사용한다.
Specular D ( 미세면 분포 함수 )
- 모든 면은 자세히 들여다보면 미세면으로 구성되어 있다는 전제에서 반사나 굴절을 모델링 하는것을 의미한다.
- 대체적으로 사용하는 GGX 등방성 미세면 분포함수를 사용. (실제 환경에 제일 가까움)
Specular G ( 미세면 감쇠 함수 )
- 미세면의 그림자를 나타내는 함수, 에너지 보존 법칙을 위해서는 반드시 고려되어야 하는 부분이다.
- Unity의 Schlick-Smith Specular G 함수 사용.
Specular F ( 프레넬 함수 )
- 금속일수록 거의 대부분의 각도에서 높은 반사율을 보이며, 비금속일수록 지표각에서 높은 반사율을 가진다.
- Unity의 Schlick Fresnel 함수 사용.
// GGX Specular D
float Specular_D_GGX(in float roughness2, in float NdotH)
{
const float lower = (NdotH * (NdotH * roughness2 - NdotH)) + 1.0f;
return roughness2 / (PI * lower * lower);
}
// Schlick-Smith specular G (visibility) By Unity Version
float Specular_G_Smith_Unity(float roughness2, float NdotV, float NdotL)
{
float SmithV = NdotL * sqrt(NdotV * (NdotV - NdotV * roughness2) + roughness2);
float SmithL = NdotV * sqrt(NdotL * (NdotL - NdotL * roughness2) + roughness2);
return 0.5f / max(SmithV + SmithL, 1e-5f);
}
// Shlick's approximation of Fresnel By Unity Engine
float3 Specular_F_Fresnel_Shlick_Unity(in float3 specularColor, in float LdotH)
{
float FC = pow(1.0f - LdotH, 5.0f);
return specularColor + (1.0f - specularColor) * FC;
}
float3 Specular_BRDF(in float roughness2, in float3 specularColor, in float NdotH, in float NdotV, in float NdotL, in float LdotH)
{
// Specular D
float specular_D = Specular_D_GGX(roughness2, NdotH);
// Specular G
float specular_G = Specular_G_Smith_Unity(roughness2, NdotV, NdotL);
// Specular F
float3 specular_F = Specular_F_Fresnel_Shlick_Unity(specularColor, LdotH);
return (specular_D * specular_G) * specular_F;
}
- Unity Engine Shader Code를 참고한 Specular BRDF.
적용 영상
'DirectX 11' 카테고리의 다른 글
[DirectX 11] Tone Mapping (0) | 2022.02.03 |
---|---|
[DirectX 11] IBL (Image Based Lighting) (0) | 2022.01.23 |
[DirectX 11] Deferred Rendering FXAA (0) | 2022.01.16 |
[DirectX 11] Order Independent Transparency (0) | 2022.01.07 |
[DirectX 11] Particle System (0) | 2021.12.26 |