# 【Shader练习-妲己】
游戏《王者荣耀》里的英雄“妲己”的渲染效果实现。
包括了以下练习内容:
Shader "Vp/DajiShader" {
Properties {
[NoScaleOffset]_DiffuseTex("Diffuse(RGB)", 2D) = "white" {}
[NoScaleOffset]_NormalTex("Normal", 2D) = "bump" {}
[NoScaleOffset]_SpecularTex("Specular", 2D) = "black" {}
[NoScaleOffset]_GlossTex("Gloss", 2D) = "black" {}
[NoScaleOffset]_AOTex("环境遮蔽", 2D) = "white" {}
[NoScaleOffset]_SkinMaskTex("皮肤遮罩", 2D) = "white" {}
_SkinColor("SkinColor", Color) = (1, 1, 1, 1)
_SkinColorIns("SkinColorIns", Range(0, 1)) = 0.1
_Ambient("Ambient", Color) = (0.3, 0.3, 0.3, 1)
_AmbientBorder("AmbientBorder", Range(0.01, 1)) = 0.3
_AmbientBlur("AmbientBlur", Range(0, 0.5)) = 0.1
_SpecularPow("SpecularPow", Range(0, 100)) = 8
_FresnelPow("FresnelPow", Range(0, 100)) = 8
_FresnelIns("FresnelIns", Range(0, 1)) = 0.5
_Cubemap ("RGB:环境球贴图", cube) = "_Skybox" {}
_CubemapMip ( "环境球Mip" , Range(0,7)) = 0
}
SubShader {
Tags {
"RenderType"="Opaque"
}
Pass {
Name "FORWARD"
Tags {
"LightMode"="ForwardBase"
}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
#include "AutoLight.cginc"// 用于阴影
#include "Lighting.cginc"// 用于阴影
#pragma multi_compile_fwdbase_fullshadows
#pragma target 3.0
uniform sampler2D _DiffuseTex;
uniform sampler2D _NormalTex;
uniform half4 _Ambient;
uniform float _AmbientBorder;
uniform float _AmbientBlur;
uniform sampler2D _SpecularTex;
uniform sampler2D _GlossTex;
uniform float _SpecularPow;
uniform sampler2D _AOTex;
uniform sampler2D _SkinMaskTex;
uniform float4 _SkinColor;
uniform float _SkinColorIns;
uniform float _FresnelPow;
uniform float _FresnelIns;
samplerCUBE _Cubemap;
uniform float _CubemapMip;
/** 具有阴影和非阴影交汇的卡通漫反射 */
half4 toondiffuse(float2 uv,float3 normal, float3 lightDir)
{
// 环境遮蔽
half4 var_AOTex = tex2D(_AOTex,uv);
half ao = var_AOTex.r;
// 皮肤
half4 var_SkinMaskTex = tex2D(_SkinMaskTex,uv);
half4 SkinCol = var_SkinMaskTex.r * _SkinColor;
// 光照模型漫反射颜色
float ndl = max(0, dot(normal, lightDir)) * ao;
float td = smoothstep(_AmbientBorder - _AmbientBlur, _AmbientBorder + _AmbientBlur, ndl);
half4 var_DiffuseTex = tex2D(_DiffuseTex,uv) + SkinCol * _SkinColorIns;
half4 a = _Ambient * var_DiffuseTex;// 环境光+漫反射
half4 rd = lerp(a, var_DiffuseTex, td);// 环境光与漫反射进行边缘混合
return rd;
}
struct VertexInput {
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
float3 normal : NORMAL;
float4 tangent : TANGENT;
};
struct VertexOutput {
float4 pos : SV_POSITION;
float2 uv : TEXCOORD0;
float3 normal : TEXCOORD1;
float3 tangent : TEXCOORD2;
float3 btangent : TEXCOORD3;
float3 posWS : TEXCOORD4;
LIGHTING_COORDS(5,6)// 用于阴影
};
VertexOutput vert (VertexInput v) {
VertexOutput o = (VertexOutput)0;
o.pos = UnityObjectToClipPos( v.vertex );
TRANSFER_VERTEX_TO_FRAGMENT(o)// 用于阴影
o.uv = v.uv;
o.normal = UnityObjectToWorldNormal(v.normal);
o.tangent = normalize(mul(unity_ObjectToWorld,float4(v.tangent.xyz,0.0)).xyz);
o.btangent = normalize(cross(o.normal,o.tangent) * v.tangent.w);
o.posWS = mul(unity_ObjectToWorld,v.vertex).xyz;
return o;
}
half4 frag(VertexOutput i) : COLOR {
// 采样纹理准备
float3 nDirTS = UnpackNormal(tex2D(_NormalTex, i.uv));
half4 var_SpecularTex = tex2D(_SpecularTex,i.uv);
half4 var_GlossTex = tex2D(_GlossTex,i.uv);
float attenuation = LIGHT_ATTENUATION(i);// 用于阴影
// 法线贴图的法线
float3x3 TBN = float3x3(
i.tangent.x,i.tangent.y,i.tangent.z,
i.btangent.x,i.btangent.y,i.btangent.z,
i.normal.x,i.normal.y,i.normal.z
);
float3 tex_normal = normalize(mul(nDirTS,TBN));
// 向量准备
float3 vDirWS = normalize(_WorldSpaceCameraPos.xyz - i.posWS.xyz);
float3 lDirWS = normalize(_WorldSpaceLightPos0.xyz);
float3 rDirWS = reflect(-lDirWS, tex_normal);
float3 vrDirWS = reflect(-vDirWS, tex_normal);
// 环境球
float3 var_CubemapSpecular = texCUBElod(_Cubemap, float4(vrDirWS, lerp(_CubemapMip, 0.0, var_SpecularTex.r))).rgb;
// 漫反射
half4 difCol = toondiffuse(i.uv,tex_normal,lDirWS);
// 镜面反射
float vdotr = dot(vDirWS, rDirWS);
float phong = pow(max(0.0, vdotr),_SpecularPow) * var_GlossTex.r;
half3 phongCubemap = var_CubemapSpecular * phong * max(var_SpecularTex.r , var_GlossTex.r);
phongCubemap = phongCubemap * 5;
// 菲涅尔反射(非金属部分都具有菲涅尔反射)
float nDotv = 1-max(0,dot(tex_normal,vDirWS));
float fresnel = pow(nDotv,_FresnelPow) * (1-var_SpecularTex.r) * _FresnelIns;
// 返回(漫反射+光高模型)*阴影
return (difCol + half4(phongCubemap,1.0) + fresnel) * attenuation;
}
ENDCG
}
}
FallBack "Diffuse"
}