Image Based Lighting - Single Scatter model

이전 포스트 (https://jooh3444.tistory.com/33) 에 구현된 라이팅 모델 결과물입니다.
SingleScattering 이라고 부르는 이유는 글 뒷부분에서 언급됩니다.
Energy Loss on rough surface

Roughness가 낮을수록 어두운 느낌이 드는데요,
White furnace test를 해서 에너지가 잘 보존되고 있는지 확인해볼 수 있습니다.
White Furnace Test
라이팅 모델이 잘 구현된 경우, 모든 방향에서 완벽한 흰색 light가 들어온다고 가정하면 물체는 완벽한 흰색 (1,1,1)이 되어서 배경과 구분할 수 없게 됩니다.
그래서 내 라이팅 모델이 제대로 구현되었는지 이 테스트를 통해 확인할 수 있습니다.


첫번째 열은 Conductor (metalic = 1) 인데요, roughness가 커질수록 어두워지는, 즉 에너지를 잃는 현상이 보여집니다.
마지막 열은 Dielectrics (metalic = 0 이고, roughness가 작은 경우에 표면에서 에너지가 더 발생하는 현상이 보여집니다.
Conductor
- roughness 가 낮을수록 에너지 손실.
- roughness = 1 에서 대략 40% 손실.

Dielectrics
- roughness = 0에서 표면에서 에너지 과다

에너지 손실 발생 이유?
문제는 multiple-scattering event

- Single-Scattering 모델에서는 첫 번째 bounce가 다른 표면에 닿으면 masking으로 판별.
- 그러나 현실에서는 두 번째 bounce가 다시 나갈 수 있음.
- 이는 복잡한 (roughness가 큰) 표면에서 영향이 큼
- 그래서 이전 모델을 single-scattering model 이라고도 부름 (multiple-scattering을 고려안해서)
손실된 에너지를 복구 방법?
⇒ Energy Compensation
부족한 에너지를 계산해서 보상해주기.
Conductor
- Metalic , Fresnel Term = 1 이라고 가정. (perfect reflecting metal)

Ess : single scattering , Ems : multi scattering
에너지 총량은 보존되어야함. (모든 들어온 에너지는 반사되기 때문)


첫번째→두번째 줄은 [Kelemen 2001] ( http://www.hungrycat.hu/microfacet.pdf ) 참고.
식을 풀어보면 fms의 directional albedo는 f의 comlements다.
Fresnel
이전에 무시했던 Fresnel도 포함시켜줘야하는데,
표면이 에너지를 흡수할 수 있어서 E (µ) = 1는 성립하지 않는다.
대신 Jakob는 아래의 새로운 대안을 제시했다.

Favg = Fss (single scatter model 의 fresnel). Eavg = Ess (single scatter model의 에너지) 이다.
제대로된 바운드는 FavgEavg 값에, 잃은 에너지 (1-E_avg) 를 bounce마다 계산해서 더해주면 잃은 에너지를 보상해줄 수 있다.

앞의 두 식 (Fresnel term 없는 계산식과 Fresnel Term 계산식)을 곱해주면 다음과 같아지고,

이를 정리하면 다음과 같아진다. (E(l) = Ess)
Fss와 Fms 두 텀을 합해주어 정리하면

이렇게 최종식이 나온다.
Ess Lookup Table
이를 실시간으로 계산하지는 않고, Ess 는 roughness, NoV 에 종속적이기 때문에
roughness, NoV 에 대해서 Ess 을 미리 계산해놓고, lighting 연산 때 이를 가져와서 사용한다.
(image-based lighting pre-integration 과 비슷하게 사용가능)
Lut 계산
float energyComp = 0.0f;
for (uint i = 0u; i < numSample; ++i)
{
float2 Xi = Hammersley(i, invNumSample);
const float3 H = ImportanceSampleGGX(Xi, roughness, N);
float3 L = 2.0 * dot(V, H) * H - V;
// Using the fact that N = (0, 0, 1).
float NoL = saturate(dot(N, L));
float NoH = saturate(dot(N, H));
float VoH = saturate(dot(V, H));
// specular term
if (NoL > 0.0)
{
const float g = V_SmithGGXCorrelated(NoV, NoL, roughness);
const float gv = g * VoH * NoL / (NoH);
energyComp += gv;
}
}
lutTexture[dispatchThreadID.xy] = float4(..., ..., energyComp * 4, 1.f) * invNumSample;
Fresnel은 런타임에 적용될 예정. GV만 계산하여 텍스쳐에 저장해둔다.
Energy Compensation on Lighting
실제 라이팅 셰이더에서는 Lut 텍스쳐의 z 값을 가져와서 보상텀을 만들어주어 곱해주면 코드는 엄청 간단하다.
float3 energyCompensation = 1.0 + F0 * (1.0 / EnvBRDF.z - 1.0);
float3 specularTerm = CookTorrenceSpecular(roughness, metalic, F0, context)
* energyCompensation;
...
Conductor. specular compensation




FlightHelmet


소스 코드
https://github.com/Jooh34/CubiEngine
Reference
- Multiple-Scattering Microfacet BSDFs with the Smith Model https://eheitzresearch.wordpress.com/240-2/
- Image Based Lighting with Multiple Scattering https://bruop.github.io/ibl/
- Physically Based Rendering in Filament https://google.github.io/filament/Filament.md.html
- SIGGRAPH 2017 Course: Physically Based Shading in Theory and Practice https://blog.selfshadow.com/publications/s2017-shading-course/#course_content
- A Multiple-Scattering Microfacet Model for Real-Time Image-based Lighting https://jcgt.org/published/0008/01/03/paper.pdf
- Sampling Hemisphere https://ameye.dev/notes/sampling-the-hemisphere/
- Importance Sampling https://patapom.com/blog/Math/ImportanceSampling/#how-to-read-brdf-integrals-with-pdf
- A Microfacet Based Coupled Specular-Matte BRDF Model with Importance Sampling http://www.hungrycat.hu/microfacet.pdf
- Kelemen 2001 , A Microfacet Based Coupled Specular-Matte BRDF Model with Importance Sampling, http://www.hungrycat.hu/microfacet.pdf
'Computer Graphics' 카테고리의 다른 글
| Image Based Lighting (3) | 2025.07.17 |
|---|---|
| Two Pass Occlusion Culling (0) | 2025.07.01 |