边缘光 (Rim Light)

增强物体轮廓的光照效果

📚 原理

边缘光本质上是菲涅尔效应的应用,但通常会加入光源方向的考量,使效果更自然。

无边缘光

简单边缘光

方向性边缘光

💻 代码实现

简单边缘光(基于菲涅尔)

// Properties
_RimColor("Rim Color", Color) = (1, 1, 1, 1)
_RimPower("Rim Power", Range(0.5, 8)) = 3

half4 frag(Varyings input) : SV_Target
{
    float3 N = normalize(input.normalWS);
    float3 V = normalize(_WorldSpaceCameraPos - input.positionWS);
    
    // 边缘光 = 1 - N·V
    float rim = 1.0 - saturate(dot(N, V));
    rim = pow(rim, _RimPower);
    
    half4 baseColor = SAMPLE_TEXTURE2D(_BaseMap, sampler_BaseMap, input.uv);
    half3 finalColor = baseColor.rgb + _RimColor.rgb * rim;
    
    return half4(finalColor, baseColor.a);
}

方向性边缘光(考虑光源)

half4 frag(Varyings input) : SV_Target
{
    float3 N = normalize(input.normalWS);
    float3 V = normalize(_WorldSpaceCameraPos - input.positionWS);
    float3 L = normalize(_MainLightPosition.xyz);
    
    // 基础菲涅尔
    float rim = 1.0 - saturate(dot(N, V));
    rim = pow(rim, _RimPower);
    
    // 只在背光面显示边缘光
    float NdotL = dot(N, L);
    float rimMask = smoothstep(-0.1, 0.3, -NdotL); // 背光遮罩
    
    rim *= rimMask;
    
    half4 baseColor = SAMPLE_TEXTURE2D(_BaseMap, sampler_BaseMap, input.uv);
    half3 finalColor = baseColor.rgb + _RimColor.rgb * rim * _MainLightColor.rgb;
    
    return half4(finalColor, baseColor.a);
}

脉冲边缘光(动画效果)

// 使用时间做脉冲
float pulse = sin(_Time.y * _PulseSpeed) * 0.5 + 0.5;
float rim = 1.0 - saturate(dot(N, V));
rim = pow(rim, _RimPower) * pulse;

half3 finalColor = baseColor.rgb + _RimColor.rgb * rim;

🎮 应用场景

👤 角色高亮

选中、悬停、被击中时的高亮

🌙 月光轮廓

黑夜场景的物体轮廓

🔮 魔法效果

能力激活、施法状态

🎨 卡通渲染

增强卡通风格的深度感

🆚 边缘光 vs 描边

特性 边缘光 (Rim Light) 描边 (Outline)
实现方式 片段着色器内计算 额外 Pass 或后处理
性能 ✅ 轻量 需要额外渲染
效果 柔和发光 锐利线条
应用 光照效果 卡通/选中高亮