【UnityShader】高光反射光照模型
阿新 • • 發佈:2021-11-28
先給出基本光照模型中高光反射部分的計算公式:
其中要知道高光反射係數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模型,逐畫素,逐頂點的渲染情況。
= (·)