高光反射计算公式(phong模型)Cspecular=(Clight*Mspecular)max(0,v*r)mgloss
mgloss为材质的官泽度,也成反射度,控制高光区域亮点有多大
Mspecular是材质的高光反射颜色,控制材质对于高光反射的轻度和颜色
Clight为光源的颜色和强度
v是观察方向的单位向量
r是反射方向 r=2(法线单位向量n*光源方向向量)法线单位向量-光源方向向量
高光反射计算公式(Blinn模型)Cspecular=(Clight*Mspecular)max(0,n*h)mgloss
n为法线向量的单位向量
h是对观察方向和光源方向取平均后归一化得到的:h(注:单位向量)=(v(注:单位向量)+光源方向)/|(v(注:单位向量)+光源方向)|
下面分别是逐顶点和逐像素两种写法
phong模型 逐顶点:
Shader "study/Chapter6/halfLambertShader" { 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; fixed4 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(UnityObjectToWorldNormal(v.normal);); fixed3 worldNormal=normalize(mul(v.normal,(float3x3)unity_WorldToObject)); fixed3 worldLightDir=normalize(_WorldSpaceLightPos0.xyz); fixed3 diffuse=_LightColor0.rgb*_Diffuse.rgb*saturate(dot(worldNormal,worldLightDir)); //反射方向get the reflect direction in world space fixed3 reflectDir=normalize(reflect(-worldLightDir,worldNormal)); //get the view direction in world space //世界空间下观察方向 fixed3 viewDir=normalize(_WorldSpaceCameraPos.xyz-mul(unity_ObjectToWorld,v.vertex).xyz); //Computer specular term fixed3 specular = _LightColor0.rgb*_Specular.rgb*pow(saturate(dot(reflectDir,viewDir)),_Gloss); o.color=diffuse+ambient+specular; return o; } fixed4 frag(v2f i):SV_Target{ return fixed4(i.color,1.0); } ENDCG } } FallBack "Specular" }
phong模型 逐像素:
Shader "study/Chapter6/SpecularPixelLevelShader" { 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{ fixed4 vertex:POSITION; fixed3 normal:NORMAL; }; struct v2f{ fixed4 pos:SV_POSITION; float3 worldNormal:TEXCOORD0; float3 worldPos:TEXCOORD1; }; v2f vert(a2v v){ v2f o; o.pos = UnityObjectToClipPos(v.vertex); //使用内置函数写法 //o.worldNormal = UnityObjectToWorldNormal(v.normal); o.worldNormal=mul(v.normal,(float3x3)unity_WorldToObject); o.worldPos=mul(unity_ObjectToWorld,v.vertex).xyz; return o; } fixed4 frag(v2f i): SV_Target{ //环境光、自发光部分 fixed3 ambient=UNITY_LIGHTMODEL_AMBIENT.xyz; //世界空间下法线单位矢量 fixed3 worldNormal=normalize(i.worldNormal); //世界空间下光源方向单位矢量 fixed3 worldLightDir=normalize(_WorldSpaceCameraPos.xyz); //漫反射部分 fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * saturate(dot(worldNormal,worldLightDir)); //世界空间下反射光矢量 fixed3 reflectDir=normalize(reflect(-worldLightDir,worldNormal)); //视野方向 fixed3 viewDir=normalize(_WorldSpaceCameraPos.xyz-i.worldPos.xyz); //高光 fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(saturate(dot(reflectDir,viewDir)),_Gloss); //最终观察到的光照 return fixed4(ambient+diffuse+specular,1.0); } ENDCG } } FallBack "Specular" }
Blinn模型逐像素
Shader "study/Chapter6/BlinnPhongShader" { 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; float3 worldNormal : TEXCOORD0; float3 worldPos : TEXCOORD1; }; v2f vert(a2v v){ v2f o; o.pos=UnityObjectToClipPos(v.vertex); o.worldNormal=mul(v.normal,(float3x3)unity_WorldToObject); o.worldPos=mul(unity_ObjectToWorld,v.vertex).xyz; return o; } fixed4 frag(v2f i):SV_Target{ float3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz; fixed3 worldNormal = normalize(i.worldNormal); //内置函数写法 //float3 worldLightDir=normalize(UnityWorldSpaceLightDir(i.worldPos)); fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz); fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * max(0,dot(worldNormal, worldLightDir)); //内置函数写法 //fixed3 viewDir=normalize(UnityWorldSpaceViewDir(i.worldNormal)); fixed3 viewDir=normalize(_WorldSpaceCameraPos.xyz-i.worldPos.xyz); fixed3 halfDir=normalize(worldLightDir + viewDir); fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(max(0, dot(worldNormal, halfDir)), _Gloss); return fixed4(ambient+diffuse+specular,1.0); } ENDCG } } FallBack "Specular" }
unity的内置函数
仅用于前向渲染的只有在渲染模式为前向渲染时(“LightMode”=“ForwordBase”或者"LightMode"="ForwordAdd")
这三个函数里的内置变量——WorldSpaceLightPos0等才能被正确赋值。
注:这一篇以及之前漫反射都是单一平行光源下计算的,查看效果时,去掉天空盒,设置方法为window->Lighting->skybox