PBR基础模板
1. PBR主体构成
PBR由主要的两个部分组成
- 直接光照
- 间接光照
☛直接光照
直接光照部分
其中BRDF, 采用拟合的Cook-Torrance BRDF((Bidirectional Reflective Distribution Function) )(双向反射分布函数)来进行计算. 公式如下:
- kd-漫反射
- fd-漫反射BRDF函数
- ks-高光反射
- fs-高光反射BRDF函数
♢fs部分
fs = DGF/4(NdotL)(NdotV)
fs = DVG/4
- D-法线分布函数
- G-几何遮蔽函数
- F-菲涅尔反射函数
- V-可见函数 = G/(NdotL)(NdotV)
D, G, F这几个函数有很多版本, Brian Karis在制作UE4的BRDF时参考了这些版本, 见specular-brdf-reference
⚐D - 法线分布函数采用GGX (Trowbridge-Reitz) - 决定高光的强度和大小
⚐G - 几何遮蔽函数(UE4)使用GGX(Schlick-Smith) - 决定表面的粗糙度
k = a*sqrt(2/PI), 即k等于a乘以(根号(2/PI)).
- a为roughness.
- sqrt(2/PI)=0.797884560803, (另rsqrt(2/PI) = 1.25331413732). 图形见下链接
但在UE中用
k = a/2, 来拟合. 即用0.5代替了0.7978.
又因为本来fs就要除以NdotV*NdotL, 所以最终用V代替了G.
G1(X) = NdotX/((NdotX)*(1-k)+k)
G(L, V) = NdotV*NdotL/((NdotV*(1-k)+k)*(NdotV*(1-k)+k))
V(L, V) = 1/((NdotV*(1-k)+k)*(NdotV*(1-k)+k))
⚐F - 菲涅尔反射公式(Schlick) - 边缘高光
F(V, H) = F0 + (1-F0) * pow((1-VoH), 5)
以下是Unity在URP中使用的版本, Unity非常鸡贼的在brdfData中定义了一个normalizationTerm的值来影响最终的判断, 导致代码阅读困难.
*另外, 公式中的Roughness并非直接采样结果, 而是采样结果的平方. 贴图采样结果在Unity中定义为"PerceptualRoughness", 感知粗糙度.
由以上代码可以看出
♢kd = lerp(1-kDielectricSpec.r, 0, metallic)
♢fd = albedo/pi *pi
♢ks = lerp(kDielectricSpec.rgb, albedo, metallic) = F0 = brdfSpecular
//注, unity用的F是不包含ks的, 所以会乘一个ks, 而通常的F算法是包含ks的,抛弃外乘的ks结果会更接近美术需求. 此处需要继续研究.
//半球积分后, 整个式子都会乘以PI, 而fd正好抵消, fs中的D项也可以抵消分母的PI.
//Unity在光照部分, 将所有的光强度除以了PI, 所以此时无论是漫反射部分, 还是高光部分的D项, 都是为了这个操作才做的简化, 但也造成了需要时刻注意Unity的光照是除以了PI的. 即Unity的光照3.14才等于UE的光照1.
fs比较复杂单独开一段来解析.
注: 整个BRDF中的a, 只是一个与"采样粗糙度roughness"有关的数, Unity中是用采样粗糙度的值的平方来决定a的. 而实际上这部分有待商榷.
虚幻的光照文章中明确的提到了这一点, 是为了让美术调整方便, 让0.5的粗糙度调整起来更符合美术的感知.
☛最终在BRDF.hlsl中加入如下代码
独立可调试版
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 | Shader "Render/URP/PBR/Custom_BRDF_Single_Lit"
{
Properties
{
[Enum(UnityEngine.Rendering.CullMode)]_Cull("Cull", Float) = 2.0
[Enum(UnityEngine.Rendering.BlendMode)]_SrcBlend("SrcBlend", Float) = 5.0
[Enum(UnityEngine.Rendering.BlendMode)]_DstBlend("DstBlend", Float) = 10.0
[Enum(Off, 0, On, 1)]_ZWrite("ZWrite", Float) = 1.0
[Enum(UnityEngine.Rendering.CompareFunction)]_ZTest("ZTest", Float) = 4.0
[Toggle(_ALPHATEST_ON)]_AlphaClip("AlphaClip", Float) = 0.0
_Cutoff("Alpha Cutoff", Range(0.0, 1.0)) = 0.5
[Space(20)]
[MainTexture] _BaseMap("Albedo", 2D) = "white" {}
[MainColor] _BaseColor("Color", Color) = (1,1,1,1)
_Smoothness("Smoothness", Range(0.0, 1.0)) = 0.5
_Metallic("Metallic", Range(0.0, 1.0)) = 0.0
_MetallicGlossMap("Metallic", 2D) = "white" {}
[Toggle(_NORMALMAP)]_UseBumpMap("UseBumpMap", Float) = 0.0
_BumpScale("BumpScale", Float) = 1.0
_BumpMap("Normal Map", 2D) = "bump" {}
[Toggle(_TANGENTMAP)]_UseTangentMap("UseTangentMap", Float) = 0.0
_TangentScale("TangentScale", Range(0, 5.0)) = 1.0
_TangentMap("Tangent Map", 2D) = "bump" {}
_OcclusionStrength("OcclusionStrength", Range(0.0, 1.0)) = 1.0
_OcclusionMap("Occlusion", 2D) = "white" {}
[HDR] _EmissionColor("Color", Color) = (0,0,0)
_EmissionMap("Emission", 2D) = "white" {}
[Space(20)]
_Anisotropy("Anisotropy", Range(-1.0, 1.0)) = 0.0
[KeywordEnum(None,Neubelt,Burley)]_AnisoRoughness("AnisoRoughness", Float) = 0.0
[Space(20)]
[KeywordEnum(None,Lambert,Disney)]_DirDiffuse("DirDiffuse", Float) = 1.0
[KeywordEnum(None,GGX,GGXAniso)]_DirSpec_N("DirSpec_N", Float) = 1.0
[KeywordEnum(None,SmithGGX_1,SmithGGX_2, SmithGGX_3, SmithGGX_Aniso, KSK)]_DirSpec_G("DirSpec_G", Float) = 1.0
[KeywordEnum(None,Schlick)]_DirSpec_F("DirSpec_F", Float) = 1.0
[Space(5)]
[KeywordEnum(None,URP,Builtin)]_DirSpec_VIS("DirSpecVIS", Float) = 0.0
[Space(5)]
[KeywordEnum(None,SH)]_IndirDiff("IndirDiff", Float) = 0.0
[KeywordEnum(None,Iso,Aniso)]_IndirSpec("IndirSpec", Float) = 0.0
// [KeywordEnum(None,NDF,G,Fresnel)]_Debug("Debug", Float) = 1.0
}
SubShader
{
Tags
{
"RenderType"="Opaque" "RenderPipeline" = "UniversalPipeline" "UniversalMaterialType" = "Lit" "IgnoreProjector" = "True"
}
LOD 100
Pass
{
Name "ForwardLit"
Tags
{
"LightMode" = "UniversalForward"
}
Blend[_SrcBlend][_DstBlend]
ZWrite[_ZWrite]
Cull[_Cull]
HLSLPROGRAM
#pragma shader_feature_local_fragment _ANISOROUGHNESS_NONE _ANISOROUGHNESS_NEUBELT _ANISOROUGHNESS_BURLEY
#pragma shader_feature_local_fragment _DIRDIFFUSE_NONE _DIRDIFFUSE_LAMBERT _DIRDIFFUSE_DISNEY
#pragma shader_feature_local_fragment _DIRSPEC_N_NONE _DIRSPEC_N_GGX _DIRSPEC_N_GGXANISO
#pragma shader_feature_local_fragment _DIRSPEC_G_NONE _DIRSPEC_G_SMITHGGX_1 _DIRSPEC_G_SMITHGGX_2 _DIRSPEC_G_SMITHGGX_3 _DIRSPEC_G_SMITHGGX_ANISO _DIRSPEC_G_KSK
#pragma shader_feature_local_fragment _DIRSPEC_F_NONE _DIRSPEC_F_SCHLICK
#pragma shader_feature_local_fragment _DIRSPEC_VIS_NONE _DIRSPEC_VIS_URP _DIRSPEC_VIS_BUILTIN
#pragma shader_feature_local_fragment _INDIRDIFF_NONE _INDIRDIFF_SH
#pragma shader_feature_local_fragment _INDIRSPEC_NONE _INDIRSPEC_ISO _INDIRSPEC_ANISO
#pragma shader_feature_local _NORMALMAP
#pragma shader_feature_local _TANGENTMAP
#pragma shader_feature_local_fragment _ALPHATEST_ON
#pragma multi_compile _ DYNAMICLIGHTMAP_ON
#pragma multi_compile _ _MAIN_LIGHT_SHADOWS _MAIN_LIGHT_SHADOWS_CASCADE _MAIN_LIGHT_SHADOWS_SCREEN
#pragma multi_compile_instancing
#pragma instancing_options renderinglayer
#pragma multi_compile _ DOTS_INSTANCING_ON
#include "Packages/com.unity.render-pipelines.universal/Shaders/LitInput.hlsl"
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"
#pragma vertex LitPassVertex
#pragma fragment LitPassFragment
struct Attributes
{
float4 positionOS : POSITION;
float3 normalOS : NORMAL;
float4 tangentOS : TANGENT;
float2 texcoord : TEXCOORD0;
float2 staticLightmapUV : TEXCOORD1;
float2 dynamicLightmapUV : TEXCOORD2;
};
struct Varyings
{
float2 uv : TEXCOORD0;
float3 positionWS : TEXCOORD1;
float3 normalWS : TEXCOORD2;
half4 tangentWS : TEXCOORD3; // xyz: tangent, w: sign
DECLARE_LIGHTMAP_OR_SH(staticLightmapUV, vertexSH, 8);
float4 positionCS : SV_POSITION;
};
float _Anisotropy, _TangentScale;
TEXTURE2D(_TangentMap);
SAMPLER(sampler_TangentMap);
Varyings LitPassVertex(Attributes input)
{
Varyings output = (Varyings)0;
float3 positionWS = TransformObjectToWorld(input.positionOS.xyz);
float3 positionVS = TransformWorldToView(positionWS);
float4 positionCS = TransformWorldToHClip(positionWS);
real sign = real(input.tangentOS.w) * GetOddNegativeScale();
float3 normalWS = TransformObjectToWorldNormal(input.normalOS);
float3 tangentWS = float3(TransformObjectToWorldDir(input.tangentOS.xyz));
float3 bitangentWS = real3(cross(normalWS, tangentWS)) * sign;
float2 mainuv = TRANSFORM_TEX(input.texcoord, _BaseMap);
OUTPUT_LIGHTMAP_UV(input.staticLightmapUV, unity_LightmapST, output.staticLightmapUV);
#ifdef DYNAMICLIGHTMAP_ON
output.dynamicLightmapUV = input.dynamicLightmapUV.xy * unity_DynamicLightmapST.xy + unity_DynamicLightmapST.zw;
#endif
OUTPUT_SH(output.normalWS.xyz, output.vertexSH);
output.uv = mainuv;
output.positionWS = positionWS;
output.normalWS = normalWS;
output.tangentWS = float4(tangentWS, sign);
output.positionCS = positionCS;
return output;
}
float V_SmithGGXCorrelatedFast(float NoV, float NoL, float roughness)
{
float a = roughness;
float GGXV = NoL * (NoV * (1.0 - a) + a);
float GGXL = NoV * (NoL * (1.0 - a) + a);
return 0.5 / (GGXV + GGXL);
}
float V_SmithGGXCorrelated(float NoV, float NoL, float a)
{
float a2 = a * a;
float GGXL = NoV * sqrt((-NoL * a2 + NoL) * NoL + a2);
float GGXV = NoL * sqrt((-NoV * a2 + NoV) * NoV + a2);
return 0.5 / (GGXV + GGXL);
}
half4 LitPassFragment(Varyings i) : SV_Target
{
half4 albedoAlpha = SampleAlbedoAlpha(i.uv, TEXTURE2D_ARGS(_BaseMap, sampler_BaseMap));
half3 albedo = albedoAlpha.rgb * _BaseColor.rgb;
half alpha = albedoAlpha.a * _BaseColor.a;
#if defined(_ALPHATEST_ON)
clip(alpha - _Cutoff);
#endif
half4 metallicSmoothness = SAMPLE_TEXTURE2D(_MetallicGlossMap, sampler_MetallicGlossMap, i.uv);
half metallic = metallicSmoothness.r * _Metallic;
half smoothness = metallicSmoothness.a * _Smoothness;
float3 normalTS = SampleNormal(i.uv, TEXTURE2D_ARGS(_BumpMap, sampler_BumpMap), _BumpScale);
//SampleOcclusion(uv);
half occ = SAMPLE_TEXTURE2D(_OcclusionMap, sampler_OcclusionMap, i.uv).g;
occ = LerpWhiteTo(occ, _OcclusionStrength);
half3 emission = SAMPLE_TEXTURE2D(_EmissionMap, sampler_EmissionMap, i.uv).rgb * _EmissionColor.rgb;
float sgn = i.tangentWS.w; // should be either +1 or -1
float3 bitangent = sgn * cross(i.normalWS.xyz, i.tangentWS.xyz);
half3x3 tangentToWorld = half3x3(i.tangentWS.xyz, bitangent.xyz, i.normalWS.xyz);
float3 normalWS = TransformTangentToWorld(normalTS, tangentToWorld);
normalWS = normalize(normalWS);
#if _TANGENTMAP
//采样切线图
float4 tt = SAMPLE_TEXTURE2D(_TangentMap, sampler_TangentMap, i.uv);
float3 tangentTS = UnpackNormalmapRGorAG(tt, _TangentScale);
float3 tangentWS = TransformTangentToWorld(tangentTS, tangentToWorld);
tangentWS = Orthonormalize(tangentWS, normalWS);
float3 bitangentWS = cross(normalWS, tangentWS);
#else
real sign = real(i.tangentWS.w) * GetOddNegativeScale();
float3 tangentWS = i.tangentWS.xyz;
float3 bitangentWS = real3(cross(normalWS, tangentWS)) * sign;
#endif
//Reflectivity = lerp(dielectricSpec, 1, metallic) 金属度越高反射率(高光占反射比例)越高
half oneMinusReflectivity = OneMinusReflectivityMetallic(metallic);
half reflectivity = half(1.0) - oneMinusReflectivity;
half3 brdfDiffuseCol = albedo * oneMinusReflectivity;
half3 brdfSpecularCol = lerp(kDieletricSpec.rgb, albedo, metallic);
float perceptualRoughness = PerceptualSmoothnessToPerceptualRoughness(smoothness);
float roughness = max(PerceptualRoughnessToRoughness(perceptualRoughness), HALF_MIN_SQRT);
float roughness2 = max(roughness * roughness, HALF_MIN);
float grazingTerm = saturate(smoothness + reflectivity);
float normalizationTerm = roughness * half(4.0) + half(2.0);
float roughness2MinusOne = roughness2 - half(1.0);
#if _ANISOROUGHNESS_NEUBELT
float roughnessT = roughness;
float roughnessB = lerp(0, roughness, 1 - _Anisotropy);
#elif _ANISOROUGHNESS_BURLEY
float roughnessT = max(roughness * (1 + _Anisotropy), 1e-4);
float roughnessB = max(roughness * (1 - _Anisotropy), 1e-4);
#else
float roughnessT = roughness;
float roughnessB = roughness;
#endif
half3 lightDirectionWS = half3(_MainLightPosition.xyz);
half3 lightColor = _MainLightColor.rgb;
half3 viewDirWS = GetWorldSpaceNormalizeViewDir(i.positionWS);
half3 viewDirTS = GetViewDirectionTangentSpace(float4(tangentWS, sgn), normalWS, viewDirWS);
float3 halfDir = normalize(lightDirectionWS + viewDirWS);
float NoH = saturate(dot(normalWS, halfDir));
half LoH = saturate(dot(lightDirectionWS, halfDir));
half NoV = saturate(dot(normalWS, viewDirWS));
half NoL = saturate(dot(normalWS, lightDirectionWS));
half LoV = saturate(dot(lightDirectionWS, viewDirWS));
half ToH = (dot(tangentWS, halfDir));
half BoH = (dot(bitangentWS, halfDir));
half ToV = (dot(tangentWS, viewDirWS));
half BoV = (dot(bitangentWS, viewDirWS));
half ToL = (dot(tangentWS, lightDirectionWS));
half BoL = (dot(bitangentWS, lightDirectionWS));
//直接光
float4 shadowCoord = TransformWorldToShadowCoord(i.positionWS);
half lightAttenuation = MainLightRealtimeShadow(shadowCoord);
half3 brdfDiffuse = brdfDiffuseCol;
#if _DIRDIFFUSE_LAMBERT
// NoL在光源那边计算
brdfDiffuse *= half3(1, 1, 1);
#elif _DIRDIFFUSE_DISNEY
brdfDiffuse *= DisneyDiffuseNoPI( NoV, NoL, LoV, perceptualRoughness);
//预留Multiscattering
#else
brdfDiffuse *= half3(0, 0, 0);
#endif
#if _DIRSPEC_N_GGX
float d = NoH * NoH * roughness2MinusOne + 1.00001f;
float ndf = roughness2 / (d * d);
#elif _DIRSPEC_N_GGXANISO
//Burley版本
float ndf = D_GGXAnisoNoPI(ToH, BoH, NoH, roughnessT, roughnessB);
#else
float ndf = 1;
#endif
#if _DIRSPEC_VIS_NONE
#if _DIRSPEC_G_SMITHGGX_1
//unity自己方案
float vis = V_SmithJointGGX(NoL, NoV, roughness);
#elif _DIRSPEC_G_SMITHGGX_2
//unreal4方案
float vis = V_SmithJointGGXApprox(NoL, NoV, roughness);
#elif _DIRSPEC_G_SMITHGGX_3
//Frostbite方案
float vis = V_SmithGGXCorrelated(NoL, NoV, roughness);
#elif _DIRSPEC_G_KSK
//ksk在ppt中不是完整的VIS 它漏了一个/4 看unity源码注释就知道
float vis = 1 / (LoH * LoH * (1 - roughness2) + roughness2) * 1 / 4;
#elif _DIRSPEC_G_SMITHGGX_ANISO
//heitz版本
float vis = V_SmithJointGGXAniso(ToV, BoV, NoV, ToL, BoL, NoL, roughnessT, roughnessB);
#else
float vis = 1;
#endif
#if _DIRSPEC_F_SCHLICK
float f = pow(1 - LoH, 5.0);
float3 fresnel = f + brdfSpecularCol * (1 - f);
#else
float3 fresnel = 1;
#endif
float3 vis_f = vis * fresnel;
#elif _DIRSPEC_VIS_URP
//计算Fresnel LoH 就是等于 VoH
//几何遮蔽用ksk-rough版本
//Fresnel_Schlik拟合后乘SpecColor
half LoH2 = LoH * LoH;
float3 vis_f = brdfSpecularCol / (max(0.1h, LoH2) * normalizationTerm);
//#elif _DIRSPEC_VIS_BUILTIN 没什么特别就没写了 上面可以拼出来
//V_SmithJointGGX + 传统fresnel(写法很正式)
#else
float3 vis_f = 1;
#endif
float3 brdfSpec = ndf * vis_f;
half3 brdf = (brdfDiffuse + brdfSpec) * lightColor * NoL;
brdf *= lightAttenuation;
//间接光
float3 inDirCol = float3(0, 0, 0);
#if _INDIRDIFF_SH
half3 indirectDiffuse = SAMPLE_GI(i.staticLightmapUV, i.vertexSH, normalWS) * brdfDiffuseCol;
inDirCol += indirectDiffuse;
#endif
#if _INDIRSPEC_ISO || _INDIRSPEC_ANISO
#if _INDIRSPEC_ISO
half3 reflectVector = reflect(-viewDirWS, normalWS);
#else
half3 anisotropicDirection = _Anisotropy >= 0.0 ? bitangentWS : tangentWS;
half3 anisotropicTangent = cross(anisotropicDirection, viewDirWS);
half3 anisotropicNormal = cross(anisotropicTangent, bitangentWS);
half3 bentNormal = normalize(lerp(normalWS, anisotropicNormal, _Anisotropy));
half3 reflectVector = reflect(-viewDirWS, bentNormal);
#endif
half fresnelTerm = Pow4(1.0 - NoV);
half3 indirectSpecular = GlossyEnvironmentReflection(reflectVector, i.positionWS, perceptualRoughness, 1.0h) * NoV;
float surfaceReduction = 1.0 / (roughness2 + 1.0);
inDirCol += indirectSpecular * half3(surfaceReduction * lerp(brdfSpecularCol, grazingTerm, fresnelTerm));
#endif
inDirCol *= albedo;
half4 color = float4(brdf + inDirCol, alpha);
color.rgb *= occ;
color.rgb += emission;
return color;
}
ENDHLSL
}
Pass
{
Name "ShadowCaster"
Tags
{
"LightMode" = "ShadowCaster"
}
ZWrite On
ZTest LEqual
ColorMask 0
Cull[_Cull]
HLSLPROGRAM
#pragma exclude_renderers gles gles3 glcore
#pragma target 4.5
// -------------------------------------
// Material Keywords
#pragma shader_feature_local_fragment _ALPHATEST_ON
#pragma shader_feature_local_fragment _SMOOTHNESS_TEXTURE_ALBEDO_CHANNEL_A
//--------------------------------------
// GPU Instancing
#pragma multi_compile_instancing
#pragma multi_compile _ DOTS_INSTANCING_ON
// -------------------------------------
// Universal Pipeline keywords
// This is used during shadow map generation to differentiate between directional and punctual light shadows, as they use different formulas to apply Normal Bias
#pragma multi_compile_vertex _ _CASTING_PUNCTUAL_LIGHT_SHADOW
#pragma vertex ShadowPassVertex
#pragma fragment ShadowPassFragment
#include "Packages/com.unity.render-pipelines.universal/Shaders/LitInput.hlsl"
#include "Packages/com.unity.render-pipelines.universal/Shaders/ShadowCasterPass.hlsl"
ENDHLSL
}
Pass
{
Name "DepthOnly"
Tags
{
"LightMode" = "DepthOnly"
}
ZWrite On
ColorMask 0
Cull[_Cull]
HLSLPROGRAM
#pragma exclude_renderers gles gles3 glcore
#pragma target 4.5
#pragma vertex DepthOnlyVertex
#pragma fragment DepthOnlyFragment
// -------------------------------------
// Material Keywords
#pragma shader_feature_local_fragment _ALPHATEST_ON
#pragma shader_feature_local_fragment _SMOOTHNESS_TEXTURE_ALBEDO_CHANNEL_A
//--------------------------------------
// GPU Instancing
#pragma multi_compile_instancing
#pragma multi_compile _ DOTS_INSTANCING_ON
#include "Packages/com.unity.render-pipelines.universal/Shaders/LitInput.hlsl"
#include "Packages/com.unity.render-pipelines.universal/Shaders/DepthOnlyPass.hlsl"
ENDHLSL
}
}
}
|
参考网页:
- PBR快速(遁)入(空)门 (Physically Based Rendering)
- URP的默认BRDF
- 草履虫也能看懂的Cook-Torrance BRDF
- learnopengl-cn
- 关于菲涅尔项
- UC Davis - Cook-Torrance BRDF - Youtube
- 独立可调试版
延展