half3 DirectBRDF_DualLobeSpecular(BRDFData brdfData, half3 normalWS, half3 lightDirectionWS, half3 viewDirectionWS,half mask, half lobeWeight)
{
float3 halfDir = SafeNormalize(float3(lightDirectionWS) + float3(viewDirectionWS));
float NoH = saturate(dot(normalWS, halfDir));
half LoH = saturate(dot(lightDirectionWS, halfDir));
float d = NoH * NoH * brdfData.roughness2MinusOne + 1.00001f;
half nv = saturate(dot(normalWS,lightDirectionWS));
half LoH2 = LoH * LoH;
float sAO = saturate(-0.3f + nv * nv);
sAO = lerp(pow(0.75, 8.00f), 1.0f, sAO);
half SpecularOcclusion = sAO;
half specularTermGGX = brdfData.roughness2 / ((d * d) * max(0.1h, LoH2) * brdfData.normalizationTerm);
half specularTermBeckMann =
(2.0 * (brdfData.roughness2) /
((d * d) * max(0.1h, LoH2) * brdfData.normalizationTerm)) * lobeWeight * mask;
half specularTerm = (specularTermGGX / 2 + specularTermBeckMann) * SpecularOcclusion ;
// On platforms where half actually means something, the denominator has a risk of overflow
// clamp below was added specifically to "fix" that, but dx compiler (we convert bytecode to metal/gles)
// sees that specularTerm have only non-negative terms, so it skips max(0,..) in clamp (leaving only min(100,...))
#if defined (SHADER_API_MOBILE) || defined (SHADER_API_SWITCH)
specularTerm = specularTerm - HALF_MIN;
specularTerm = clamp(specularTerm, 0.0, 100.0); // Prevent FP16 overflow on mobiles
#endif
half3 color = specularTerm * brdfData.specular;
return color;
}
듀얼 로브 스페큘러 BRDF를 계산하는 셰이더 코드다. BRDF는 빛이 표면에서 어떻게 반사되는지를 수학적으로 모델링하는 함수로, 실시간 렌더링에서 사실적인 재질 표현을 위해 사용한다.
함수의 핵심 구조
입력 매개변수들:
- brdfData: 거칠기, 스페큘러 색상 등 재질 정보
- normalWS: 표면의 법선 벡터 (월드 스페이스)
- lightDirectionWS: 빛의 방향
- viewDirectionWS: 시점 방향
- mask: 마스킹 값
- lobeWeight: 로브 가중치
단계별 계산 과정
1. 하프 벡터 계산
float3 halfDir = SafeNormalize(float3(lightDirectionWS) + float3(viewDirectionWS));
빛의 방향과 시점 방향의 중간 벡터를 구한다. 이는 마이크로패싯 이론에서 반사가 일어나는 방향을 나타낸다.
2. 내적 계산
float NoH = saturate(dot(normalWS, halfDir));
half LoH = saturate(dot(lightDirectionWS, halfDir));
- NoH: 법선과 하프벡터 사이의 각도
- LoH: 빛 방향과 하프벡터 사이의 각도
3. 스페큘러 오클루전 계산
half nv = saturate(dot(normalWS,lightDirectionWS));
float sAO = saturate(-0.3f + nv * nv);
sAO = lerp(pow(0.75, 8.00f), 1.0f, sAO);
표면의 기하학적 특성에 따른 빛의 차폐 효과를 근사한다. 얕은 각도에서 들어오는 빛이 표면의 미세한 요철에 의해 가려지는 현상을 시뮬레이션한다.
4. 듀얼 로브 계산
GGX 분포:
half specularTermGGX = brdfData.roughness2 / ((d * d) * max(0.1h, LoH2) * brdfData.normalizationTerm);
Beckmann 분포:
half specularTermBeckMann = (2.0 * (brdfData.roughness2) / ((d * d) * max(0.1h, LoH2) * brdfData.normalizationTerm)) * lobeWeight * mask;
이 함수는 GGX와 Beckmann 두 가지 마이크로패싯 분포를 조합한다. GGX는 현실적인 반사를 제공하고, Beckmann은 추가적인 제어를 위해 사용한다.
5. 최종 조합
half specularTerm = (specularTermGGX / 2 + specularTermBeckMann) * SpecularOcclusion;
두 분포를 가중 평균하고 스페큘러 오클루전을 적용한다.
6. 모바일 최적화
#if defined (SHADER_API_MOBILE) || defined (SHADER_API_SWITCH)
specularTerm = specularTerm - HALF_MIN;
specularTerm = clamp(specularTerm, 0.0, 100.0);
#endif
모바일 GPU의 16비트 부동소수점 한계를 고려하여 오버플로우를 방지한다.
활용 목적
이 듀얼 로브 접근법은 단일 분포로는 표현하기 어려운 복잡한 재질의 반사 특성을 모델링한다. 예를 들어 금속 표면의 거친 반사와 부드러운 반사를 동시에 표현하거나, 클리어코트가 있는 페인트 같은 다층 재질을 시뮬레이션할 때 유용하다.
결과적으로 이 함수는 물리 기반 렌더링에서 더욱 사실적이고 세밀한 스페큘러 반사를 구현하기 위한 고급 BRDF 모델이라 할 수 있다.
원작자 정보
이 코드는 leegoonz(JP)가 개발한 것으로, Unity URP용 듀얼 로브 스킨 셰이더 기법의 일부다.
leegoonz의 블로그 링크
- 관련 포스트: Dual Lobe for Skin Shader by URP
- 듀얼 로브 GGX 작업: Mobile shader Dual Lobe GGX works
[Mobile shader] Dual Lobe GGX works
Unity3D URP Dual Lobe GGX works Dual Lobe Debug view. // Specular term half perceptualRoughness = SmoothnessToPerceptualRoughness(smoothness); half roughness = PerceptualRoughnessToRoughness(percep…
leegoonz.blog
Extra technique for Skin shader by URP
Dual Lobe BeckMann half3 DirectBDRFXD(BRDFData brdfData, BRDFDataXD brdfDataXD, half3 normalWS, half3 lightDirectionWS, half3 viewDirectionWS,half mask) { #ifndef _SPECULARHIGHLIGHTS_OFF float3 hal…
leegoonz.blog
'UNITY3D' 카테고리의 다른 글
고객사와 함께 읽는 울티밋 가이드 프로파일링 유니티 (0) | 2025.07.08 |
---|---|
유니티 6.1 인스턴싱 로컬 키워드 추가 리스트. (0) | 2025.06.04 |
GetDefaultDepthBufferBits() 메서드 (1) | 2025.06.04 |
ReflectionProbeAtlas 와 LIGHTMAP_BICUBIC_SAMPLING (0) | 2025.06.04 |
Sony agx 추가 (0) | 2025.06.02 |