原文:https://catlikecoding.com/unity/tutorials/rendering/part-4/
译文:http://gad.qq./com/program/translateview/7173932
第四章:基本光照知识点总结
知识点:
· 将法线从物体空间转换到世界空间。
· 使用方向光。
· 计算漫反射和镜面高光反射。
· 实现能量守恒。
· 使用金属的工作流程。
· 利用Unity的基于物理规则渲染的算法。
1法线从物体空间转换到世界空间
动态批次合并(DyDynamic Batching)
Unity动态地将小的网格合并在一起,以减少绘制调用。球体的网格对动态批次合并而言太大了,因此球体的网格不受影响。但是动态批次合并会对立方体有影响。
世界坐标空间中的法线
InterpolatorsMyVertexProgram (VertexData v) {
Interpolatorsi;
i.position= mul(UNITY_MATRIX_MVP, v.position);
i.normal = mul(unity_ObjectToWorld, float4(v.normal, 0));
i.uv= TRANSFORM_TEX(v.uv, _MainTex);
return
i;}
v.normal
是一个
float3
类型,
unity_ObjectToWorld
是
4*4
矩阵,将点(或者向量)从模型坐标系变换到世界坐标系
法向量归一化:
i.normal =normalize(i.normal);
法向量的拉伸会发生角度的变动
在X轴进行缩放,顶点和法线都变为½。
在X轴进行缩放,顶点变为½,而法线加倍。
正确的做法
UnityCG包含一个方便的UnityObjectToWorldNormal
InterpolatorsMyVertexProgram (VertexData v) {
Interpolators i;
i.position = mul(UNITY_MATRIX_MVP,v.position);
i.normal =UnityObjectToWorldNormal(v.normal);
i.uv = TRANSFORM_TEX(v.uv, _MainTex);
returni;
}
重新归一化
在片段着色器中,法线或通过内插值器,它会变得比单位长度更短一些,需要进行重新归一化,(也可以选择不归一化,因为误差通常很小,这是移动设备中常见的优化)
2漫反射的渲染Diffuse
兰伯特余弦定理:漫反射光的量与光的入射方向和表面法线之间的角度的余弦成正比
点积: 两个向量之间的点积在几何上定义为A·B = ||A || || B || cosθ。
在两个单位向量的情况下,A·B =cosθ。
UnityStandardBRDF.cginc导入文件定义了方便的DotClaped函数,确保点积结果在0-1之间
光源
平行光被认为是无限远的
UnityShaderVariables里面定义了float4_WorldSpaceLightPos0,光源的位置有四个分量,因为这些是齐次坐标。因此,我们的方向光的第四个分量是0,(齐次坐标系中,w=1表示点)
渲染路径有:前向渲染路径,延迟渲染路径
使用前向渲染路径,在shader中必须有个一通道使用LightMode =“ForwardBase”
光源可以有颜色,通过fixed4 _LightColor0
反射率Albedo
材质的漫反射率的颜色被称为材质的反射率。因此,它描述了有多少红色、绿色和蓝色被漫反射。其余的部分被吸收。
float3diffuse = albedo * lightColor * DotClamped(lightDir, i.normal);
漫反射颜色 = 反射率 * 光颜色* 漫反射光强度
3镜面高光着色(Specular Shading)
视点方向
float3 viewDir = normalize(_WorldSpaceCameraPos -i.worldPos);
反射光方向
float3 reflectionDir= reflect(-lightDir, i.normal);
Blinn反射模型
视点方向与反射方向的点积,光滑度控制分量大小
镜面高光 =pow(DotClamped(viewDir, reflectionDir),_Smoothness * 100)
Blinn-Phong
使用光的入射方向和视线方向之间的半矢量halfVector,法线normal和半矢量之间的点积可以确定镜面高光的贡献。
halfVector = normalize(lightDir + viewDir)
镜面高光 =pow(DotClamped(halfVector, i.normal),_Smoothness * 100)
优点:可以产生更大个高亮,更接近现实
(镜面高光可以带颜色)
能量守恒
简单把结果 = 漫反射+镜面高光反射,物体太亮了,可以简单将漫反射乘以1减去镜面高光,来调整albedo *= 1 - _SpecularTint.rgb(彩色能量守恒)
Unity函数EnergyConservationBetweenDiffuseAndSpecular(half3 albedo, half3 specColor, out half oneMinusReflectivity)
4.Metallic(这个好些)
金属度(金属没有反射率),通过调节金属度来调节漫反射与镜面反射的比例。
specular *= albedo * _Metallic
albedo * = 1-_Metallic
Unity中也自带函数
5. Physically-Based Shading
目前行业热点,代替了前面的Blinn-Phong模型,
Unity中在"UnityPBSLighting.cginc"文件中
BRDF双向反射分布数(不懂都是公式)
要使用它,在shader中shader level要高于3.0
#pragma target 3.0
float4 MyFragmentProgram (Interpolators i) : SV_TARGET {
i.normal = normalize(i.normal);
float3 lightDir = _WorldSpaceLightPos0.xyz;
float3 viewDir = normalize(_WorldSpaceCameraPos - i.worldPos);
float3 lightColor = _LightColor0.rgb;
float3 albedo = tex2D(_MainTex, i.uv).rgb * _Tint.rgb;
float3 specularTint;
float oneMinusReflectivity;
albedo = DiffuseAndSpecularFromMetallic(
albedo, _Metallic, specularTint, oneMinusReflectivity
);
UnityLight light;
light.color = lightColor;
light.dir = lightDir;
light.ndotl = DotClamped(i.normal, lightDir);
UnityIndirect indirectLight;
indirectLight.diffuse = 0;
indirectLight.specular = 0;
return UNITY_BRDF_PBS(
albedo, specularTint,
oneMinusReflectivity, _Smoothness,
i.normal, viewDir,
light, indirectLight
);
}
UNITY_BRDF_PBS8个参数,漫反射颜色,高光颜色,反射率,光滑度,法向,视点方向,直接光源和间接光