【Unity Shader】(3)Phong光照模型 逐顶点光照 和 逐像素光照 分别实现 高光反射光照模型

使用逐顶点光照和逐像素光照分别在unityShader中实现高光反射光照模型

Phong高光反射模型
1
Phong高光反射模型 共有4个参数

  • 入射光线的颜色和强度—— C light
  • 材质的漫反射系数—— M specular
  • 视线向量—— v
  • 反射方向—— r

为了避免 v 和 r 的点积为负值,我们需要使用max来操作。但在Unity Shader中,我们可以使用 saturate(x)函数达到相同的效果。

其中的 r 可以直接使用如下公式计算:

3

2

在计算 r 的过程中,可以直接使用CG给我们封装好的reflect( i,n )

其中,i为入射方向;n为放线方向。reflect可以直接得到反射方向。



  • 逐顶点高光反射

1. 创建一个空场景(只有摄像机和平行光),删除该场景中的天空盒。

2. 新建一个材质,命名为Mat_HighLight

3. 新建一个UnityShader,命名为Sha_HighLight并将该Shader赋值给Mat_HighLight

4. 在场景中新建一个胶囊体,将Mat_HighLight赋予该物体。


5. 保存,开始编辑Shader代码:

①删除第3步新建的Shader里的默认代码。

②输入下面代码:

Shader "LeonShader/shader_6_5_HighLight_Phong"{
	Properties{
		_Diffuse("Diffuse",Color) = (1,1,1,1)
		_Specular("Specular",Color) = (1,1,1,1)
		_Gloss("Gloss",Range(8.0 , 256)) = 20
	}
	SubShader{
		Pass{
			//用于正确获取_LightColor0
			Tags { "LightMode" = "ForwardBase"}

			CGPROGRAM

			#pragma vertex vert
			#pragma fragment frag
			#include "Lighting.cginc"

			float4 _Diffuse;
			float4 _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);

				//基础底色
				fixed diffuse = _LightColor0.rgb * _Diffuse.rgb * saturate(dot(worldNormal, worldLightDir));

				//计算反射方向 r
				fixed3 reflectDir = normalize(reflect(-worldLightDir, worldNormal));
				//得到视角方向 V
				fixed3 viewDir = normalize(_WorldSpaceCameraPos.xyz - mul(unity_ObjectToWorld, v.vertex).xyz);

				//使用Phong公式 计算高光反射
				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"
}

  • 效果:

4

  • 逐像素高光反射

直接上代码:

// Upgrade NOTE: replaced '_Object2World' with 'unity_ObjectToWorld'

// Upgrade NOTE: replaced '_Object2World' with 'unity_ObjectToWorld'

Shader "LeonShader/shader_6_5_HighLight_Phong_Pixel"{
	Properties{
		_Diffuse("Diffuse",Color) = (1,1,1,1)
		_Specular("Specular",Color) = (1,1,1,1)
		_Gloss("Gloss",Range(8.0 , 256)) = 20
	}
	SubShader{
		Pass{
			//用于正确获取_LightColor0
			Tags { "LightMode" = "ForwardBase"}

			CGPROGRAM

			#pragma vertex vert
			#pragma fragment frag
			#include "Lighting.cginc"

			float4 _Diffuse;
			float4 _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{
				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 reflectDir = normalize(reflect(-worldLightDir, worldNormal));
				fixed3 viewDir = normalize(_WorldSpaceCameraPos.xyz - i.worldPos.xyz);
				fixed3 specular = _LightColor0.rgb * _Specular * pow(saturate(dot(reflectDir, viewDir)), _Gloss);



				return fixed4(ambient + diffuse + specular,1.0);
			}
			ENDCG
		}
	}
		FallBack "Specular"
}

  • 结果

5


版权声明:本文为weixin_46840974原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。