Blinn-Phong高光模型的公式:
Specular = 直射光 * pow(cosθ,高光的参数)
θ是法线和x的夹角
x是平行光和视野方向的平分线
shader代码
Shader "Custom/MySpecularShader-Blinn-Phong"
{
Properties
{
_Diffuse("Diffuse color",Color) = (1,1,1,1)
_Gloss("Gloss",Range(8,200)) = 10
_Specular("Specular",Color) = (1,1,1,1)
}
SubShader
{
pass
{
Tags { "LightMode"="ForwardBase" }
CGPROGRAM
#include "Lighting.cginc"
#pragma vertex vert
#pragma fragment frag
fixed4 _Diffuse;
half _Gloss;
fixed3 _Specular;
struct a2v
{
float4 vertex:POSITION;
float3 normal:NORMAL;
};
struct v2f
{
float4 pos:SV_POSITION;
fixed3 worldNormalDir:color;
};
v2f vert(a2v i)
{
v2f o;
o.pos = UnityObjectToClipPos(i.vertex);//UnityObjectToClipPos(i.vertex);
o.worldNormalDir = mul(i.normal,(float3x3)unity_WorldToObject);
// o.color = tempColor;
return o;
}
float4 frag(v2f i):SV_TARGET
{
//fixed3 worldNormalDir = mul(i.normal,(float3x3)unity_WorldToObject);
fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.rgb;//获取环境光
fixed3 normalDir = normalize(i.worldNormalDir); //这个矩阵把一个方向从世界空间转换到模型空间 这样放在后面就是模型到世界了
fixed3 lightDir = normalize(_WorldSpaceLightPos0.xyz);//对于每个顶点来说光的位置就是光的方向,因为光是平行的。
fixed3 halfLambert = dot(normalDir,lightDir) * 0.5 + 0.5; //半兰伯特光照公式 max(dot(normalDir,lightDir),0);
fixed3 diffuse = _LightColor0.rgb * halfLambert * _Diffuse;//取得漫反射的颜色
//fixed3 reflectDir = normalize(reflect(-lightDir,normalDir));//反射光方向
fixed3 viewDir = normalize(_WorldSpaceCameraPos.xyz - i.pos.xyz);//视野方向
fixed3 halfDir = normalize(viewDir + lightDir);
fixed3 specular = _LightColor0.rgb * _Specular * pow(max(dot(normalDir, halfDir) , 0) , _Gloss);
fixed3 tempColor = diffuse + ambient + specular;
return fixed4(tempColor,1);
}
ENDCG
}
}
FallBack "Diffuse"
}
效果会比之前的好一点背光处的异常也没了
在后续发现高光位置和现实中不符合发现一个bug原因如下:
我在计算相机位置的时候把 点在剪裁空间下的坐标代入计算了,
实际上应该把点从模型空间下转成世界空间下再代入计算。
完整代码如下:
// Upgrade NOTE: replaced '_Object2World' with 'unity_ObjectToWorld'
Shader "Custom/MySpecularShader-Blinn-Phong"
{
Properties
{
_Diffuse("Diffuse color",Color) = (1,1,1,1)
_Gloss("Gloss",Range(8,200)) = 10
_Specular("Specular",Color) = (1,1,1,1)
}
SubShader
{
pass
{
Tags { "LightMode"="ForwardBase" }
CGPROGRAM
#include "Lighting.cginc"
#pragma vertex vert
#pragma fragment frag
fixed4 _Diffuse;
half _Gloss;
fixed3 _Specular;
struct a2v
{
float4 vertex:POSITION;
float3 normal:NORMAL;
};
struct v2f
{
float4 pos:SV_POSITION;
fixed3 worldNormalDir:color;
float4 worldVert:TEXCOORD1;
};
v2f vert(a2v i)
{
v2f o;
o.pos = UnityObjectToClipPos(i.vertex);//UnityObjectToClipPos(i.vertex);
o.worldNormalDir = mul(i.normal,(float3x3)unity_WorldToObject);
o.worldVert = mul(unity_ObjectToWorld, i.vertex);
// o.color = tempColor;
return o;
}
float4 frag(v2f i):SV_TARGET
{
//fixed3 worldNormalDir = mul(i.normal,(float3x3)unity_WorldToObject);
fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.rgb;//获取环境光
fixed3 normalDir = normalize(i.worldNormalDir); //这个矩阵把一个方向从世界空间转换到模型空间 这样放在后面就是模型到世界了
fixed3 lightDir = normalize(_WorldSpaceLightPos0.xyz);//对于每个顶点来说光的位置就是光的方向,因为光是平行的。
fixed3 halfLambert = dot(normalDir,lightDir) * 0.5 + 0.5; //半兰伯特光照公式 max(dot(normalDir,lightDir),0);
fixed3 diffuse = _LightColor0.rgb * halfLambert * _Diffuse;//取得漫反射的颜色
//fixed3 reflectDir = normalize(reflect(-lightDir,normalDir));//反射光方向
fixed3 viewDir = normalize(_WorldSpaceCameraPos.xyz - i.worldVert.xyz);//视野方向
fixed3 halfDir = normalize(viewDir + lightDir);
fixed3 specular = _LightColor0.rgb * _Specular * pow(max(dot(normalDir, halfDir) , 0) , _Gloss);
fixed3 tempColor = diffuse + ambient + specular;
return fixed4(tempColor,1);
}
ENDCG
}
}
FallBack "Diffuse"
}
效果如下: