头发各项异性高光:
(1)KaJiYa的介绍:
跟KaJiYa的略有区别但是 背后原理一样,实际效果比kjy好
用一张图来说明kjy的原理:
代码中求衰减用到的函数 exp(x):
(2)代码中大体思路:
头发颜色: 直接光漫反射 + 直接光各项异性高光反射 + 间接光镜面反射;(间接光漫反射直接去掉)
间接光镜面反射相关介绍
直接光各项异性高光反射: 两层颜色,第一层粗糙颜色 第二层精细颜色。
(3)打完收工! 代码中基本都添加了注释:
Shader "Unlit/CharHair"
{
Properties
{
_BaseMap ("BaseMap", 2D) = "white" {}
_CompMask ("ComMase", 2D) = "white" {}
_NormalMap("bumpMap",2D) = "bump"{}
_SpecIntensity("_SpecIntensity",Range(0,20))= 1
_SpecShininess("_SpecShininess",Range(0,20))= 1
[Header(IBL)]
_EvnMap("cube map",Cube) = "white"{}
_Tint("tint",Color) = (1,1,1,1)
_Expose("Expose",float) = 1
_Rotate("Rotate",Range(0,360)) = 0
[Header(Aniso)]
_AnisoMap("anis",2D) = "gray"{}
_SpecColor1("specColor 1",Color) = (1,1,1,1)
_SpecShininess1("_SpecShininess 1",Range(0,1)) = 0.1
_SpecNoise1("_SpecNoise1",float) = 1
_SpecOffset1("_Specffset1",float) = 0
_SpecColor2("specColor 2",Color) = (1,1,1,1)
_SpecShininess2("_SpecShininess 2",Range(0,1)) = 0.1
_SpecNoise2("_SpecNoise 2",float) = 1
_SpecOffset2("_Specffset 2",float) = 0
_RoughnessAdjust("_RoughnessAdjust",Range(0,1)) = 1
}
SubShader
{
Tags { "RenderType"="Opaque" }
LOD 100
Pass
{
Tags{ "LightMode"="ForwardBase"}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma multi_compile_fwdbase
// 这是两种写法
#pragma shader_feature _SPECCHECK_ON
#pragma multi_compilr _ _IBLCHECK_ON
#include "UnityCG.cginc"
#include "AutoLight.cginc"
#include "Lighting.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 texcoord : TEXCOORD0;
float3 normal : NORMAL;
float4 tangent : TANGENT;
};
struct v2f
{
float2 uv : TEXCOORD0;
float4 pos : SV_POSITION;
float3 pos_world : TEXCOORD1;
float3 normal_dir : TEXCOORD2;
float3 tangent_dir : TEXCOORD3;
float3 binormal_dir : TEXCOORD4;
};
sampler2D _BaseMap;
float4 _BaseMap_ST;
sampler2D _NormalMap;
float _SpecShininess;
float4 _SpecIntensity;
float _RoughnessAdjust;
// ibl
samplerCUBE _EvnMap;
float4 _EvnMap_HDR;
float4 _Tint;
float _Expose;
// aniso
sampler2D _AnisoMap;
float4 _AnisoMap_ST;
float4 _SpecColor1;
float _SpecNoise1;
float _SpecShininess1;
float _SpecOffset1;
float4 _SpecColor2;
float _SpecNoise2;
float _SpecShininess2;
float _SpecOffset2;
v2f vert (appdata v)
{
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.texcoord, _BaseMap);
o.normal_dir = normalize(UnityObjectToWorldNormal(v.normal));
o.tangent_dir = normalize(UnityObjectToWorldDir(v.tangent.xyz));
o.binormal_dir = normalize(cross(o.normal_dir, o.tangent_dir)) * v.tangent.w;
o.pos_world = mul(unity_ObjectToWorld,v.vertex).xyz;
return o;
}
fixed4 frag (v2f i) : SV_Target
{
fixed4 base_color_ = tex2D(_BaseMap, i.uv);
fixed4 base_color = base_color_;
fixed4 spec_color = base_color_;
half roughtness = saturate(_RoughnessAdjust);
fixed3 normal_data = UnpackNormal(tex2D(_NormalMap,i.uv));
half3 light_dir = normalize(UnityWorldSpaceLightDir(i.pos_world));
half3 view_dir = normalize(UnityWorldSpaceViewDir(i.pos_world));
half3 normal_dir = normalize(i.normal_dir);
half3 tangent_dir = normalize(i.tangent_dir);
half3 binormal_dir = normalize(i.binormal_dir);
float3x3 TBN = float3x3(tangent_dir,binormal_dir,normal_dir);
normal_dir = normalize(mul(normal_data.xyz,TBN));
// Direct diffuse 直接光漫反射
//half diff_term = saturate(dot(light_dir,normal_dir));
half diff_term = dot(light_dir,normal_dir);
// 半兰伯特模型: 将【-1,1】 映射到【0,1】, 对于负数(背光面),也会右明暗变化!!!!!!
half half_lambert = (diff_term + 1) * 0.5;
half direct_diffuse = diff_term * _LightColor0.xyz * base_color.xyz;
//Direct specular 直接光 镜面反射
half2 uv_aniso = i.uv * _AnisoMap_ST.xy + _AnisoMap_ST.zw;
half aniso_noise = tex2D(_AnisoMap,uv_aniso).r - 0.5;
half3 half_dir = normalize(light_dir + view_dir);
half NdotH = saturate(dot(normal_dir,half_dir));
half TdotH = dot(tangent_dir,half_dir);
half NdotV = saturate(dot(view_dir,normal_dir));
// 求出各项异性高光的 衰减值
float aniso_atten = saturate(sqrt(saturate(half_lambert/NdotV)));
// spec1
// 加上baseColor ,有一个渐变的过渡
float3 spec_color1 = _SpecColor1.rgb + base_color;
float3 aniso_offset1 = normal_dir * (aniso_noise * _SpecNoise1 + _SpecOffset1);
binormal_dir = normalize(binormal_dir + normal_dir * aniso_offset1);
// 除以光滑度
float BdotH1 = dot(binormal_dir,half_dir)/ _SpecShininess1;
// float3 kajiya = sqrt(1 - BdotH1 * BdotH1)
float spec_term1 = exp(-(TdotH * TdotH + BdotH1 * BdotH1)/ (1+ NdotH));
float3 final_spec1 = spec_term1 * aniso_atten * spec_color1 * _LightColor0.xyz;
// spec2
float3 spec_color2 = _SpecColor2.rgb + base_color;
float3 aniso_offset2 = normal_dir * (aniso_noise * _SpecNoise2 + _SpecOffset2);
binormal_dir = normalize(binormal_dir + normal_dir * aniso_offset2);
float BdotH2 = dot(binormal_dir,half_dir)/ _SpecShininess2;
float spec_term2 = exp(-(TdotH * TdotH + BdotH2 * BdotH2)/ (1+ NdotH));
float3 final_spec2 = spec_term2 * aniso_atten * spec_color2 * _LightColor0.xyz;
// 正常的镜面反射
// half3 half_dir = normalize(light_dir + view_dir);
// half NdotH = saturate(dot(normal_dir,half_dir));
// half smoothness = 1- roughtness;
// half shininess = lerp(1,_SpecShininess,smoothness);
// half spec_term = pow(NdotH,shininess);
// half3 direct_specular = spec_term * spec_color * _LightColor0.rgb * _SpecIntensity;
// InDirect spec 间接光镜面反射
float3 reflect_dir = reflect(-view_dir,normal_dir);
roughtness = roughtness * (1.7 - 0.7 * roughtness);
float mip_level = roughtness * 6;
half4 color_cubemap = texCUBElod(_EvnMap,float4(reflect_dir,mip_level));
float3 evn_color = DecodeHDR(color_cubemap,_EvnMap_HDR);
// 用系数 乘以 金属色
half3 evn_specular = evn_color * _Expose * spec_color;
//float3 final_color = direct_diffuse + direct_specular + evn_specular;
float3 final_color = direct_diffuse + final_spec2 + final_spec1 + evn_specular;
return fixed4(final_color,1);
}
ENDCG
}
}
}
附百度云下载:链接: https://pan.baidu.com/s/1ZrnuYMV4twKCLsXKeJuJqw 提取码: f2w9
喜欢本文请 点赞!!
更多参考链接:头发