unity,选择默认渲染管线
效果图:
原理:
通过副切线和对半方向(即视线方向+光照方向)进行点乘计算高光,从而代替blinn-Phong中法线和对半方向的点乘
代码:
Properties
{
_MainTex("MainTex", 2D) = "white"{}
_SpecularTex("_SpecularTex", 2D) = "black"{}
_exp("Exp", Range(0.0, 20.0)) = 1.0
_scale("HightLightScale", Range(0.5, 5.0)) = 1.0
_shiftControl("shiftControl", Range(-1.0, 1.0)) = 0.0
_SpecularCol("SpecularCol", color) = (1.0, 1.0, 1.0, 1.0)
}
SubShader
{
Tags { "RenderType"="Opaque" }
Cull Off
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
uniform sampler2D _MainTex;
uniform sampler2D _SpecularTex;
uniform float _exp;
uniform float _scale;
uniform float _shiftControl;
uniform float3 _SpecularCol;
struct VertexInput
{
float4 vertex : POSITION;
float4 tangent : TANGENT;
float4 normal : NORMAL;
float2 uv : TEXCOORD0;
};
struct VertexOutput
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
float3 posWS : TEXCOORD1;
float3 nDir : TEXCOORD2;
float3 tDir : TEXCOORD3;
float3 bDir : TEXCOORD4;
};
VertexOutput vert (VertexInput v)
{
VertexOutput o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.posWS = mul(unity_ObjectToWorld, v.vertex);
o.nDir = UnityObjectToWorldNormal(v.normal);
o.tDir = UnityObjectToWorldDir(v.tangent.xyz);
o.bDir = cross(o.tDir, o.nDir);
o.uv = v.uv;
return o;
}
fixed4 frag (VertexOutput i) : SV_Target
{
//mainTex
float3 var_MainTex = tex2D(_MainTex, i.uv);
//数据准备
float3 lDir = _WorldSpaceLightPos0.xyz;
float3 vDir = _WorldSpaceCameraPos.xyz - i.posWS;
float3 nDir = i.nDir;
float3 tDir = i.tDir;
float3 bDir = i.bDir;
float3 hDir = normalize(lDir + vDir);
//偏移bDir
float var_SpecularTex = tex2D(_SpecularTex, i.uv) - 0.5; //控制高光以及偏移量
bDir = normalize(bDir + (var_SpecularTex + _shiftControl) * nDir); //偏移后的结果
//点积准备
float ndotl = dot(nDir, lDir);
float bdoth = dot(bDir, hDir);
//光照模型
//half-Lambert
float diffusion = ndotl * 0.5 + 0.5;
//Kajiya-Kay
float sinBH = sqrt(1 - bdoth * bdoth);
float dirAtten = smoothstep(-1.0, 0.0, bdoth); //控制衰减
float3 specular = dirAtten * pow(sinBH, _exp) * 0.3 * _SpecularCol;
//返回最终值
float finalLight = diffusion + specular;
float3 finalCol = var_MainTex * diffusion + specular;
return float4(finalCol, 1.0);
}
ENDCG
}
}