[基础] Unity Shader:法向量与光照

在现实世界中,太阳照射在物体的那一面较亮,而物体背朝太阳的那一面较暗,这就是我们要讨论的问题:如何计算一个物体各个表面的阴暗程度。

1. 法向量

法向量(normal vector) 也被称为法线(normal),它是垂直于平面的向量,在游戏中,模型的一个顶点往往会携带额外的信息,顶点法线就是其中之一。

2. 辐照度

在实时渲染中,我们通常把光源当成一个没有体积的点,用 来表示它的方向,那么,我们如何量化光呢?在光学里,我们使用辐照度(irradiance) 来量化光。在计算光照模型时,我们需要知道一个物体表面的辐照度,而物体表面往往是和 不垂直的,那么如何计算这样的表面的辐照度呢?

如上图所示,我们可以使用光源方向 和表面法线 之间的夹角 的余弦值来得到。

3. 辐照度的计算

两个向量之间的一个点积公式如下:

由此公式我们可以得出:

若我们将 规范化,也就是模长变为1,则公式又变成了:

由此可得出,辐照度可通过规范化光源向量 和规范化法向量 的点积来得到。

4. 应用于Shader

接下来,我们将理论真正地应用于Shader中,首先,我们要先规范化法向量和光源向量:

cpp 复制代码
float3 N = normalize(appData.normal); // 规范化法向量
float3 L = normalize(_WorldSpaceLightPos0); // 规范化光源向量

然后通过点积求得辐照度,为了防止点积结果为负值,我们需要将其限制在[0, 1]范围内,Cg提供了 saturate 函数恰恰可以实现这样的功能:

cpp 复制代码
float E = saturate(dot(N, L)); // 辐照度

得到辐照度后,我们就可以用物体颜色乘上辐照度了:

cpp 复制代码
outData.color = _Color.rgb * E; // 物体颜色 × 辐照度

当然,我们也可以让物体表面颜色也受到光照色的影响,不过在此之前要先引入 Lighting.cginc 文件:

cpp 复制代码
outData.color = (_Color * 0.5 + _LightColor0 * 0.5) * E; // 物体颜色混合光照色 × 辐照度

当然,我们也可以在片元着色器最后返回颜色时加上环境色 UNITY_LIGHTMODEL_AMBIENT,这样物体表面也将会受到环境色的影响:

cpp 复制代码
return inputData.color + UNITY_LIGHTMODEL_AMBIENT;

最终效果如下:

相关推荐
向宇it6 小时前
2025年技术总结 | 在Unity游戏开发路上的持续探索与沉淀
游戏·unity·c#·游戏引擎
技术小甜甜9 小时前
【Godot】【入门】输入系统详解:InputMap 动作映射(键鼠/手柄一套代码通吃)
游戏引擎·godot
Thomas_YXQ12 小时前
Unity3D IL2CPP如何调用Burst
开发语言·unity·编辑器·游戏引擎
Jet_581 天前
一次完整的 Unity Mono 安卓游戏逆向:Frida Hook 绕过碰撞死亡判定
android·游戏·unity
老朱佩琪!1 天前
Unity享元模式
unity·游戏引擎·享元模式
lrh30251 天前
Custome SRP 17 - FXAA
3d·unity·srp·render pipeline·fxaa·抗锯齿
XR技术研习社1 天前
第二种升级Quest系统的方案
unity·xr·vr
三和尚1 天前
AI开发之Cursor的下载安装以及Unity-MCP下载安装到你的个人Unity项目中(一)
unity·ai·游戏引擎·cursor·unity-mcp·unity自动化
__water1 天前
RHQ《Unity2D图片切割方式》
unity·2d·精灵图切割
DaLiangChen1 天前
Unity 导览相机实现:键鼠控制自由漫游(WASD 移动 + 右键旋转)
数码相机·unity·游戏引擎