GameTech/URP 渲染实战
源码 / shaders/Ch18/Ch18Common.glsl
shaders/Ch18/Ch18Common.glsl
// 第 18 章公共函数:一个够用的“简易光照”,以及菲涅尔、哈希等小工具。(GLSL 版,对应 Ch18Common.hlsl)
// 本章重点是效果本身,光照只用主光 + 阴影 + 球谐环境光 + Blinn-Phong 高光,
// 完整 PBR 见第 10、11 章;需要时可以把 SimpleLighting 换成 UniversalFragmentPBR。
// Core.glsl / Lighting.glsl 已自动包含,这里不用再 include。
#ifndef COOKBOOK_CH18_COMMON_INCLUDED
#define COOKBOOK_CH18_COMMON_INCLUDED

vec3 SimpleLighting(vec3 albedo, vec3 positionWS, vec3 normalWS, float smoothness)
{
    vec4 shadowCoord = TransformWorldToShadowCoord(positionWS);
    Light mainLight = GetMainLight(shadowCoord);
    vec3 viewWS = GetWorldSpaceNormalizeViewDir(positionWS);

    float NdotL = saturate(dot(normalWS, mainLight.direction));
    vec3 halfDir = SafeNormalize(mainLight.direction + viewWS);
    // 光滑度 0~1 映射到高光指数 2~2048,乘 smoothness 让粗糙表面的高光更暗
    float specPow = exp2(10.0 * smoothness + 1.0);
    float spec = pow(saturate(dot(normalWS, halfDir)), specPow) * smoothness * NdotL;

    float atten = mainLight.distanceAttenuation * mainLight.shadowAttenuation;
    vec3 direct = (albedo * NdotL + spec) * mainLight.color * atten;
    vec3 ambient = SampleSH(normalWS) * albedo;
    return direct + ambient;
}

// 经验菲涅尔:视线与法线越垂直(轮廓处)值越大。power 越大,亮边越窄。
float FresnelRim(vec3 normalWS, vec3 viewWS, float power)
{
    return pow(1.0 - saturate(dot(normalWS, viewWS)), power);
}

// 简单的 1D/2D 哈希,用来做闪烁、故障条等随机数
float Hash11(float p)
{
    p = fract(p * 0.1031);
    p *= p + 33.33;
    p *= p + p;
    return fract(p);
}

float Hash21(vec2 p)
{
    vec3 p3 = fract(vec3(p.xyx) * 0.1031);
    p3 += dot(p3, p3.yzx + 33.33);
    return fract((p3.x + p3.y) * p3.z);
}

#endif