浏览代码

Kajiya Kay Hair

/projects-TheLastStand
John Parsaie 6 年前
当前提交
48229436
共有 6 个文件被更改,包括 284 次插入127 次删除
  1. 22
      ScriptableRenderPipeline/LightweightPipeline/LWRP/Editor/ShaderGUI/LightweightHairGUI.cs
  2. 164
      ScriptableRenderPipeline/LightweightPipeline/LWRP/Shaders/Hair/Lighting.hlsl
  3. 6
      ScriptableRenderPipeline/LightweightPipeline/LWRP/Shaders/Hair/LightweightHair.shader
  4. 26
      ScriptableRenderPipeline/LightweightPipeline/LWRP/Shaders/Hair/LightweightPassLit.hlsl
  5. 184
      ScriptableRenderPipeline/LightweightPipeline/LWRP/Shaders/Hair/InputSurface.hlsl
  6. 9
      ScriptableRenderPipeline/LightweightPipeline/LWRP/Shaders/Hair/InputSurface.hlsl.meta

22
ScriptableRenderPipeline/LightweightPipeline/LWRP/Editor/ShaderGUI/LightweightHairGUI.cs


//Hair Properties
public static GUIContent hairAreaText = new GUIContent("Hair", "");
public static GUIContent hairShadows = new GUIContent("Shadows", "TODO");
public static GUIContent hairMapText = new GUIContent("Hair Map", "");
public static GUIContent specularShift0Text = new GUIContent("Specular Shift 0", "");
public static GUIContent specularShift1Text = new GUIContent("Specular Shift 1", "");
public static GUIContent specularTint0 = new GUIContent("Specular Tint 0", "");
public static GUIContent specularTint1 = new GUIContent("Specular Tint 1", "");
public static string primaryMapsText = "Main Maps";
public static string secondaryMapsText = "Secondary Maps";

//Hair Properties
private MaterialProperty recieveShadows;
private MaterialProperty hairMap;
private MaterialProperty specularShift0;
private MaterialProperty specularShift1;
private MaterialProperty specularTint0;
private MaterialProperty specularTint1;
public override void FindProperties(MaterialProperty[] properties)
{

//Hair Properties
recieveShadows = FindProperty("_RecieveShadows", properties);
hairMap = FindProperty("_HairMap", properties);
specularShift0 = FindProperty("_SpecularShift0", properties);
specularShift1 = FindProperty("_SpecularShift1", properties);
specularTint0 = FindProperty("_SpecularTint0", properties);
specularTint1 = FindProperty("_SpecularTint1", properties);
}
public override void MaterialChanged(Material material)

bool shadows = EditorGUILayout.Toggle(Styles.hairShadows, recieveShadows.floatValue == 1);
if(EditorGUI.EndChangeCheck())
recieveShadows.floatValue = shadows ? 1 : 0;
m_MaterialEditor.TexturePropertySingleLine(Styles.hairMapText, hairMap);
m_MaterialEditor.ShaderProperty(specularShift0, Styles.specularShift0Text);
m_MaterialEditor.ShaderProperty(specularShift1, Styles.specularShift1Text);
m_MaterialEditor.ShaderProperty(specularTint0, Styles.specularTint0);
m_MaterialEditor.ShaderProperty(specularTint1, Styles.specularTint1);
}
static SmoothnessMapChannel GetSmoothnessMapChannel(Material material)

//Hair Keywords
CoreUtils.SetKeyword(material, "_HAIR_RECEIVE_SHADOWS", material.GetFloat("_RecieveShadows") == 1);
CoreUtils.SetKeyword(material, "_TWO_SIDED", material.GetFloat("_Cull") == 0);
// A material's GI flag internally keeps track of whether emission is enabled at all, it's enabled but has no effect
// or is enabled and may be modified at runtime. This state depends on the values of the current flag and emissive color.

164
ScriptableRenderPipeline/LightweightPipeline/LWRP/Shaders/Hair/Lighting.hlsl


