歡迎加入Unity業內qq交流羣:956187480
qq掃描二維碼加羣
基本光照模型中高光反射部分的計算模型:
計算高光反射我們需要知道四個參數:入射光線的顏色跟強度,材質的高光反射係數,視角方向v以及反射方向r。
其中反射方向r可以由表面法線n和光源方向l計算:,此公式我們可以用函數reflect(i,n),i入射方向跟n法線方向
一.逐頂點高光反射,高光部分明顯不平滑,因爲高光反射部分的計算是非線性的,而頂點着色器計算光照再進行插值的過程是線性的,破壞了原計算的非線性關係就出現了視覺問題。
// Upgrade NOTE: replaced '_World2Object' with 'unity_WorldToObject'
Shader "a幻世界/SpecularVertex"
{
Properties
{
_Diffuse ("Diffuse", Color) = (1, 1, 1, 1) //漫反射顏色
_Specular ("Specular", Color) = (1, 1, 1, 1) //控制高光的反射顏色
_Gloss ("Gloss", Range(8, 256)) = 20 //控制高光範圍
}
SubShader
{
Pass{
Tags { "RenderType" = "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 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-UnityObjectToClipPos(v.vertex));//相機的世界座標-頂點轉換到世界空間=世界空間下的視角方向
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);
}
ENDCG
}
}
FallBack "Specular"
}
二.逐像素高光反射,按照逐像素處理我們就能得到更加平滑的高光效果
// Upgrade NOTE: replaced '_Object2World' with 'unity_ObjectToWorld'
Shader "a幻世界/SpecularPixel"
{
Properties
{
_Diffuse("Diffuse", Color) = (1, 1, 1, 1) //漫反射顏色
_Specular("Specular", Color) = (1, 1, 1, 1) //控制高光的反射顏色
_Gloss("Gloss", Range(8, 256)) = 20 //控制高光範圍
}
SubShader
{
Pass{
Tags { "RenderType" = "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);//模型空間頂點轉換到裁剪空間
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 ambienm = UNITY_LIGHTMODEL_AMBIENT.xyz;
fixed3 worldNormal = normalize(i.worldNormal);
fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz);
fixed3 diffuse = _LightColor0.rbg*_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.rbg*pow(saturate(dot(reflectDir, viewDir ) ),_Gloss);
return fixed4(ambienm+diffuse+specular,1);
}
ENDCG
}
}
FallBack "Specular"
}
三.Blinn-Phong光照模型,高光反射部分看起來更大更亮一些。而具體在實際渲染中選擇哪一種我們要視情況而定
Shader "a幻世界/SpecularBlinnPhong"
{
Properties
{
_Diffuse("Diffuse", Color) = (1, 1, 1, 1) //漫反射顏色
_Specular("Specular", Color) = (1, 1, 1, 1) //控制高光的反射顏色
_Gloss("Gloss", Range(8, 256)) = 20 //控制高光範圍
}
SubShader
{
Pass{
Tags { "RenderType" = "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);//模型空間頂點轉換到裁剪空間
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 ambienm = UNITY_LIGHTMODEL_AMBIENT.xyz;
fixed3 worldNormal = normalize(i.worldNormal);
fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz);
fixed3 diffuse = _LightColor0.rbg*_Diffuse.rgb*saturate(dot(worldLightDir, worldNormal));
fixed3 reflectDir = normalize(reflect(-worldLightDir,worldNormal));
fixed3 viewDir = normalize(_WorldSpaceCameraPos.xyz - i.worldPos.xyz);
fixed3 halfDir = normalize(worldLightDir+viewDir);
fixed3 specular = _LightColor0.rgb*_Specular.rbg*pow(max(0,dot(worldNormal, halfDir)),_Gloss);
return fixed4(ambienm + diffuse + specular,1);
}
ENDCG
}
}
FallBack "Specular"
}
四.使用Unity內置函數來寫shader以上面的模型爲例
Shader "a幻世界/SpecularBlinnPhongUseBuildInunction"
{
Properties
{
_Diffuse("Diffuse", Color) = (1, 1, 1, 1) //漫反射顏色
_Specular("Specular", Color) = (1, 1, 1, 1) //控制高光的反射顏色
_Gloss("Gloss", Range(8, 256)) = 20 //控制高光範圍
}
SubShader
{
Pass{
Tags { "RenderType" = "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);//模型空間頂點轉換到裁剪空間
o.worldNormal = UnityObjectToWorldNormal(v.normal);
o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;
return o;
}
fixed4 frag(v2f i) :SV_Target {
fixed3 ambienm = UNITY_LIGHTMODEL_AMBIENT.xyz;
fixed3 worldNormal = normalize(i.worldNormal);
fixed3 worldLightDir = normalize( UnityWorldSpaceLightDir(i.worldPos));
fixed3 diffuse = _LightColor0.rbg*_Diffuse.rgb*saturate(dot(worldLightDir, worldNormal));
fixed3 reflectDir = normalize(reflect(-worldLightDir,worldNormal));
fixed3 viewDir = normalize(UnityWorldSpaceViewDir(i.worldPos));
fixed3 halfDir = normalize(worldLightDir + viewDir);
fixed3 specular = _LightColor0.rgb*_Specular.rbg*pow(max(0,dot(worldNormal, halfDir)),_Gloss);
return fixed4(ambienm + diffuse + specular,1);
}
ENDCG
}
}
FallBack "Diffuse"
}
歡迎加入Unity業內qq交流羣:956187480
qq掃描二維碼加羣