高光反射的公式:
Specular = 直射光 * pow(cosθ,高光的参数) θ是反射光方向和视野方向的夹角
由图像看出高光参数可控制光的可视范围
- 逐顶点的高光反射
// Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'
Shader "Custom/MySpecularShader-Vert"
{
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 color:color;
};
v2f vert(a2v i)
{
v2f o;
o.pos = UnityObjectToClipPos(i.vertex);//UnityObjectToClipPos(i.vertex);
fixed3 worldNormalDir = mul(i.normal,(float3x3)unity_WorldToObject);
fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.rgb;//获取环境光
fixed3 normalDir = normalize(worldNormalDir); //这个矩阵把一个方向从世界空间转换到模型空间 这样放在后面就是模型到世界了
fixed3 lightDir = normalize(_WorldSpaceLightPos0.xyz);//对于每个顶点来说光的位置就是光的方向,因为光是平行的。
fixed3 halfLambert = max(dot(normalDir,lightDir),0);//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 - o.pos.xyz);//视野方向
fixed3 specular = _LightColor0.rgb * _Specular * pow(max(dot(reflectDir, viewDir) , 0) , _Gloss);
fixed3 tempColor = diffuse + ambient + specular;
o.color = tempColor;
return o;
}
float4 frag(v2f i):SV_TARGET
{
return fixed4(i.color,1);
}
ENDCG
}
}
FallBack "Diffuse"
}
- 逐像素的高光反射
Shader "Custom/MySpecularShader-Frag"
{
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 = max(dot(normalDir,lightDir),0);//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 specular = _LightColor0.rgb * _Specular * pow(max(dot(reflectDir, viewDir) , 0) , _Gloss);
fixed3 tempColor = diffuse + ambient + specular;
return fixed4(tempColor,1);
}
ENDCG
}
}
FallBack "Diffuse"
}
效果如下
在后续发现高光位置和现实中不符合发现一个bug原因如下:
我在计算相机位置的时候把 点在剪裁空间下的坐标代入计算了,
实际上应该把点从模型空间下转成世界空间下再代入计算。
最终代码:
// Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'
Shader "Custom/MySpecularShader-Vert"
{
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 color:color;
};
v2f vert(a2v i)
{
v2f o;
o.pos = UnityObjectToClipPos(i.vertex);//UnityObjectToClipPos(i.vertex);
fixed3 worldNormalDir = mul(i.normal,(float3x3)unity_WorldToObject);
fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.rgb;//获取环境光
fixed3 normalDir = normalize(worldNormalDir); //这个矩阵把一个方向从世界空间转换到模型空间 这样放在后面就是模型到世界了
fixed3 lightDir = normalize(_WorldSpaceLightPos0.xyz);//对于每个顶点来说光的位置就是光的方向,因为光是平行的。
fixed3 halfLambert = max(dot(normalDir,lightDir),0);//dot(normalDir,lightDir) * 0.5 + 0.5; //半兰伯特光照公式 max(dot(normalDir,lightDir),0);
fixed3 diffuse = _LightColor0.rgb * halfLambert * _Diffuse;//取得漫反射的颜色
fixed3 reflectDir = normalize(reflect(-lightDir,normalDir));//反射光方向
float4 worldVert = mul(unity_ObjectToWorld, i.vertex);
fixed3 viewDir = normalize(_WorldSpaceCameraPos.xyz - worldVert.xyz);//视野方向
fixed3 specular = _LightColor0.rgb * _Specular * pow(max(dot(reflectDir, viewDir) , 0) , _Gloss);
fixed3 tempColor = diffuse + ambient + specular;
o.color = tempColor;
return o;
}
float4 frag(v2f i):SV_TARGET
{
return fixed4(i.color,1);
}
ENDCG
}
}
FallBack "Diffuse"
}
Shader "Custom/MySpecularShader-Frag"
{
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 = max(dot(normalDir,lightDir),0);//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 specular = _LightColor0.rgb * _Specular * pow(max(dot(reflectDir, viewDir) , 0) , _Gloss);
fixed3 tempColor = diffuse + ambient + specular;
return fixed4(tempColor,1);
}
ENDCG
}
}
FallBack "Diffuse"
}
这才是正确效果: