菲涅尔效果 (Fresnel Effect)
物体边缘发光的物理原理
📚 什么是菲涅尔效应
菲涅尔效应是一种光学现象:当光线以掠射角度射向表面时,反射率会增加。在 Shader 中常用于制作边缘光、能量护盾、水面反射等效果。
🧮 数学原理
菲涅尔公式(简化版)
基础公式:Fresnel = 1 - (N·V)
幂次调整:Fresnel = pow(1 - (N·V), power)
其中:
- N:表面法线
- V:视线方向
- power:控制边缘范围(通常 1-5)
Schlick 近似(物理更准确)
F = F0 + (1 - F0) × (1 - N·V)⁵
F0:基础反射率(垂直入射时的反射率)
- 水:约 0.02
- 玻璃:约 0.04
- 金属:0.5 - 1.0
💻 代码实现
基础菲涅尔
// Properties
_FresnelPower("Fresnel Power", Range(0.1, 5)) = 2
_FresnelColor("Fresnel Color", Color) = (0, 0.5, 1, 1)
// Fragment Shader
half4 frag(Varyings input) : SV_Target
{
float3 N = normalize(input.normalWS);
float3 V = normalize(_WorldSpaceCameraPos - input.positionWS);
// 计算菲涅尔
float NdotV = saturate(dot(N, V));
float fresnel = pow(1.0 - NdotV, _FresnelPower);
// 应用颜色
half4 baseColor = SAMPLE_TEXTURE2D(_BaseMap, sampler_BaseMap, input.uv);
half3 finalColor = lerp(baseColor.rgb, _FresnelColor.rgb, fresnel);
return half4(finalColor, baseColor.a);
}
Schlick 近似
float FresnelSchlick(float cosTheta, float F0)
{
return F0 + (1.0 - F0) * pow(1.0 - cosTheta, 5.0);
}
// 使用
float NdotV = saturate(dot(N, V));
float fresnel = FresnelSchlick(NdotV, 0.04); // 0.04 为非金属默认值
带颜色的菲涅尔
float3 FresnelSchlickColor(float cosTheta, float3 F0)
{
return F0 + (1.0 - F0) * pow(1.0 - cosTheta, 5.0);
}
// 金属使用 albedo 作为 F0
float3 F0 = lerp(0.04, albedo, metallic);
float3 fresnel = FresnelSchlickColor(NdotV, F0);
🎮 应用场景
🛡️ 能量护盾
科幻护盾的边缘发光效果
🌊 水面反射
水面边缘反射天空
👤 角色轮廓
角色选中或被击中时的高亮
🚗 车漆效果
双层漆面的边缘色变
💡 常用组合
菲涅尔 + 自发光
// 护盾效果 float fresnel = pow(1.0 - NdotV, _FresnelPower); float3 emission = _FresnelColor.rgb * fresnel * _EmissionStrength; return half4(baseColor.rgb + emission, baseColor.a * fresnel);