return vertexLightColor;
}
#define ALPHA_R -5.0
#define ALPHA_TT ALPHA_R / 2.0
#define ALPHA_TRT -3.0 * ALPHA_R / 2.0
#define BETA_R 5.0
#define BETA_TT BETA_R / 2.0
#define BETA_TRT 2.0 * BETA_R
#define IOR 1.55
float Fresnel(float ior, float x)
half3 HairGlobalIllumination(BRDFData brdfData, half3 bakedGI, half occlusion, half3 normalWS, half3 viewDirectionWS,
half3 tangent)
float num = 1.0 - ior;
float den = 1.0 + ior;
float F0 = (num * num) / (den * den);
half3 reflectVector = normalWS;// reflect(-viewDirectionWS, normalWS);
half fresnelTerm = Pow4(1.0 - saturate(dot(normalWS, viewDirectionWS)));
return F0 + (1.0 - F0) * pow(1.0 - x, 5);
}
//M Term is a simple gaussian distribution
float M(float B, float Theta)
{
float term0 = 1.0 / (B * sqrt(2.0 * PI));
float term1 = -( (Theta * Theta) / (2.0 * B * B) );
return term0 * exp(term1);
half3 indirectDiffuse = bakedGI * occlusion;
half3 indirectSpecular = GlossyEnvironmentReflection(reflectVector, brdfData.perceptualRoughness, occlusion);
return EnvironmentBRDF(brdfData, indirectDiffuse, indirectSpecular, fresnelTerm);
//NR Term
float NR(float CosPhi, float CosHalfPhi)
//Kajiya-Kay Phenomenological Shading Model for Hair
float HairDiffuseTerm(float3 N, float3 L)
float Distribution = 0.25 * CosHalfPhi;
float Attenuation = Fresnel(IOR, CosHalfPhi);
return Distribution * Attenuation;
return saturate(0.75 * dot(N, L) + 0.25);
//NTT Term
float3 NTT(float CosPhi, float CosHalfPhi, float CosThetaD, float3 VolumeAlbedo)
float HairSingleSpecularTerm(float3 T, float3 H, float exponent)
//Assumes Eta of 1.55 for human hair.
float EtaPrime = (1.19 / CosThetaD) + 0.36 * CosThetaD;
float a = 1.0 / EtaPrime;
float h = (1.0 + (a * (0.6 - (0.8 * CosPhi)))) * CosHalfPhi;
//Attenuation Term
float F = Fresnel(EtaPrime, CosThetaD * sqrt(1.0 - h*h));
float Fp = Fresnel(IOR, CosHalfPhi);
float Texp = (sqrt(1.0 - (h*h*a*a)) / (2.0 * CosThetaD));
float3 T = pow(VolumeAlbedo, Texp);
float3 A = pow(1 - F, 2) * Fp * T;
//Distribution Term
float D = exp((-3.65 * CosPhi) - 3.98);
return A * D;
float dotTH = dot(T, H);
float sinTH = sqrt(1.0 - dotTH * dotTH);
return pow(sinTH, exponent);
//NTRT Term
float3 NTRT(float CosPhi, float CosHalfPhi, float CosThetaD, float3 VolumeAlbedo)
float3 ShiftTangent(float3 T, float3 N, float shiftAmount)
//Assumes Eta of 1.55 for human hair.
float EtaPrime = (1.19 / CosThetaD) + 0.36 * CosThetaD;
float h = sqrt(3) / 2.0;
float F = Fresnel(EtaPrime, CosThetaD * sqrt(1.0 - h*h));
float Fp = Fresnel(IOR, CosHalfPhi);
float3 T = pow(VolumeAlbedo, 0.8 / CosThetaD);
float3 A = pow(1 - F, 2) * Fp * T;
float D = exp((17.0 * CosPhi) - 16.78);
return A * D;
}
return normalize(T + shiftAmount * N);
}
half3 Hair(BRDFData brdfData,
half3 Light, half3 View, half3 Normal, half3 Tangent)
//Based of the Rendermonkey Hair shading demo.
//Hair Data:
//x: Mask
//y: Base
//z: Shift
half3 Hair(BRDFData brdfData, half3 HairData,
Light L, half3 V, half3 N, half3 T, half Smoothness)
//Calculate Binormal to complete the onormal basis.
half3 Binormal = cross(Tangent, Normal);
//Calculate cosines.
float TdotL = dot(Tangent, Light);
float TdotV = dot(Tangent, View);
float BdotL = dot(Binormal, Light);
float BdotV = dot(Binormal, View);
float LdotV = dot(Light, View);
//Azimuth projection.
float3 ProjLight = Light - TdotL * Tangent;
float3 ProjView = View - TdotV * Tangent;
float ThetaH = (TdotL + TdotV) / 2.0;
float CosPhi = dot(ProjView, ProjLight) * pow(dot(ProjView, ProjView) * dot(ProjLight, ProjLight), -0.5);
float CosHalfPhi = sqrt(0.5 + 0.5 * CosPhi);
float CosThetaD = cos( (acos(TdotV) - acos(TdotL)) / 2.0 );
//R Path
float mr = M(radians(BETA_R), ThetaH - radians(ALPHA_R));
float nr = NR(CosPhi, CosHalfPhi);
//TT Path
float mtt = M(radians(BETA_TT), ThetaH - radians(ALPHA_TT));
float3 ntt = NTT(CosPhi, CosHalfPhi, CosThetaD, brdfData.diffuse);
//TRT Path
float mtrt = M(radians(BETA_TRT), ThetaH - radians(ALPHA_TRT));
float3 ntrt = NTRT(CosPhi, CosHalfPhi, CosThetaD, brdfData.diffuse);
float3 T1 = ShiftTangent(T, N, _SpecularShift0 + HairData.z);
float3 T2 = ShiftTangent(T, N, _SpecularShift1 + HairData.z);
return brdfData.diffuse + (1.5 * ((mr * nr * 1) + (mtt * ntt * 1) + (mtrt * ntrt * 5)) / (CosThetaD * CosThetaD));
}
L.color *= L.attenuation;
float3 Diffuse = brdfData.diffuse * L.color * HairDiffuseTerm(N, L.direction);
half3 HairGlobalIllumination(BRDFData brdfData, half3 bakedGI, half occlusion, half3 normalWS, half3 viewDirectionWS,
half3 tangent)
{
half3 reflectVector = normalWS;// reflect(-viewDirectionWS, normalWS);
half fresnelTerm = Pow4(1.0 - saturate(dot(normalWS, viewDirectionWS)));
float3 H = normalize(L.direction + V);
float3 Specular1 = _SpecularTint0 * HairSingleSpecularTerm(T1, H, Smoothness * 256);
float3 Specular2 = _SpecularTint1 * HairSingleSpecularTerm(T2, H, Smoothness * 256);
Specular2 *= HairData.x;
half3 indirectDiffuse = bakedGI * occlusion;
half3 indirectSpecular = GlossyEnvironmentReflection(reflectVector, brdfData.perceptualRoughness, occlusion);
float TdotL = dot(tangent, normalWS);
float TdotV = dot(tangent, viewDirectionWS);
float ThetaH = (TdotL + TdotV) / 1.0;
float mr = M(radians(BETA_R), ThetaH - radians(ALPHA_R));
float SpecularAttenuation = saturate(1.75 * dot(N, L.direction) + 0.25);
float3 Specular = (Specular1 + Specular2) * L.color * SpecularAttenuation;
return EnvironmentBRDF(brdfData, indirectDiffuse, indirectSpecular, fresnelTerm);
half3 O;
O.rgb = Diffuse * HairData.y;
O.rgb += Specular * HairData.y;
return O;
}
///////////////////////////////////////////////////////////////////////////////

