Global Illumination(GI)은 표면에서 반구 방향으로 들어오는 모든 광량(직접광 + 간접광)을 BRDF를 통해 적분하여 계산하는 이상적인 조명 모델이다. 이 모델은 빛의 다중 반사(Bounce)까지 모두 고려하므로 현실적인 조명 표현이 가능하지만, 전체 적분을 실시간으로 계산하기에는 연산 비용이 매우 크다.
그래서 실제 그래픽스 파이프라인에서는 다음과 같이 직접광과 간접광을 분리하여 처리한다.
1. 직접광 (Direct Lighting)
실시간 정보를 반영하여 실시간으로 계산한다.
(DiffuseBRDF + SpecularBRDF) * Radiance * N·L
2. 정적 간접광 (Static Indirect Lighting)
실시간 정보를 반영하여 실시간으로 계산한다.
(DiffuseBRDF + SpecularBRDF)를 모두 포함한 GI 적분식
실제 GI 적분식(다중 Bounce 포함)을 완전히 계산하는 대신, 이를 오프라인에서 미리 계산해 저장한 데이터를 사용한다. Lightmap, Light Probe, IBL 등 다양한 형태로 사전에 구축하여, 렌더링 시에는 매우 빠르게 간접광을 조회할 수 있다.
3. 동적 간접광 (Dynamic Indirect Lighting)
장면이 변화할 때 간접광도 변해야 하는 상황에서, 레이트레이싱, SSGI, Voxel GI 등의 기법을 사용하여
일부 또는 전체 간접광을 실시간으로 근사한다.
요약하면,
GI는 원래 ‘Direct + Indirect’를 의미하지만, 실제 렌더링에서는 연산량 때문에 직접광은 실시간, 간접광은 정적 또는 동적으로 분리하여 처리하는 구조를 사용한다. 때문에 실무에서 말하는 GI는 정적 간접광의 사용을 의미한다.
정적 간접광(Static Indirect Lighting)
정적 간접광(static indirect lighting)은 광원에서 표면에 바로 닿는 직접광이 아닌, 환경에서 여러번 반사되어 들어오는 간접광을 사전에 계산해 저장해두고, 런타임에서는 이를 조회하는 방식이다. 실시간 비용을 크게 줄이면서도 자연스러운 간접광 표현이 가능하다.
간접광은 크게 3가지로 구분된다.
[ 정적 간접광 ]
1. 라이트 맵 (Lightmap)
2. 라이트 프로브 (Light Probe)
3. IBL 기반 환경광 (Image-Based Lighting)
라이트 맵 (Lightmap) 정적 지오메트리에 대해 간접광과 그림자를 오프라인에서 미리 계산해 텍스처로 굽는(Baking) 방식이다.
다중 Bounce까지 포함한 고품질 간접광을 저장
실시간 비용이 거의 없음
건물 실내 조명, 벽면 반사, 색 번짐(color bleeding)의 표현에 매우 유용
단, 정적인 오브젝트에만 적용이 가능하여 동적 오브젝트는 사용이 불가
라이트 프로브 (Light Probe, Spherical Harmonics) 정적 간접광을 공간의 여러 위치에 샘플점(Probe) 형태로 저장한 뒤, 이를 SH(Spherical Harmonics)로 압축하여 동적 오브젝트에 적용하는 방식이다.
라이트맵을 사용할 수 없는 캐릭터나 움직이는 물체가 환경 간접광을 자연스럽게 받을 수 있음
부드러운 ambient 간접광을 제공
정확도는 라이트맵보다 낮지만 매우 가볍고 실용적임
실내/ 실외 모두에서 필수적으로 사용됨
IBL 기반 환경광 (Image-Based Lighting) IBL은 환경의 HDL 큐브맵을 이용해 간접광을 계산하는 방식으로, 환경 자체가 하나의 거대한 광원처럼 작동한다. 즉, 광원을 직접 두지 않고 환경 자체가 조명 역할을 하도록 한다.
Diffuse IBL : 주변의 환경광(soft lighting)
Specular IBL : 주변의 반사광(Reflection)
BRDF LUT : 재질 특성 조정
종류
대상
데이터 형태
특징
Lightmap
정적 Mesh
Texture
정적 오브젝트용, 정확함
Light Probe (SH)
동적 Mesh
SH 계수
동적 오브젝트에 간접광 제공
Diffuse IBL
모든 오브젝트
Irradiance Map / SH
확산 간접광
Specular IBL
반사/금속
Prefiltered EnvMap + BRDF LUT
하이라이트/반사 간접광
IBL (Image-Based Lighting)
IBL(Image-Based Lighting)은 주변 환경을 HDR(큐브맵)에 저장해 두고, 이 이미지로부터 간접광을 계산하는 조명 기법이다. 환경 자체가 하나의 거대한 조명 역할을 한다고 이해하면 된다.
IBL은 크게 두 요소로 구성된다.
1. Diffuse IBL (확산 간접광)
거친 표면이나 비금속 표면에서 환경 전체가 퍼지듯 들어오는 부드러운 간접광을 계산한다.
2. Specular IBL (반사 간접광)
매끄러운 표면이나 금속 표면에서 주변 환경을 거울처럼, 또는 흐릿하게 반사한다.
1. IBL Diffuse Term
IBL Diffuse Term에서는 환경 전체에서 들어오는 빛이 표면에 난반사로 퍼지는 간접광을 계산한다. 난반사는 방향성이 약하고 표면의 roughness에 크게 영향받지 않기 때문에, 반구 적분된 환경광(Irradiance Map)을 미리 만들어두고 표면 법선 방향으로 샘플링하는 것만으로 빠르게 간접광을 계산할 수 있다.
원래는 반구 위 모든 방향에 대해 Radiance × N·L을 적분해야 하는데
IBL에서는 이 적분을 “미리 계산한 Irradiance Map”이 대신한다.
결과적으로 실시간에서는 ‘kd × albedo/π × irradiance‘만으로 환경에서 반사된 부드러운 간접 diffuse 조명을 계산한다.
Irradiance Map
입력 : HDR 큐브맵 이미지
출력 : 매우 블러 처리된 저해상도 큐브맵 (dds)
목적 : 환경광의 부드러운 확산 반사 계산 (Diffuse IBL)
샘플링 키 값 : N(normal)
내용 : Lambert(NdotL)의 적분 Irradiance(방사 조도)는 표면이 모든 방향에서 받는 Radiance의 총합(적분)으로, 표면이 받는 입사광량을 의미한다. Diffuse IBL 텀에 사용될 Irradiance를 미리 계산하여 텍스처로 저장해두면 실시간 비용을 크게 줄일 수 있다. 표면의 p 지점을 기준으로 반구 전체에서 다양한 방향 Wi 로 빛이 들어온다고 가정한다. 이때 Radiance는 특정 방향에서 들어오는 빛의 색과 세기를 의미하며, 표면은 해당 방향에 대해 Lambert 법칙에 따라 N·L만큼만 밝게 기여한다. 즉, 어떠한 방향에서 Radiance가 아무리 강해도 표면 법선과의 각도가 크면 기여도가 줄어든다.
결국, 반구의 모든 방향에 대해 Radiance(Wi) × (N dot Wi)를 누적한 값이 그 표면이 받는 전체 Diffuse 간접광이다. Irradiance Map은 이 적분 결과를 큐브맵 형태로 저장한 것으로, 큐브맵의 각 픽셀 방향은 표면의 법선 방향에 해당한다. Diffuse 조명은 기본적으로 방향성이 퍼져 있으므로, 이 Irradiance Map은 낮은 해상도로도 충분히 부드럽고 자연스러운 간접광을 제공한다.
실시간 Diffuse IBL 계산
// 1. Irradiance Map 샘플링 - 미리 계산된 난반사 간접광
// 텍스처는 표면 법선(N)으로 샘플링한다.
float3 irradiance = txIBL_Diffuse.Sample(samplerLinear, N).rgb;
// 2. 프레넬 반사율 F 계산
// 프레넬(시선-빛 방향)에 따른 반사율을 최소 반사율(비금속/금속)을 고려하여 구한다.
// 빛 방향은 특정 할 수 없으므로 cosLo = dot(Normal,View)을 사용한다.
float3 F0 = lerp(Fdielectric, albedo, metalness);
float3 F = fresnelSchlick(F0, cosLo);
// 3. 난반사(표면산란) 비율 계산
// 금속일수록 표면 산란을 제거하며 비금속일수록 표면 산란이 그대로 표현된다.
float3 kd = lerp(1.0 - F, 0.0, metalness);
// 4. Diffuse IBL
// txIBL_Diffuse 맵에는 Lambertian BRDF를 가정하여 포함되어 있다.
float3 diffuseIBL = kd * BaseColor * irradiance / PI;
2. IBL Specular Term
Specular IBL Term에서는 환경광이 표면에서 반사(Specular) 형태로 반사되는 간접광을 계산한다. Specular IBL은 사실 아래의 적분(환경 전체를 대상으로 한 반사 계산)을 해야하는데 이 적분은 실시간으로 절대 계산할 수 없다.
IBL에서는 이 적분을 실시간에 수행하는 대신, 적분을 쪼개서 두 텍스처로 저장해두고 실시간 연산에 샘플링하여 사용한다.
환경 방향에 대한 적분 → Prefiltered EnvMap
BRDF 자체에 대한 적분 → BRDF LUT
원래는 모든 방향 Wi 에 대해 D × G × F / (4 N·V N·L) × (N·L) dL 을 적분해야 한다.
IBL에서는 이 적분을 Prefiltered EnvMap + BRDF LUT가 대신 수행한다.
결과적으로, 실시간에서는 ‘SpecularIBL = PrefilteredColor * (F0 * specularBRDF.x + specularBRDF.y)’ 의 형태로 매우 빠르게 스페큘러 간접광을 계산한다.
Prefiltered Environment Map (Specular EnvMap)
입력 : HDR 큐브맵 이미지
출력 : Roughness 단계(Mip)별로 블러된 CubeMap (DDS)
샘플링 키 값 : R(반사 벡터)로 샘플링, roughness * specularTextureLevels로 LOD level 결정
내용 : 환경 Radiance + D(미세면 분포) + roughness 관련 적분 Prefiltered EnvMap은 Specular IBL에서 환경 쪽에서 미리 계산해둘 수 있는 부분을 만들어둔 텍스처이다. 즉, 환경 Radiance가 각 roughness에서 어떻게 퍼지고 흐려지는지(D함수 포함)를 모두 계산한 결과를 저장한다.
따라서, Prefiltered EnvMap은 roughness별로 블러링된 MipMap CubeMap으로 구성된다.
BRDF Lookup Table (LUT)
입력 : N·V, roughness
출력 : 2D LUT (R=scale, G=bias)
샘플링 키 값 : float2(NdotL, roughness)).rg
내용 : F(프레넬) + G(기하 감쇠) 적분 BRDF LUT은 Specular IBL에서 표면 BRDF 쪽에서 미리 계산해둘 수 있는 부분을 저장한 텍스처이다. Specular BRDF의 항 중에서 F와 G는 환경과 독립적이며, NdotV와 roughness만으로 결정되므로 이를 미리 적분해 2D Lookup Table에 저장한다. 실시간에서는 LUT에서 두 값(scale, bias)을 샘플링하고 프레넬 Schlick F0와 조합하여 최종 Specluar IBL을 계산한다.
실시간 Specular IBL 계산
// 1. 텍스처 Mipmap 레벨 구하기
uint specularTextureLevels, width, height;
txIBL_Specular.GetDimensions(0, width, height, specularTextureLevels);
// 2. Prefiltered EnvMap 샘플링
// View-Reflection 벡터(Lr) 기반으로 샘플링
// roughness * specularTextureLevels 로 LOD를 결정하여 거칠기에 따른 블러 효과 적용
float3 PrefilteredColor = txIBL_Specular.SampleLevel(samplerLinear, Lr, roughness * specularTextureLevels).rgb;
// 3. Cook-Torrance BRDF 근사용 LUT 샘플링
// NdotL, roughness를 기반으로 F*G 평균값과 Geometry term(G) 샘플링
float2 specularBRDF = txIBL_SpecularBRDF_LUT.Sample(samplerClamp, float2(NdotL, roughness)).rg;
// 4. Specular IBL 계산
// 쿡토런스 Spceular BRDF 근사식
float3 F0 = lerp(Fdielectric, albedo, metalness);
float3 specularIBL = PrefilteredColor * (F0 * specularBRDF.x + specularBRDF.y);
// 최종 간접광 합산
// 난반사(diffuseIBL)와 반사광(specularIBL)을 합치고 AmbientOcclusion 곱하여 최종 IBL 계산
indirectIBL = (diffuseIBL + specularIBL) * AmbientOcclusion;