GameTech/URP 渲染实战
源码 / Ch11/MyPBR_Input.hlsl
Ch11/MyPBR_Input.hlsl
// MyPBR 的材质输入:属性 CBUFFER、贴图声明、从贴图读出“表面参数”。
// 这里只做“读数据”,不做任何光照计算。
#ifndef COOKBOOK_MYPBR_INPUT_INCLUDED
#define COOKBOOK_MYPBR_INPUT_INCLUDED

#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Packing.hlsl"
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/CommonMaterial.hlsl"   // LerpWhiteTo 等

// 所有材质属性(贴图除外)都放进 UnityPerMaterial,且每个 Pass 看到的布局完全一致,
// 这是 SRP Batcher 兼容的硬条件。贴图本身不进 CBUFFER,但 _ST 要进。
CBUFFER_START(UnityPerMaterial)
    float4 _BaseMap_ST;
    half4  _BaseColor;
    half   _Metallic;
    half   _Smoothness;
    half   _OcclusionStrength;
    half   _BumpScale;
    half4  _EmissionColor;
    half   _Cutoff;
    half   _EnergyCompensation;   // 0 = 只算单次散射,1 = 加多次散射能量补偿
    half   _SpecularOcclusion;    // 0 = 关,1 = 用 AO 推算镜面遮蔽
CBUFFER_END

TEXTURE2D(_BaseMap);      SAMPLER(sampler_BaseMap);
TEXTURE2D(_MaskMap);      // R 金属度  G AO  A 光滑度(与配套贴图约定一致)
TEXTURE2D(_BumpMap);      SAMPLER(sampler_BumpMap);
TEXTURE2D(_EmissionMap);
TEXTURE2D(_DFGLut);       // 程序生成的环境 BRDF 查找表(RG = A, B),用全局的 sampler_LinearClamp
// Mask 与自发光借用 _BaseMap 的采样器:平铺/过滤方式一样,省采样器槽位(部分平台上限 16 个)。
// 法线贴图单独一个采样器:DepthNormals Pass 只采法线不采基础色,
// 若借用 sampler_BaseMap,_BaseMap 被编译器优化掉后 Metal 会报“采样器找不到贴图”。

// 表面参数:全部在“线性空间、物理含义明确”的单位下
struct MySurface
{
    half3 albedo;               // 基础色(金属时就是 F0 的颜色)
    half  alpha;
    half  metallic;
    half  perceptualRoughness;  // 感知粗糙度 = 1 - smoothness,美术直接调的那个值
    half  occlusion;            // 材质 AO(只影响间接光)
    half3 normalTS;             // 切线空间法线
    half3 emission;
};

MySurface MySampleSurface(float2 uv)
{
    MySurface s;
    half4 base = SAMPLE_TEXTURE2D(_BaseMap, sampler_BaseMap, uv) * _BaseColor;
    s.albedo = base.rgb;
    s.alpha  = base.a;
#if defined(_ALPHATEST_ON)
    clip(s.alpha - _Cutoff);
#endif

#if defined(_MASKMAP)
    half4 mask = SAMPLE_TEXTURE2D(_MaskMap, sampler_BaseMap, uv);
    s.metallic   = mask.r;                       // 有 Mask 时金属度完全由贴图决定(与 URP Lit 一致)
    half smooth  = mask.a * _Smoothness;         // 光滑度 = 贴图 × 滑条,滑条当总强度用
    s.occlusion  = LerpWhiteTo(mask.g, _OcclusionStrength);
#else
    s.metallic   = _Metallic;
    half smooth  = _Smoothness;
    s.occlusion  = 1.0h;
#endif
    s.perceptualRoughness = 1.0h - smooth;

#if defined(_NORMALMAP)
    s.normalTS = UnpackNormalScale(SAMPLE_TEXTURE2D(_BumpMap, sampler_BumpMap, uv), _BumpScale);
#else
    s.normalTS = half3(0, 0, 1);
#endif

#if defined(_EMISSION)
    s.emission = SAMPLE_TEXTURE2D(_EmissionMap, sampler_BaseMap, uv).rgb * _EmissionColor.rgb;
#else
    s.emission = 0;
#endif
    return s;
}

#endif