half4 LightweightFragmentPBR(InputData inputData, half3 albedo, half metallic, half3 specular,
half smoothness, half occlusion, half3 emission, half alpha, half3 tangent)
half smoothness, half occlusion, half3 emission, half alpha, half3 hairData, half3 tangent)
{
BRDFData brdfData;
InitializeBRDFData(albedo, metallic, specular, smoothness, alpha, brdfData);

half3 color = HairGlobalIllumination(brdfData, inputData.bakedGI, occlusion, normalFake, inputData.viewDirectionWS, tangent);
//Hair Shading.
half NdotL = saturate(dot(inputData.normalWS, mainLight.direction));
half3 radiance = mainLight.color * (mainLight.attenuation * NdotL);
color += Hair(brdfData, mainLight.direction, inputData.viewDirectionWS, inputData.normalWS, tangent) * radiance;
color += Hair(brdfData, hairData, mainLight, inputData.viewDirectionWS, inputData.normalWS, tangent, smoothness);
half NdotL = saturate(dot(inputData.normalWS, light.direction));
radiance = light.color * (light.attenuation * NdotL);
color += Hair(brdfData, light.direction, inputData.viewDirectionWS, inputData.normalWS, tangent) * radiance;
color += Hair(brdfData, hairData, light, inputData.viewDirectionWS, inputData.normalWS, tangent, smoothness);
color += inputData.vertexLighting * brdfData.diffuse;
color += emission;

6
ScriptableRenderPipeline/LightweightPipeline/LWRP/Shaders/Hair/LightweightHair.shader


//Hair Properties
[HideInInspector] _RecieveShadows("__rshadows", Float) = 0.0
_HairMap ("Hair Map", 2D) = "white" {}
_SpecularShift0 ("Specular Shift 0", Range(-1.0, 1.0)) = 0.5
_SpecularShift1 ("Specular Shift 1", Range(-1.0, 1.0)) = 0.5
_SpecularTint0 ("Specular Tint 0", Color) = (1, 1, 1, 1)
_SpecularTint1 ("Specular Tint 1", Color) = (1, 1, 1, 1)
[Enum(UV0,0,UV1,1)] _UVSec("UV Set for secondary textures", Float) = 0

#pragma shader_feature _GLOSSYREFLECTIONS_OFF
#pragma shader_feature _SPECULAR_SETUP
#pragma shader_feature _TWO_SIDED
#pragma shader_feature _HAIR_RECEIVE_SHADOWS
// -------------------------------------

26
ScriptableRenderPipeline/LightweightPipeline/LWRP/Shaders/Hair/LightweightPassLit.hlsl


#ifndef LIGHTWEIGHT_PASS_LIT_INCLUDED
#define LIGHTWEIGHT_PASS_LIT_INCLUDED
#include "LWRP/ShaderLibrary/InputSurface.hlsl"
#include "InputSurface.hlsl"
#include "Lighting.hlsl"
struct LightweightVertexInput

float4 shadowCoord : TEXCOORD8;
#if SHADER_STAGE_FRAGMENT
FRONT_FACE_TYPE cullFace : FRONT_FACE_SEMANTIC;
#endif
UNITY_VERTEX_INPUT_INSTANCE_ID
UNITY_VERTEX_OUTPUT_STEREO
};

inputData.normalWS = TangentToWorldNormal(normalTS, IN.tangent, IN.binormal, IN.normal);
#else
inputData.normalWS = normalize(IN.normal);
#endif
bool isFrontFace = true;
#if SHADER_STAGE_FRAGMENT
isFrontFace = IS_FRONT_VFACE(IN.cullFace, true, false);
#endif
#ifdef _TWO_SIDED
if(!isFrontFace)
{
inputData.normalWS = -inputData.normalWS;
}
#endif
#ifdef SHADER_API_MOBILE

InputData inputData;
InitializeInputData(IN, surfaceData.normalTS, inputData);
half4 color = LightweightFragmentPBR(inputData, surfaceData.albedo, surfaceData.metallic, surfaceData.specular, surfaceData.smoothness, surfaceData.occlusion, surfaceData.emission, surfaceData.alpha, -IN.binormal);
half4 color = LightweightFragmentPBR(inputData, surfaceData.albedo, surfaceData.metallic, surfaceData.specular, surfaceData.smoothness, surfaceData.occlusion, surfaceData.emission, surfaceData.alpha, surfaceData.hairData, IN.binormal);
return color;
return half4(color.rgb * SSAO(IN.shadowCoord), color.a);
}
// Used for Standard shader

184
ScriptableRenderPipeline/LightweightPipeline/LWRP/Shaders/Hair/InputSurface.hlsl


