#define kDielectricSpec half4(0.04, 0.04, 0.04, 1.0 - 0.04) // standard dielectric reflectivity coef at incident angle (= 4%)
으로 정의되어 있으므로
half OneMinusReflectivityMetallic(half metallic)
{
// We'll need oneMinusReflectivity, so
// 1-reflectivity = 1-lerp(dielectricSpec, 1, metallic) = lerp(1-dielectricSpec, 0, metallic)
// store (1-dielectricSpec) in kDielectricSpec.a, then
// 1-reflectivity = lerp(alpha, 0, metallic) = alpha + metallic*(0 - alpha) =
// = alpha - metallic * alpha
half oneMinusDielectricSpec = kDielectricSpec.a;
return oneMinusDielectricSpec - metallic * oneMinusDielectricSpec;
}
이 되어 있어서 Reflectivity 는 유전체일때 0.04 도체일때 1이 나오도록 되어 있다.
half3 brdfDiffuse = albedo * oneMinusReflectivity;
half3 brdfSpecular = lerp(kDieletricSpec.rgb, albedo, metallic);
이므로
유전체일때
brdfDiffuse 는 albedo * (1-0.04) 가 되고
brdfSpecular 는 kDieletricSpec.rgb 즉 float3(0.04, 0.04, 0.04) 가 된다.
가 된다. 뭐 유전체의 스페큘러는 흑백이고 유전체의 반사율은 4% 이므로 맞는듯.
전도체일때에
brdfDiffuse 는 albedo * 0 이 되고
brdfSpecular 는 albedo 가 된다.
그래서 실시간 라이트 연산을 보자면
half3 brdf = brdfData.diffuse;
로 스페큘러를 뺀 디퓨즈 반사율에 알베도를 곱한 것이 들어가고 그게 brdf에 들어간다
아니 brdf라고 이름붙이면 좀 곤란하지 않나? 이미 Albedo가 곱해져 버렸잖아.
흠... 아니 칼라 brdf라고 생각하면 될지도
어쨌건 디퓨즈 연산이 이렇게 되었으므로
스페큘러 연산이 여기에 더해져야 하는데,
brdf += brdfData.specular * DirectBRDFSpecular(brdfData, normalWS, lightDirectionWS, viewDirectionWS);
공식이 이거임.
그럼 brdfData.specular 가 뭔지 봐야하는데, 위에서 설명했듯
비금속일때는 0.04 흑백이고 금속일때는 albedo임.
이걸 일단 구현해보면
Shader "Lecture7"
{
Properties
{
_BaseColor ("Main Color", color) = (1, 1, 1, 1)
_BaseMap ("Main Texture", 2D) = "white" { }
_Metallic ("Metallic", range(0, 1)) = 0
}
SubShader
{
Tags { "RenderType" = "Opaque" "RenderPipeline" = "UniversalPipeline" }
cull off
Pass
{
Tags { "LightMode" = "UniversalForward" }
HLSLPROGRAM
#pragma vertex Vert
#pragma fragment Frag
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
CBUFFER_START(UnityPerMaterial)
float4 _BaseColor;
float4 _BaseMap_ST;
float _Metallic;
CBUFFER_END
TEXTURE2D(_BaseMap);
SAMPLER(sampler_BaseMap);
struct Attributes
{
float4 positionOS : POSITION;
float3 normalOS : NORMAL;
float4 texcoord : TEXCOORD;
};
struct Varyings
{
float4 positionCS : SV_POSITION;
float3 normalWS : NORMAL;
float4 uv : TEXCOORD;
float4 vertexSH : TEXCOORD1;
float3 viewWS : TEXCOORD2;
};
Varyings Vert(Attributes input)
{
Varyings output = (Varyings)0;
//Transform
float3 positionWS = TransformObjectToWorld(input.positionOS.xyz);
float3 positionVS = TransformWorldToView(positionWS);
float4 positionCS = TransformWorldToHClip(positionWS);
// float4 positionCS = TransformObjectToHClip(input.positionOS.xyz);
output.positionCS = positionCS;
output.vertexSH.rgb = SampleSHVertex(output.normalWS);
output.uv.xy = input.texcoord;
output.viewWS = normalize(GetWorldSpaceViewDir(positionWS));
output.normalWS = TransformObjectToWorldDir(input.normalOS);
return output;
}
#define kDielectricSpec half4(0.04, 0.04, 0.04, 1.0 - 0.04)
half4 Frag(Varyings input) : SV_Target
{
//MainLight
Light light = GetMainLight();
float3 lightDir = light.direction;
float3 lightColor = light.color;
//Variables
float3 normalWS = input.normalWS;
//texture
float4 albedo = SAMPLE_TEXTURE2D(_BaseMap, sampler_BaseMap, TRANSFORM_TEX(input.uv, _BaseMap));
half NdotL = saturate(dot(input.normalWS, lightDir));
half3 radiance = lightColor * NdotL;
//brdf
half oneMinusDielectricSpec = kDielectricSpec.a;
half oneMinusReflectivity = oneMinusDielectricSpec - _Metallic * oneMinusDielectricSpec;
half3 brdfDiffuse = albedo * oneMinusReflectivity;
half3 brdfSpecular = lerp(kDieletricSpec.rgb, albedo, _Metallic);
// return float4(brdfDiffuse + brdfSpecular, 1);
float3 brdf = (brdfDiffuse);
brdf = brdf * radiance;
return float4(brdf, 1);
}
ENDHLSL
}
}
}
메탈일때 디퓨즈는 0가 되고 비메탈일때 디퓨즈는 Albedo * (1-0.4) 가 됨
float3 brdf = (brdfSpecular);
brdf = brdf * radiance;
return float4(brdf, 1);
스페큘러를 보면
메탈릭이 0일때 0.4가 되고, 메탈릭이 1일때 albedo가 됨.
반응형
'Shader ' 카테고리의 다른 글
빌보드(Billboard)를 만들어 봅시다 1부. 변환 행렬의 비밀 (0) | 2024.07.27 |
---|---|
Lit 셰이더 분석 2 (0) | 2023.10.10 |
매크로 상수 배열 정의하기 (0) | 2023.02.15 |
카메라 디렉션 구하기 (0) | 2022.10.04 |
OpenGL Transform 개요 (0) | 2022.06.04 |
댓글