본문 바로가기

Unreal Engine

Two-Sided Foliage Shading Model in Unreal Engine

셰이딩 모델의 이름에서 알 수 있듯, 양면 폴리지를 위한 셰이딩 모델이다.

폴리지의 셰이딩은 보통 노멀 방향에서 받은 빛이 뒷면으로 투과해서 또다른 색상으로 변화하는 것이 특징인데,  Subsurface 셰이딩 모델 외에 폴리지 전용 셰이딩 모델을 만든 이유가 예전부터 궁금했었다.

셰이더 코드를 살펴보면, 수많은 폴리지들을 렌더링하기 위해 Subsurface 에 비해 간소화한 코드임을 알 수 있다.

아래는 Two-Sided Foliage 의 BxDF 함수이다.

FDirectLighting TwoSidedBxDF( FGBufferData GBuffer, half3 N, half3 V, half3 L, float Falloff, half NoL, FAreaLight AreaLight, FShadowTerms Shadow )
{
	FDirectLighting Lighting = DefaultLitBxDF( GBuffer, N, V, L, Falloff, NoL, AreaLight, Shadow );

	half3 SubsurfaceColor = ExtractSubsurfaceColor(GBuffer);

	// http://blog.stevemcauley.com/2011/12/03/energy-conserving-wrapped-diffuse/
	half Wrap = 0.5;
	half WrapNoL = saturate( ( -dot(N, L) + Wrap ) / Square( 1 + Wrap ) );

	// Scatter distribution
	half VoL = dot(V, L);
#if SHADING_PATH_MOBILE
	half Scatter = D_GGX_Mobile(0.6, saturate(-VoL));
#else
	float Scatter = D_GGX( 0.6*0.6, saturate( -VoL ) );
#endif

	Lighting.Transmission = AreaLight.FalloffColor * (Falloff * WrapNoL * Scatter) * SubsurfaceColor;

	return Lighting;
}

 

Subsurface 셰이딩 모델과 비교했을 때, 아래와 같은 차이가 있었다.

  • G-Buffer 의 Opacity 데이터를 사용하지 않음
  • Mobile 패스 분기가 있음

하지만 이외 Wrap Diffuse를 사용하는 점이나, L dot V를 사용해 빛이 카메라 정면으로 오는 방향일 때 물체를 투과하는 듯한 효과를 주는 핵심적인 부분은 거의 동일하다.

다만 이 두 셰이딩을 lerp 로 섞거나 Opacity 등으로 강도를 조절하지 않고, 단순 곱하기로 합성한다. GBuffer에서 얻어온 Subsurface Color도 별다른 가공 없이 여기에 그대로 곱해진다.

 

Diffuse, Specular

	FDirectLighting Lighting = DefaultLitBxDF( GBuffer, N, V, L, Falloff, NoL, AreaLight, Shadow);

 

Subsurface 셰이딩 모델처럼 이 두 가지 요소는 DefaultLitBxDF 를 수행해서 계산한다. 즉 Transmission 결과값이 0이라면, Default Lit 셰이딩 모델과 동일한 결과가 출력될 것이다.

Transmission 강도를 수정할 수 있는 파라미터는 오직 Subsurface Color 하나이다. 이것이 0이면 Transmission 도 0이다.

 

Transmission

	// http://blog.stevemcauley.com/2011/12/03/energy-conserving-wrapped-diffuse/
	half Wrap = 0.5;
	half WrapNoL = saturate( ( -dot(N, L) + Wrap ) / Square( 1 + Wrap ) );

	// Scatter distribution
	half VoL = dot(V, L);
#if SHADING_PATH_MOBILE
	half Scatter = D_GGX_Mobile(0.6, saturate(-VoL));
#else
	float Scatter = D_GGX( 0.6*0.6, saturate( -VoL ) );
#endif

	Lighting.Transmission = AreaLight.FalloffColor * (Falloff * WrapNoL * Scatter) * SubsurfaceColor;

 

WrappedDiffuse

아쉽게도 주석에 달린 링크는 지금은 연결되지 않는 듯 하다. 대신 아래 포스팅에서 자세한 설명을 볼 수 있다.

https://diffuse133.rssing.com/chan-36853166/article2.html

 

포스팅 내용에 따르면, Wrapped Diffuse 자체로는 Energy Conserving 하지 않기 때문에, Wrapped Diffuse를 normalize factor인 (1 + w) 로 나누어 주어야 한다고 한다.

수정된 WrappedDiffuse

 

직관적으로 생각해보면, w = 1일 때, 즉 Wrap을 최대한으로 수행해 (N dot L 의 경우처럼 절반이 아닌) Sphere 전체를 빛이 감싸는 형태가 되었을 때, normalization factor는 아래와 같은 값이 된다.

 

즉 정확히 절반 만큼 밝기가 줄어든다. 따라서 위의 수정된 WrappedDiffuse는 에너지 보존된다고 할 수 있다.

 

다시 셰이더 코드를 살펴보면, w = 0.5 고정으로 WrappedDiffuse 가 계산됨을 볼 수 있다.

	half Wrap = 0.5;
	half WrapNoL = saturate( ( -dot(N, L) + Wrap ) / Square( 1 + Wrap ) );

Subsurface 셰이딩 모델에서는 BackScatter에 해당하는 부분이다.

왼쪽 : Opacity가 1.0일 때 InScatter, 오른쪽 : NdotL

Scatter Distribution

float Scatter = D_GGX( 0.6*0.6, saturate( -VoL ) );

 

D_GGX란 Trowbridge-Reitz GGX로, 주로 Specular분포를 계산할 때 사용했었다.

(이미지 출처 : https://velog.io/@15ywt/%EA%B7%B8%EB%9E%98%ED%94%BD%EC%8A%A4PBR-BRDF)

https://velog.io/@15ywt/%EA%B7%B8%EB%9E%98%ED%94%BD%EC%8A%A4PBR-BRDF

 

// GGX / Trowbridge-Reitz
// [Walter et al. 2007, "Microfacet models for refraction through rough surfaces"]
float D_GGX( float a2, float NoH )
{
	float d = ( NoH * a2 - NoH ) * NoH + 1;	// 2 mad
	return a2 / ( PI*d*d );					// 4 mul, 1 rcp
}

엔진 코드의 GGX 함수

Two-Sided Foliage 셰이딩 모델에서는 특이하게도 NoH 가 들어갈 자리에 -VoL 을 인풋으로 두었다.

-VoL은 Subsurface 셰이딩 모델에서 InScatter에 해당하는 부분으로, 카메라 방향과 빛 방향이 정 반대 방향으로 정렬되었을 때 동그렇게 빛나는 영역을 만들어서, 마치 빛이 물체를 투과하는 듯한 효과를 준다.

Scatter Distribution 부분만 출력해 본 모습

 

Normal이 고려되지 않은 계산이기 때문에, 이 셰이딩이 나타날 때는 물체가 평평해 보인다.

 

왼쪽 : Subsurface 의 BackScatter 부분만 출력해 본 모습

Roughness를 의미하는 a는 0.6으로 고정되어 있다.

 

최종 Transmission

위에서 본 WappedNoL 과 Scatter Distribution 이 곱해져 Transmission 강도가 되고, 여기에 Subsurface Color가 곱해져 최종 색상이 된다.

Subsurface 셰이딩 모델보다 자유도가 없는 대신 훨씬 간단하고, 그래서 렌더링 결과를 예측하기도 더 쉽다.