[先行版]基础渲染光照介绍
Lambert
漫反射:lambert数值为法线和光照的点乘
| float3 worldLight = normalize(_WorldSpaceLightPos0.xyz)float3 worldNormal = normalize(i.worldNormal)
 
 float NdotL = max(0.0, dot(finiNormal, worldLight))
 
 | 
Phong
环境光+漫反射+高光
高光:光照颜色高光反射颜色视线方向与反射方向的点乘的gloss次幂
Gloss用于控制高光反射范围
| float3 reflectDir = normalize(reflect(-worldLight, finiNormal));float3 viewDir = normalzie(_WorldSpaceCameraPos.xyz - i.worldPOs.xyz);
 float VdotR = max(0.0, dor(reflectDir, viewDir);
 float3 specular = _LightColor0.rgb * _Specular.rgb * pow(VdotR, _Gloss);
 
 float3 color = diffuse + ambient + specular;
 
 | 
Blinn-Phong
与Phong模型的区别在于计算specular时,使用的是半角向量而非反射向量
比起Phong模型,计算效率提升至少三分之一以上
| float3 halfDir = normalize(worldLight + viewDir);float3 NdotH = saturate(dot(halfDir, viewDir);
 float specular = _LightColor0.rgb * _Specular.rgb * pow(NdotH, _Gloss);
 
 | 
法线贴图
UnpackNormal:空间转换(【0-1】空间→【-1-1】空间)
Unity内置的法线转换:
| inline fixed3 UnpackNormalDXT5nm(fixed4 packednormal){
 fixed3 normal;
 normal.xy = packednormal.xy * 2 - 1;
 normal.z = sqrt(1 - saturate(dot(normal.xy, normal.xy)));
 return normal;
 }
 
 inline fixd3 UnpackNormal(fixed4 packednormal)
 {
 ##ifdef UNITY_NO_DXT5nm
 return packednormal.xyz * 2 - 1;
 ##els
 return UnpackNormalDXT5nm(packednormal);
 ##endif
 }
 
 | 
在世界空间计算光照:计算切线空间→世界空间的变换矩阵,在frag中读取法线贴图然后将切线空间的法线信息转换到世界空间
法线的空间变换(法线空间→世界空间):
| struct a2v{
 
 float3 normal : NORMAL;
 float4 tangent : TANGENT;
 }
 
 struct v2f
 {
 
 float3 worldNormalDir : TEXCOORD1;
 float4 worldTangentDir : TEXCOORD2;
 float3 worldbiTangentDir : TEXCOORD3;
 }
 
 v2f vert(a2v v)
 {
 
 
 o.worldNormalDir = UnityObjectToWorldNormal(v.normal);
 o.worldTangentDir = normalize(mul(unity_ObjectToWorld, float4( v.tangent.xyz, 0.0)).xyz);
 o.worldbiTangentDir = normalize(cross(o.worldNormalDir, o.worldTangentDir) * v.tangent.w);
 }
 
 fixed4 frag(v2f i) : SV_Target
 {
 
 float3x3 tangentTransform = float3x3(i.worldTangentDir, i.worldbiTangentDir, i.worldNormalDir);
 
 float3 normalLocal = UnpackNormal(tex2D(_NormalMap, TRANSFORM_TEX(i.uv0, _NormalMap)));
 float3 normalWorld = normalize(mul(normalLocal.rgb, tangentTransform));
 }
 
 | 
CUBE Map
做反射效果、环境光效果时会用到CUBE Map
用反射向量来读取CUBE Map
| float3 worldRefl = normalize(reflect(-viewDir, finiNormal));
 
 float4 refCol = texCUBElod(_Cubemap, float4(worldRefl.rgb, (255-_Gloss)*8/(255)))*_EnvScale;
 
 
 
 
 
 
 
 
 
 | 
IBL
IBL:image based lighting,基于图像的光照,把一张图当成光源来加入物体的光照计算中
通常会用到texCUBElod来模拟PBR中粗糙度的表现(同上方CUBE Map中对_Gloss的解释,只不过换成了对光的反射率/显示出的亮度)
处理漫反射暗面死黑的trick
通过插值计算漫反射(暗部以环境光作为光源,亮部以真是光源作为光源)
| float3 diffuse = lerp(ambient.rgb*_Diffuse.rgb*MainTex.rgb, _LightColor.rgb*_Diffuse.rgb*MainTex.rgb, NdotL);
 | 
有金属质感,同时兼具非金属质感的trick
高光计算的trick
模拟PBR效果:通过gloss的值对specular和diffuse进行插值,当Gloss很高(金属质感)时高光颜色与漫反射无关,当Gloss很低时(非金属质感)高光颜色会被漫反射影响
| float3 specular = _LightColor0.rgb * _SpecularColor.rgb * pow(NdotH, _Gloss);specular = lerp(diffuse * specular, specular, _Gloss/255);
 
 | 
环境映射的trick
和高光计算同理
| reflColor = lerp(diffuse * reflColor, reflColor, _Gloss/255);
 | 
很不标准,不建议用,只是一种强行对PBR的仿制