光照理论与光照模型
详细的光照理论和光照模型在我另一篇文章中有比较详细的阐释,这里就不再赘述。
详见:3D游戏与计算机图形学中的数学方法读书笔记–第七章–光照部分
在这里我做几点简要补充:
-
光源与物体表面相交只会有两个结果:散射与吸收。散射到物体内部的现象被称为折射或散射,而散射到物体外部的现象称为反射;其余部分则被吸收。散射不改变光线密度和颜色,只会改变方向;而吸收不改变方向,只会改变密度和颜色。
-
计算机图形学第一定律:如果它看起来是对的,那么它就是对的。
-
漫反射兰伯特定律计算如下: c d i f f u s e = ( c l i g h t ⋅ m d i f f u s e ) m a x ( 0 , n ^ ⋅ l ^ ) c_{diffuse}=(c_{light}\cdot m_{diffuse})max(0,\hat n\cdot \hat l ) cdiffuse=(clight⋅mdiffuse)max(0,n^⋅l^)
-
高光反射计算
- Phong模型:
r
^
=
2
(
n
^
⋅
l
^
)
n
^
−
l
^
\hat r=2(\hat n\cdot \hat l)\hat n-\hat l
r^=2(n^⋅l^)n^−l^
c s p e c u l a r = ( c l i g h t ⋅ m s p e c u l a r ) m a x ( 0 , v ^ ⋅ r ^ ) m g l a s s c_{specular}=(c_{light}\cdot m_{specular})max(0,\hat v\cdot \hat r)^{m_{glass}} cspecular=(clight⋅mspecular)max(0,v^⋅r^)mglass - Blinn-Phong模型:
h
^
=
v
^
+
l
^
∣
v
^
+
l
^
∣
\hat h=\frac {\hat v+\hat l}{|\hat v+\hat l|}
h^=∣v^+l^∣v^+l^
c s p e c u l a r = ( c l i g h t ⋅ m s p e c u l a r ) m a x ( 0 , n ^ ⋅ h ^ ) m g l a s s c_{specular}=(c_{light}\cdot m_{specular})max(0,\hat n\cdot \hat h)^{m_{glass}} cspecular=(clight⋅mspecular)max(0,n^⋅h^)mglass
- Phong模型:
r
^
=
2
(
n
^
⋅
l
^
)
n
^
−
l
^
\hat r=2(\hat n\cdot \hat l)\hat n-\hat l
r^=2(n^⋅l^)n^−l^
相关案例与详细代码
-
漫反射案例
- 逐顶点漫反射光照
Shader "Unity Shaders Book/Chapter 6/Diffuse Vertex-Level"{ Properties{ _Diffuse("Diffuse",color) = (1,1,1,1) } SubShader{ Pass{ Tags{"LightMode" = "ForwardBase"}//设置前向渲染 CGPROGRAM #pragma vertex vert #pragma fragment frag #include "Lighting.cginc" fixed4 _Diffuse; 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 worldLight=normalize(_WorldSpaceLightPos0.xyz); fixed3 diffuse=_LightColor0.rgb*_Diffuse.rgb*saturate(dot(worldNormal,worldLight)); o.color=ambient+diffuse; return o; } fixed4 frag(v2f i):SV_Target{ return fixed4(i.color,1.0); } ENDCG } } Fallback "Diffuse" }
- 逐像素漫反射光照
Shader "Unity Shaders Book/Chapter 6/Diffuse Pixel-Level"{ Properties{ _Diffuse("Diffuse",color) = (1,1,1,1) } SubShader{ Pass{ Tags{"LightMode" = "ForwardBase"} CGPROGRAM #pragma vertex vert #pragma fragment frag #include "Lighting.cginc" fixed4 _Diffuse; struct a2v{ float4 vertex:POSITION; float3 normal:NORMAL; }; struct v2f{ float4 pos:SV_POSITION; fixed3 worldNormal:TEXCOORD0; }; v2f vert(a2v v){ v2f o; o.pos=UnityObjectToClipPos(v.vertex); o.worldNormal=mul(v.normal,(float3x3)unity_WorldToObject); 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 diffuse=_LightColor0.rgb*_Diffuse.rgb*saturate(dot(worldNormal,worldLightDir)); fixed3 color=ambient+diffuse; return fixed4(color,1.0); } ENDCG } } Fallback "Diffuse" }
- 半兰伯特光照模型(通过改变点积结果范围,使背光面也可以有一定变化)
Shader "Unity Shaders Book/Chapter 6/Diffuse Half_Lambert"{ Properties{ _Diffuse("Diffuse",color) = (1,1,1,1) } SubShader{ Pass{ Tags{"LightMode" = "ForwardBase"} CGPROGRAM #pragma vertex vert #pragma fragment frag #include "Lighting.cginc" fixed4 _Diffuse; struct a2v{ float4 vertex:POSITION; float3 normal:NORMAL; }; struct v2f{ float4 pos:SV_POSITION; fixed3 worldNormal:TEXCOORD0; }; v2f vert(a2v v){ v2f o; o.pos=UnityObjectToClipPos(v.vertex); o.worldNormal=mul(v.normal,(float3x3)unity_WorldToObject); return o; } fixed4 frag(v2f i):SV_Target{ fixed3 ambient=UNITY_LIGHTMODEL_AMBIENT.xyz; fixed3 worldNormal=normalize(i.worldNormal); fixed3 worldLightDir=normalize(_WorldSpaceLightPos0.xyz); fixed halfLambert=dot(worldLightDir,worldNormal)*0.5+0.5; fixed3 diffuse=_LightColor0.rgb*_Diffuse.rgb*halfLambert; fixed3 color=ambient+diffuse; return fixed4(color,1.0); } ENDCG } } Fallback "Diffuse" }
- 以上三个shader的效果如下:
-
高光反射案例
- 逐顶点高光反射
Shader "Unity Shaders Book/Chapter 6/Specular Vertex-Level"{ 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=_LightColor0.rgb*_Diffuse.rgb*saturate(dot(worldNormal,worldLightDir)); fixed3 reflectDir=normalize(reflect(-worldLightDir,worldNormal)); fixed3 viewDir=normalize(_WorldSpaceCameraPos.xyz-mul(unity_ObjectToWorld,v.vertex).xyz); fixed3 specular=_LightColor0.rgb*_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" }
- 逐像素高光反射
Shader "Unity Shaders Book/Chapter 6/Specular Pixel-Level"{ 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);//pos is the type of float4 while worldPos is float3,so worldPos have the extra .xyz o.worldNormal=mul(v.normal,(float3x3)unity_WorldToObject); o.worldPos=mul(v.vertex,(float3x3)unity_WorldToObject).xyz; 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 diffuse=_LightColor0.rgb*_Diffuse.rgb*saturate(dot(worldLightDir,worldNormal)); 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-Phong光照模型
Shader "Unity Shaders Book/Chapter 6/Specular BlinnPhong"{ 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);//pos is the type of float4 while worldPos is float3,so worldPos have the extra .xyz o.worldNormal=mul(v.normal,(float3x3)unity_WorldToObject); o.worldPos=mul(v.vertex,(float3x3)unity_WorldToObject).xyz; 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 diffuse=_LightColor0.rgb*_Diffuse.rgb*saturate(dot(worldLightDir,worldNormal)); fixed3 viewDir=normalize(_WorldSpaceCameraPos.xyz-i.worldPos.xyz); fixed3 newDir=normalize(viewDir+worldLightDir); fixed3 specular=_LightColor0.rgb*_Specular.rgb*pow(saturate(dot(newDir,worldNormal)),_Gloss); return fixed4(ambient+diffuse+specular,1.0); } ENDCG } } Fallback "Specular" }
- 则上述三个shader效果如下: