본문 바로가기

Unreal Engine

Unreal에서의 Metallic 표현

왼쪽부터 Metalic 0.0 ~ 1.0

  • BaseColor 색은 모두 0, 0, 1
  • Roughness 0.32

색만 진해지는 것 같지만, 자세히 보면 스페큘러의 양상도 다르다.

Metalic 0.0 ~ 1.0
Pre-Tonemapped HDR Color
Unlit 모드일 때. 라이팅 계산이 되기 전 이미 색상에 변화가 있음을 알 수 있다.

 

DIffuse Color Scene Texture

Diffuse Color 는 메탈릭 재질에 따른 색상의 변화가 있음.

(Metalic = 1.0 일 경우, Diffuse Color = 0, 0, 0

중간에 있는 Sphere의 Diffuse Color는 0, 0, 0.6

 

Diffuse Color

  • DeferredShadingCommon.ush
GBuffer.SpecularColor = ComputeF0(GBuffer.Specular, GBuffer.BaseColor, GBuffer.Metallic);

		if (UseSubsurfaceProfile(GBuffer.ShadingModelID))
		{
			AdjustBaseColorAndSpecularColorForSubsurfaceProfileLighting(GBuffer.BaseColor, GBuffer.SpecularColor, GBuffer.Specular, bChecker);
		}

		GBuffer.DiffuseColor = GBuffer.BaseColor - GBuffer.BaseColor * GBuffer.Metallic;
  • Diffuse Color는 BaseColor - (BaseColor * Metalic) 임
    즉, Metalic이 1이면, Diffuse Color는 0이 되고,
    Metalic이 0에 가까워질수록, Diffuse Color는 본래의 BaseColor 색상에 가까워진다.
  • Specular Color는 ComputeF0 함수로 계산되는데, 여기에도 Metalic 값의 영향이 있다.
  • ComputeF0() 함수는 ShadingCommon.ush 에서 찾을 수 있다.
float3 ComputeF0(float Specular, float3 BaseColor, float Metallic)
{
	return lerp(DielectricSpecularToF0(Specular).xxx, BaseColor, Metallic.xxx);
}

float DielectricSpecularToF0(float Specular)
{
	return 0.08f * Specular;
}

DialectricSpecularToF0 은 단순히 Specular값에 0.08을 곱해준다.
Dialectric은 유전체라는 뜻이라고 하는데, 검색해봐도 의미를 잘 모르겠다.

  • ComputeF0 함수는 Specular를 0.08 한 것과 BaseColor 사이를 Metalic 값으로 보간한다.
    Metalic이 0이면, Specular Color는 Specular * 0,08 이 되고,
    Metalic이 1이면 Specular Color는 BaseColor가 된다.

ShadingModels.ush를 살펴보면, BaseColor 대신 GBuffer에 저장된 DiffuseColor가 주로 라이팅 계산에 사용됨을 알 수 있다. (FDirectLighting DefaultLitBxDF 중)

Lighting.Diffuse = Diffuse_Lambert(GBuffer.DiffuseColor);

스페큘러 계산에도 앞서 계산된 Specular Color가 사용된다.

Lighting.Specular = AreaLight.FalloffColor * (Falloff * NoL) * SpecularGGX(GBuffer.Roughness, GBuffer.Anisotropy, GBuffer.SpecularColor, Context, NoL, AreaLight);

Specular 값을 0으로 줘 보았다. 특이하게도 메탈릭이 1에 가까워질수록 스페큘러가 되살아난다.

이 하이라이트는 Roughness를 1.0으로 하면 완전히 사라진다. 하지만 여전히 DiffuseColor (0.0) 가 그대로 나오진 않는다.

이 상태에서 Show > Lighting Components > Specular 부분만 꺼 보았다.

 

순수한 Diffuse Color 만 남았다. 머터리얼 Specular 값이 0 인데도 결과의 차이가 있는 걸 보면,

반사상이 맺힐 때, 다른 부분에서 한번 더 본래 색을 덮어 메탈릭이 완전히 0으로 보이지 않게끔 해 주는 것 같다.

 

 

Specular Color

검은색이 되어버린 메탈릭 재질의 색상을 다시 살려내는 것은 스페큘러 컬러라는 것이 확인되었다.

위에서 ComputeF0 함수로 계산된 GBuffer.SpecularColor 색상값은 아래와 같이 사용된다.

(BasePassPixelShader.usf)

    #if !FORCE_FULLY_ROUGH
	if (View.RenderingReflectionCaptureMask) // Force material rendered in reflection capture to have an expanded albedo to try to be energy conservative (when specular is removed).
	#endif
	{
		EnvBRDFApproxFullyRough(GBuffer.DiffuseColor, GBuffer.SpecularColor);
		// When rendering reflection captures, GBuffer.Roughness is already forced to 1 using RoughnessOverrideParameter in GetMaterialRoughness.
	}

 EnvBRDF ApproxFullyRough에서는, 아래와 같이 Diffuse Color에 Specular Color를 더해주고, Specular Color는 0으로 만들어 주고 있다.

void EnvBRDFApproxFullyRough(inout half3 DiffuseColor, inout half3 SpecularColor)
{
	// Factors derived from EnvBRDFApprox( SpecularColor, 1, 1 ) == SpecularColor * 0.4524 - 0.0024
	DiffuseColor += SpecularColor * 0.45;
	SpecularColor = 0;
	// We do not modify Roughness here as this is done differently at different places.
}

맨 오른쪽 Sphere의 Metalic = 1.0f이므로 위에서의 식대로 SpecularColor가 계산되었다면, SpecularColor == BaseColor == (0, 0, 1) 이다.

따라서, EnvBRDFApproxFullyRough 함수가 실행된 이후, DIffuseColor는 (0, 0, 0.45) 가 된다.

 

 

Renderdoc으로 디버깅 해보기

LumenReflections 처리 과정에서 생성되는 LumenReflectionsSpecularIndirect 텍스처이다. 텍스처 포맷은 R16G16B16A16F이다.

이 직후, CopyDepth() 단계에서 SceneDepth 텍스처를 Lumen.DepthHistory 로 카피한 이후, DiffuseIndirectComposite() 단계에서 GBuffer상의 다른 텍스처들과 위 Specular가 합성된다.

(합성되기 전에, 이 텍스처를 BilaterialFIlter*라는 단계를 거쳐 필요한 부분만 필터링한 텍스처로 변환하는 것 같다. 변환된 텍스처는 ResolvedSpecularIndirect 이다.

ResolvedSpecularIndirect
Specular가 합성된 결과물

 

Bilaterial Filter란?

이미지의 Edge 부분은 보존하면서 noise는 줄이는 필터의 일종인 것 같다.

https://velog.io/@claude_ssim/%EA%B3%84%EC%82%B0%EC%82%AC%EC%A7%84%ED%95%99-Edge-Aware-Image-Filtering-Bilateral-Filtering

 

[계산사진학] Edge Aware Image Filtering - Bilateral Filtering

Edge Aware Filters Filter는 다양한 computer vision이나 graphics 분야에서 fundamental building block의 역할을 한다. 이러한 filter의 하나로 특수한 경우가 바로 edge aware filter이다. Edg

velog.io

 

그 다음, 레벨에 배치된 Light로부터 생성되는 정반사 스페큘러 부분은 DirectLighting이 계산되는 부분에서 그려진다. (Light::StandardDeferred)

라이트로부터 오는 Specular가 그려진 SceneColor 텍스처