#ifndef LIGHTWEIGHT_SURFACE_INPUT_INCLUDED
#define LIGHTWEIGHT_SURFACE_INPUT_INCLUDED
#include "../../ShaderLibrary/Core.hlsl"
#include "CoreRP/ShaderLibrary/Packing.hlsl"
#include "CoreRP/ShaderLibrary/CommonMaterial.hlsl"
#ifdef _SPECULAR_SETUP
#define SAMPLE_METALLICSPECULAR(uv) SAMPLE_TEXTURE2D(_SpecGlossMap, sampler_SpecGlossMap, uv)
#else
#define SAMPLE_METALLICSPECULAR(uv) SAMPLE_TEXTURE2D(_MetallicGlossMap, sampler_MetallicGlossMap, uv)
#endif
CBUFFER_START(UnityPerMaterial)
half4 _MainTex_ST;
half4 _Color;
half _Cutoff;
half _Glossiness;
half _GlossMapScale;
half _SmoothnessTextureChannel;
half _Metallic;
half4 _SpecColor;
half _BumpScale;
half _OcclusionStrength;
half4 _EmissionColor;
half _Shininess;
//Hair
half _SpecularShift0;
half _SpecularShift1;
half4 _SpecularTint0;
half4 _SpecularTint1;
CBUFFER_END
TEXTURE2D(_MainTex); SAMPLER(sampler_MainTex);
TEXTURE2D(_MetallicGlossMap); SAMPLER(sampler_MetallicGlossMap);
TEXTURE2D(_SpecGlossMap); SAMPLER(sampler_SpecGlossMap);
TEXTURE2D(_BumpMap); SAMPLER(sampler_BumpMap);
TEXTURE2D(_OcclusionMap); SAMPLER(sampler_OcclusionMap);
TEXTURE2D(_EmissionMap); SAMPLER(sampler_EmissionMap);
TEXTURE2D(_HairMap); SAMPLER(sampler_HairMap);
// Must match Lightweigth ShaderGraph master node
struct SurfaceData
{
half3 albedo;
half3 specular;
half metallic;
half smoothness;
half3 normalTS;
half3 emission;
half3 occlusion; //TLS: Colored AO.
half alpha;
half3 hairData;
};
///////////////////////////////////////////////////////////////////////////////
// Material Property Helpers //
///////////////////////////////////////////////////////////////////////////////
inline half Alpha(half albedoAlpha)
{
#if defined(_SMOOTHNESS_TEXTURE_ALBEDO_CHANNEL_A)
half alpha = _Color.a;
#else
half alpha = albedoAlpha * _Color.a;
#endif
#if defined(_ALPHATEST_ON)
clip(alpha - _Cutoff);
#endif
return alpha;
}
half3 Normal(float2 uv)
{
#if _NORMALMAP
return UnpackNormalScale(SAMPLE_TEXTURE2D(_BumpMap, sampler_BumpMap, uv), _BumpScale);
#else
return half3(0.0h, 0.0h, 1.0h);
#endif
}
half4 SpecularGloss(half2 uv, half alpha)
{
half4 specularGloss = half4(0, 0, 0, 1);
#ifdef _SPECGLOSSMAP
specularGloss = SAMPLE_TEXTURE2D(_SpecGlossMap, sampler_SpecGlossMap, uv);
specularGloss.rgb = specularGloss.rgb;
#elif defined(_SPECULAR_COLOR)
specularGloss = _SpecColor;
#endif
#ifdef _GLOSSINESS_FROM_BASE_ALPHA
specularGloss.a = alpha;
#endif
return specularGloss;
}
half4 MetallicSpecGloss(float2 uv, half albedoAlpha)
{
half4 specGloss;
#ifdef _METALLICSPECGLOSSMAP
specGloss = specGloss = SAMPLE_METALLICSPECULAR(uv);
#ifdef _SMOOTHNESS_TEXTURE_ALBEDO_CHANNEL_A
specGloss.a = albedoAlpha * _GlossMapScale;
#else
specGloss.a *= _GlossMapScale;
#endif
#else // _METALLICSPECGLOSSMAP
#if _SPECULAR_SETUP
specGloss.rgb = _SpecColor.rgb;
#else
specGloss.rgb = _Metallic.rrr;
#endif
#ifdef _SMOOTHNESS_TEXTURE_ALBEDO_CHANNEL_A
specGloss.a = albedoAlpha * _GlossMapScale;
#else
specGloss.a = _Glossiness;
#endif
#endif
return specGloss;
}
half Occlusion(float2 uv)
{
#ifdef _OCCLUSIONMAP
#if (SHADER_TARGET < 30)
// SM20: instruction count limitation
// SM20: simpler occlusion
return SAMPLE_TEXTURE2D(_OcclusionMap, sampler_OcclusionMap, uv).g;
#else
half occ = SAMPLE_TEXTURE2D(_OcclusionMap, sampler_OcclusionMap, uv).g;
return LerpWhiteTo(occ, _OcclusionStrength);
#endif
#else
return 1.0;
#endif
}
half3 Emission(float2 uv)
{
#ifndef _EMISSION
return 0;
#else
return SAMPLE_TEXTURE2D(_EmissionMap, sampler_EmissionMap, uv).rgb * _EmissionColor.rgb;
#endif
}
half3 HairData(float2 uv)
{
return half3(SAMPLE_TEXTURE2D(_HairMap, sampler_HairMap, uv * 1).x,
SAMPLE_TEXTURE2D(_HairMap, sampler_HairMap, uv * 1).y,
SAMPLE_TEXTURE2D(_HairMap, sampler_HairMap, uv * 1).z);
}
inline void InitializeStandardLitSurfaceData(float2 uv, out SurfaceData outSurfaceData)
{
half4 albedoAlpha = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, uv);
half4 specGloss = MetallicSpecGloss(uv, albedoAlpha.a);
outSurfaceData.albedo = albedoAlpha.rgb * _Color.rgb;
#if _SPECULAR_SETUP
outSurfaceData.metallic = 1.0h;
outSurfaceData.specular = specGloss.rgb;
#else
outSurfaceData.metallic = specGloss.r;
outSurfaceData.specular = half3(0.0h, 0.0h, 0.0h);
#endif
outSurfaceData.smoothness = specGloss.a;
outSurfaceData.normalTS = Normal(uv);
outSurfaceData.occlusion = Occlusion(uv);
outSurfaceData.emission = Emission(uv);
outSurfaceData.alpha = Alpha(albedoAlpha.a);
outSurfaceData.hairData = HairData(uv);
}
#endif

9
ScriptableRenderPipeline/LightweightPipeline/LWRP/Shaders/Hair/InputSurface.hlsl.meta


fileFormatVersion: 2
guid: 68f4e13197c9d3e4e9f7e23ea458ec4a
ShaderImporter:
externalObjects: {}
defaultTextures: []
nonModifiableTextures: []
userData:
assetBundleName:
assetBundleVariant:
正在加载...
取消
保存