Unity Shader 学习系列(九)第一个 Fresnel Shader
这一篇做很多特效都会用到的“边缘光”:Fresnel。
简单说,就是视线越贴近表面边缘,亮度越强。
1. 先新建 Shader 文件
建议在这个目录新建文件:
Assets/Shaders/Effects/S08_Fresnel.shader
2. 完整代码
Shader "Study/S08_Fresnel"
{
Properties
{
_BaseColor ("Base Color", Color) = (0.1, 0.2, 0.6, 1.0)
_FresnelColor ("Fresnel Color", Color) = (0.3, 0.9, 1.0, 1.0)
_FresnelPower ("Fresnel Power", Float) = 4.0
_FresnelIntensity ("Fresnel Intensity", Float) = 1.0
}
SubShader
{
Tags
{
"RenderType" = "Opaque"
"RenderPipeline" = "UniversalPipeline"
"Queue" = "Geometry"
}
Pass
{
Name "ForwardUnlit"
HLSLPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
struct Attributes
{
float4 positionOS : POSITION;
float3 normalOS : NORMAL;
};
struct Varyings
{
float4 positionCS : SV_POSITION;
float3 normalWS : TEXCOORD0;
float3 positionWS : TEXCOORD1;
};
float4 _BaseColor;
float4 _FresnelColor;
float _FresnelPower;
float _FresnelIntensity;
Varyings vert(Attributes input)
{
Varyings output;
VertexPositionInputs posInputs = GetVertexPositionInputs(input.positionOS.xyz);
VertexNormalInputs normalInputs = GetVertexNormalInputs(input.normalOS);
output.positionCS = posInputs.positionCS;
output.positionWS = posInputs.positionWS;
output.normalWS = normalInputs.normalWS;
return output;
}
half4 frag(Varyings input) : SV_Target
{
float3 normalWS = normalize(input.normalWS);
float3 viewDirWS = normalize(GetCameraPositionWS() - input.positionWS);
float ndv = saturate(dot(normalWS, viewDirWS));
float fresnel = pow(1.0 - ndv, _FresnelPower) * _FresnelIntensity;
float3 finalColor = _BaseColor.rgb + _FresnelColor.rgb * fresnel;
return half4(finalColor, 1.0);
}
ENDHLSL
}
}
}
3. 知识点拆解
3.1 为什么 Fresnel 要用法线
Fresnel 本质是“法线方向和视线方向夹角”驱动的效果。
所以除了位置,这篇第一次必须把 normalOS 从顶点输入带进来。
3.2 GetVertexPositionInputs 和 GetVertexNormalInputs 的意义
这两个 URP 封装函数会帮你把对象空间数据转到常用空间:
positionWS:世界空间位置。normalWS:世界空间法线。positionCS:裁剪空间位置(用于光栅化)。
相比手写矩阵乘法,初学阶段更稳、更不容易出错。
3.3 视线方向是怎么求的
GetCameraPositionWS() - input.positionWS
从像素指向相机的向量就是视线方向。归一化后才能参与点乘。
3.4 dot(normal, viewDir) 代表什么
点乘值越接近 1,说明视线越正对表面;越接近 0,越接近擦边看。
Fresnel 一般就是在“擦边”时变亮,所以用了:
1.0 - ndv
3.5 pow 对边缘分布的影响
pow(x, power) 会改变曲线陡峭程度。
power小:边缘光扩散更宽。power大:边缘光更细、更集中。
这就是 _FresnelPower 的调参意义。
3.6 最终颜色怎么叠加
_BaseColor + _FresnelColor * fresnel
你可以理解为:先有一个基础底色,再在边缘区域额外叠一层发光色。
这是最常见、也最容易控制的写法。
4. 跑起来验证
- 新建材质:
Assets/Materials/M_Fresnel.mat。 - Shader 选择:
Study/S08_Fresnel。 - 把材质挂到球体上,旋转相机观察边缘高光变化。
- 重点调
_FresnelPower和_FresnelIntensity,看“边缘宽度”和“亮度”分别怎么变。
这篇掌握后,你就能做非常多“护盾、描边、能量体”效果。
5. 本篇图片占位
材质展示图:
动态效果图:
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 Beyond Lightcone!





