[Unity] URP 셰이더 BRDF(양방향 반사도 분포 함수)
2023. 6. 13. 14:00ㆍUnity
728x90
반응형
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를 끈 이유는 환경 라이트의 개입 없이 램버트 라이팅만 확인하기 위함이다.
참고자료
728x90
반응형
'Unity' 카테고리의 다른 글
[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 |