在Unity Shader中使用Phong-Blinn高光反射模型来优化高光反射。
对于Phong高光反射模型可以查看之前写的这篇文章
在Blinn模型中,引入了一个新的矢量 h,它是通过对视角方向 v 和光照方向 I相加后再归一化得到的值。
从代码上来看,Phong-Blinn更像是 Phong的逐像素高光反射的变种。因为进改变了其在片元着色器的部分代码。
完整代码如下:
// Upgrade NOTE: replaced '_Object2World' with 'unity_ObjectToWorld'
// Upgrade NOTE: replaced '_Object2World' with 'unity_ObjectToWorld'
Shader "LeonShader/shader_6_5_HighLight_Phong-Blinn"{
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 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 Shader】(4)Blinn-Phong 高光反射模型 实现 高光反射效果》已经结束了!
写这么多居然会被影响推荐。一下内容已经在上一节提到过,看过的可以直接无视掉。我们在这里复习一遍:
Phong高光反射模型
Phong高光反射模型 共有4个参数
- 入射光线的颜色和强度—— C light
- 材质的漫反射系数—— M specular
- 视线向量—— v
- 反射方向—— r
为了避免 v 和 r 的点积为负值,我们需要使用max来操作。但在Unity Shader中,我们可以使用 saturate(x)
函数达到相同的效果。
其中的 r
可以直接使用如下公式计算:
在计算 r 的过程中,可以直接使用CG给我们封装好的reflect( i,n )
其中,i
为入射方向;n
为放线方向。reflect可以直接得到反射方向。