BRDF는 Bidirectional Reflectance Distribution Function의 약자이다. 어떻게 반사할지를 정의하는 함수이다.
요즘의 사실적인 BRDF는 PBS(Physically Based Shading)라고 부르는 물리 기반 셰이딩 기법을 사용한다. 유니티는 Smoothness, Metallic, BaseColor 값으로 사실적으로 보이도록 한다.
(*참고 디즈니 BRDF 자료 링크)

Lambert BRDF
Shader "Custom/BRDF/Lambert"
{
Properties
{
[MainTexture] _BaseMap("Base Map", 2D) = "white" {}
[MainColor][HDR]_BaseColor("BaseColor", Color) = (1, 1, 1, 1)
}
SubShader
{
Tags { "RenderType" = "Opaque" "RenderPipeline" = "UniversalPipeline" }
Pass
{
HLSLPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"
struct Attributes
{
float4 positionOS : POSITION;
float2 uv : TEXCOORD0;
float3 normalOS : NORMAL;
};
struct Varyings
{
float4 positionHCS : SV_POSITION;
float2 uv : TEXCOORD0;
float3 normal : TEXCOORD1;
float3 lightDir : TEXCOORD2;
};
TEXTURE2D(_BaseMap);
SAMPLER(sampler_BaseMap);
CBUFFER_START(UnityPerMaterial)
float4 _BaseMap_ST;
half4 _BaseColor;
CBUFFER_END
Varyings vert(Attributes IN)
{
Varyings OUT;
OUT.positionHCS = TransformObjectToHClip(IN.positionOS.xyz);
OUT.uv = TRANSFORM_TEX(IN.uv, _BaseMap);
OUT.normal = TransformObjectToWorldNormal(IN.normalOS);
OUT.lightDir = normalize(_MainLightPosition.xyz);
return OUT;
}
half4 frag(Varyings IN) : SV_Target
{
// 이걸 안 하면 버텍스 사이 픽셀 노멀의 길이가 1이 아닌 것들이 발생함.
IN.normal = normalize(IN.normal);
half4 color = SAMPLE_TEXTURE2D(_BaseMap, sampler_BaseMap, IN.uv);
color *= _BaseColor;
float NdotL = saturate(dot(IN.normal, IN.lightDir));
half3 ambient = SampleSH(IN.normal);
half3 lighting = NdotL * _MainLightColor.rgb + ambient;
color.rgb *= lighting;
return color;
}
ENDHLSL
}
UsePass "Universal Render Pipeline/Lit/ShadowCaster"
}
}

Half Lambert BRDF
밸브 게임사에서 만들었던 BRDF이다. 그냥 램버트가 특정 경계에서 극단적으로 어두워지는 느낌이라면 하프 램버트는 부드럽게 라이팅 된다.

Shader "Custom/BRDF/HalfLambert No Ambient"
{
Properties
{
...
}
SubShader
{
Tags { "RenderType" = "Opaque" "RenderPipeline" = "UniversalPipeline" }
Pass
{
...
half4 frag(Varyings IN) : SV_Target
{
// 이걸 안 하면 버텍스 사이 픽셀 노멀의 길이가 1이 아닌 것들이 발생함.
IN.normal = normalize(IN.normal);
half4 color = SAMPLE_TEXTURE2D(_BaseMap, sampler_BaseMap, IN.uv);
color *= _BaseColor;
float NdotL = saturate(dot(IN.normal, IN.lightDir) * 0.5 + 0.5);
//half3 ambient = SampleSH(IN.normal);
//half3 lighting = NdotL * _MainLightColor.rgb + ambient;
half3 lighting = NdotL * _MainLightColor.rgb;
color.rgb *= lighting;
return color;
}
ENDHLSL
}
UsePass "Universal Render Pipeline/Lit/ShadowCaster"
}
}
Ambient를 주석으로 껐고 saturate 함수를 적용하기 전에 " * 0.5 + 0.5 " 계산으로 하프 램버트를 적용했다는 것을 볼 수 있다. 원래 -1이었던 값은 0.5를 곱하고 0.5를 더하여 0이 되고, 원래 0이었던 값은 0.5를 곱하고 0.5를 더하여 0.5가 되어 조금 완만한 곡선을 그리는 것을 위의 첨부한 사진에서 볼 수 있다.
과거에 엔진 성능이 부족해서 쓰던 방식이라 지금은 쓰이는 일이 없고 GI 환경광과 같이 사용하면 오히려 너무 밝아지게 된다.
Lambert NoAmbient
Shader "Custom/BRDF/Lambert No Ambient"
{
Properties
{
...
}
SubShader
{
Tags { "RenderType" = "Opaque" "RenderPipeline" = "UniversalPipeline" }
Pass
{
...
half4 frag(Varyings IN) : SV_Target
{
// 이걸 안 하면 버텍스 사이 픽셀 노멀의 길이가 1이 아닌 것들이 발생함.
IN.normal = normalize(IN.normal);
half4 color = SAMPLE_TEXTURE2D(_BaseMap, sampler_BaseMap, IN.uv);
color *= _BaseColor;
float NdotL = saturate(dot(IN.normal, IN.lightDir));
//half3 ambient = SampleSH(IN.normal);
//half3 lighting = NdotL * _MainLightColor.rgb + ambient;
half3 lighting = NdotL * _MainLightColor.rgb;
color.rgb *= lighting;
return color;
}
ENDHLSL
}
UsePass "Universal Render Pipeline/Lit/ShadowCaster"
}
}
다른 부분들은 Lambert BRDF와 같고 프래그먼트 쪽이 약간 달라졌다. half3 두 줄을 주석으로 처리하여 Ambient를 끈 이유는 환경 라이트의 개입 없이 램버트 라이팅만 확인하기 위함이다.
참고자료
아티스트를 위한 유니티 URP 셰이더 입문 - YES24
셰이더(Shader)를 HLSL(High Level Shader Language)로 다루고 싶은 아티스트를 위한 입문서다. 아티스트들의 눈높이에 맞추어 기초 그래픽스 이론과 셰이더 개념을 설명하고, 이를 유니티 엔진에서 활용할
www.yes24.com
'Unity > 내용 정리&Tip' 카테고리의 다른 글
| [Unity] URP 셰이더 그래프 기초 개념2 (Graph Inspector - Node Settings 인터페이스) (0) | 2023.07.10 |
|---|---|
| [Unity] URP 셰이더 퐁(Phong), 블린 퐁(Blinn Phong), 프레넬(Fresnel), Vertex Shader 연산(Gouraud Shading) (0) | 2023.06.13 |
| [Unity] URP 셰이더 아웃라인 셰이더 (0) | 2023.06.12 |
| [Unity] 행렬과 MVP 변환 (0) | 2023.06.12 |
| [Unity] URP 셰이더 HLSL 추가사항 (#pragma, 변수 Scope) (0) | 2023.06.12 |