Unity3D 的物理渲染和光照模型

为什么地球在两极严寒,而在赤道火热?这个问题,仿佛与着色器毫不相干,但却是理解光照模型怎样工作的基础。正如这个教程前面部分所解释的,表面着色器使用数学模型来预测光照在三角形上怎样反射。总的来说,Unity 引擎支持两种着色技术,一个是哑光着色器,一个是镜面材料着色器。前一种对于不透明表面的支持很完美,而后一种则用来模拟反射对象。这些光照模型背后的数学可能非常复杂,但是如果你想创造属于你自己的光照效果,你就得理解它们是如何工作的。直到 Unity 版本 4.x,默认的漫射光照模型都基于朗伯反射(Lambertian reflectance)的。

Unity3D--定义摄像机的投影矩阵

Unity3D 几个默认函数的区分

Unity3D 一个设置方向键移动和空格起跳的脚本

Unity3D 给对象(gameObject)添加脚本代码

Unity3D中实现动态加载Resources目录外的资源

漫反射面:郎伯模型

回到最开始的问题,两极冷的原因就在于它受照射的阳光比赤道区域少。这是由于它们受到太阳的斜射。下图显示了八角形两极区域受到的光线明显少于正面区域。

Light Geometry2

蓝线代表了正交法向量单位长度。橙线表示了光线的方向。光通量的衰减取决于光线方向与法向向量的夹角。在郎伯模型( Lambertian model )中,它的值等于垂直的入射光线。

light cos

其可以表述为:

    \[I= \left \| L \right \| \, cos \alpha = cos \alpha\]

式中, \left \| L \right \| 为 L(这个量是之前定义过的)的长度 ,然后 \alpha 为 N 和 L 的夹角。这个算子在向量代数中被叫做点积 ,在前边的文章中也已经简单介绍了。正式的写法应该是这个样子的:

    \[A \cdot B = \left \| A \right \| \, \left \| B \right \| \, cos \alpha\]

在 Cg/HLSL 中都可以使用点操作符。其将返回一个从 -1 到 1 的数,当两向量正交时将返回 0,并且当它们平行时 \pm 为 1。我们将使用其作为一个乘法系数,代表了从一个光源接收到多少三角光(三角函数光,即正弦余弦的意思,意会!)。

朗伯着色器(Lambertian shader)

我们现在已经有必要来理解一个朗伯模型在着色器中是如何实现的。Cg/HLSL 允许用一个自定义的函数替换标准的朗伯模型。在第8行,在指令 #pragma surface 中使用 SimpleLambert,强制着色器搜索叫做 LightingSimpleLambert 的函数:

Shader "Example/SimpleLambert" {
Properties {
_MainTex ("Texture", 2D) = "white" {}
}
SubShader {
Tags { "RenderType" = "Opaque" }
CGPROGRAM
#pragma surface surf SimpleLambert
 
struct Input {
float2 uv_MainTex;
};
 
sampler2D _MainTex;
void surf (Input IN, inout SurfaceOutput o) {
o.Albedo = tex2D (_MainTex, IN.uv_MainTex).rgb;
}
 
half4 LightingSimpleLambert (SurfaceOutput s, half3 lightDir, half atten) {
half NdotL = dot (s.Normal, lightDir);
half4 c;
c.rgb = s.Albedo * _LightColor0.rgb * (NdotL * atten * 2);
c.a = s.Alpha;
return c;
}
 
ENDCG
}
Fallback "Diffuse"
}
Shader "Example/SimpleLambert" {Properties {_MainTex ("Texture", 2D) = "white" {}}SubShader {Tags { "RenderType" = "Opaque" }CGPROGRAM#pragma surface surf SimpleLambertstruct Input {float2 uv_MainTex;};sampler2D _MainTex;void surf (Input IN, inout SurfaceOutput o) {o.Albedo = tex2D (_MainTex, IN.uv_MainTex).rgb;}half4 LightingSimpleLambert (SurfaceOutput s, half3 lightDir, half atten) {half NdotL = dot (s.Normal, lightDir);half4 c;c.rgb = s.Albedo * _LightColor0.rgb * (NdotL * atten * 2);c.a = s.Alpha;return c;}ENDCG}Fallback "Diffuse"}

从19到25行 展示了朗伯模型如何简单地在一个表面着色器中再实现。NdotL 为光颜色的强度系数(相乘)。参数衰减器用于调制光强。其需要被两个量乘是最初 Unity3D 用于仿真某些特效的技巧。这在 Aras Pranckevičius 中有解释,在Unity4中留存了下来为了向后兼容。最终在 Unity5 进行了修复,所以如果你在 Unity5 上再实现一个朗伯模型的时候,仅仅只要乘上一个量就行啦。

理解标准发光模型的原理是改变其不可或缺的步骤。许多可选的着色技术事实上仍然使用朗伯模型作为其第一步。

Toon shading

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/fb366dea235f5a11bd4d198e9f0d2501.html