【UnityShader】高光反射光照模型
先给出基本光照模型中高光反射部分的计算公式:

其中要知道高光反射系数m,视角方向v和反射方向。
反射方向可以由表面法线和光线方向计算 r = l-2(n·l)n ,CG中也提供了reflect函数来操作。
这里给出逐顶点计算的代码:
// Upgrade NOTE: replaced '_Object2World' with 'unity_ObjectToWorld' // Upgrade NOTE: replaced '_World2Object' with 'unity_WorldToObject' Shader "Custom/Chapter6-SpecularVertexLevel" { Properties{ _Diffuse("Diffuse",Color) = (1,1,1,1) _Specular("Specular",Color)=(1,1,1,1) //高光颜色 _Gloss("Gloss",Range(8.0,256)) = 20//高光区域大小 } SubShader{ Pass{ Tags{"LightMode" = "ForwardBase"} CGPROGRAM #pragma vertex vert #pragma fragment frag #include "Lighting.cginc" fixed4 _Diffuse; fixed4 _Specular; float _Gloss; struct a2v{ float4 vertex:POSITION;//顶点信息 float3 normal:NORMAL; }; struct v2f{ float4 pos:SV_POSITION;//裁剪空间信息 fixed3 color:COLOR; }; v2f vert(a2v v){ v2f o; o.pos = UnityObjectToClipPos(v.vertex);//将模型空间坐标转化为裁剪空间 //获得环境光 fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz; //将法线由模型空间转化到世界坐标 fixed3 worldNormal =normalize( mul(v.normal,(float3x3)unity_WorldToObject)); //得到光源方向 fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz); //计算漫反射 fixed3 diffuse = _Diffuse.rgb*_LightColor0*saturate(dot(worldNormal,worldLightDir)); //_LightColor0为内置变量 :表示光色及强度 //计算反射方向 fixed3 reflectDir = normalize(reflect(-worldLightDir,worldNormal)); //计算视角方向 fixed3 viewDir = normalize(_WorldSpaceCameraPos.xyz-mul(unity_ObjectToWorld,v.vertex).xyz); //计算高光反射 fixed3 specular = _LightColor0*_Specular.rgb*pow(saturate(dot(reflectDir,viewDir)),_Gloss); o.color = ambient+diffuse+specular; return o; } fixed4 frag(v2f i):SV_Target{ return fixed4(i.color,1.0); } ENDCG } } FallBack "Specular" }
此外,还有一种Blinn-Phong光照模型:
Blinn模型引入了一个新的矢量h来替换phomh中的r。
其中h的计算公式如下:

给出程序如下:
// Upgrade NOTE: replaced '_Object2World' with 'unity_ObjectToWorld' // Upgrade NOTE: replaced '_World2Object' with 'unity_WorldToObject' // Upgrade NOTE: replaced '_Object2World' with 'unity_ObjectToWorld' // Upgrade NOTE: replaced '_World2Object' with 'unity_WorldToObject' Shader "Custom/Chapter6-SpecularVertexLevel" { Properties{ _Diffuse("Diffuse",Color) = (1,1,1,1) _Specular("Specular",Color)=(1,1,1,1) //高光颜色 _Gloss("Gloss",Range(8.0,256)) = 20//高光区域大小 } SubShader{ Pass{ Tags{"LightMode" = "ForwardBase"} CGPROGRAM #pragma vertex vert #pragma fragment frag #include "Lighting.cginc" fixed4 _Diffuse; fixed4 _Specular; float _Gloss; struct a2v{ float4 vertex:POSITION;//顶点信息 float3 normal:NORMAL; }; struct v2f{ float4 pos:SV_POSITION;//裁剪空间信息 fixed3 worldNormal:TEXCOORD0; fixed3 worldPos:TEXCOORD1; }; v2f vert(a2v v){ v2f o; o.pos = UnityObjectToClipPos(v.vertex);//将模型空间坐标转化为裁剪空间 o.worldNormal = mul(v.normal,(float3x3)unity_WorldToObject); //o.worldNormal = UnityObjectToWorldNormal(v.normal); o.worldPos = mul(unity_ObjectToWorld,v.vertex); return o; } fixed4 frag(v2f i):SV_Target{ //获得环境光 fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz; fixed3 worldNormal = normalize(i.worldNormal); fixed3 worldLightDir = normalize(_WorldSpaceLightPos0).xyz; //fixed3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos)); fixed3 diffuse = _Diffuse.rgb*_LightColor0*saturate(dot(worldNormal,worldLightDir)); //_LightColor0为内置变量 :表示光色及强度 //计算反射方向 fixed3 reflectDir = normalize(reflect(-worldLightDir,worldNormal)); //计算视角方向 fixed3 viewDir = normalize(_WorldSpaceCameraPos.xyz-i.worldPos.xyz); //fixed3 viewDir = normalize(UnityWorldSpaceViewDir(i.worldPos)); //计算B-P模型新矢量 fixed3 halfDir = normalize(worldLightDir+viewDir); //计算高光反射 fixed3 specular = _LightColor0*_Specular.rgb*pow(max(0,dot(reflectDir,halfDir)),_Gloss); return fixed4(ambient+diffuse+specular,1.0); } ENDCG } } FallBack "Specular" }
一般来说B-P模型高光反射部分更大更亮,而在实际渲染中我们也常选择这个模型。但是注意的是,此为经验模型。

从左到右依次是B-P模型,逐像素,逐顶点的渲染情况。
= (
·
)

浙公网安备 33010602011771号