556 lines
21 KiB
HLSL
556 lines
21 KiB
HLSL
// NiloToon Character Fur - Shared Definitions
|
|
// Full-featured structs, CBUFFER, and common functions
|
|
|
|
#ifndef NILOTOON_CHARACTER_FUR_SHARED_INCLUDED
|
|
#define NILOTOON_CHARACTER_FUR_SHARED_INCLUDED
|
|
|
|
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
|
|
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"
|
|
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Shadows.hlsl"
|
|
|
|
// Include NiloToon utility functions (order matters - InvLerpRemapUtil must come before PerspectiveRemovalUtil)
|
|
#include "../../ShaderLibrary/NiloUtilityHLSL/NiloInvLerpRemapUtil.hlsl"
|
|
#include "../../ShaderLibrary/NiloUtilityHLSL/NiloBlendEquationUtil.hlsl"
|
|
#include "../../ShaderLibrary/NiloUtilityHLSL/NiloDitherFadeoutClipUtil.hlsl"
|
|
#include "../../ShaderLibrary/NiloUtilityHLSL/NiloPerspectiveRemovalUtil.hlsl"
|
|
#include "../../ShaderLibrary/NiloUtilityHLSL/NiloUVCalculateUtil.hlsl"
|
|
|
|
//------------------------------------------------------------------------------------------------------------------------------
|
|
// NiloToon Global Light Override Variables (from NiloToonCharacterMainLightOverrider)
|
|
//------------------------------------------------------------------------------------------------------------------------------
|
|
half4 _GlobalUserOverriddenFinalMainLightDirWSParam; // xyz: direction, w: 1 if enabled
|
|
half4 _GlobalUserOverriddenFinalMainLightColorParam; // rgb: color, w: 1 if enabled
|
|
|
|
//------------------------------------------------------------------------------------------------------------------------------
|
|
// Helper function for view direction (compatible with all URP versions)
|
|
//------------------------------------------------------------------------------------------------------------------------------
|
|
float3 GetWorldSpaceViewDirSafe(float3 positionWS)
|
|
{
|
|
return normalize(_WorldSpaceCameraPos.xyz - positionWS);
|
|
}
|
|
|
|
//------------------------------------------------------------------------------------------------------------------------------
|
|
// Helper function for shadow coord (compatible with all URP versions)
|
|
//------------------------------------------------------------------------------------------------------------------------------
|
|
float4 GetShadowCoordSafe(VertexPositionInputs vertexInput)
|
|
{
|
|
#if defined(_MAIN_LIGHT_SHADOWS_SCREEN) && !defined(_SURFACE_TYPE_TRANSPARENT)
|
|
return ComputeScreenPos(vertexInput.positionCS);
|
|
#else
|
|
return TransformWorldToShadowCoord(vertexInput.positionWS);
|
|
#endif
|
|
}
|
|
|
|
//------------------------------------------------------------------------------------------------------------------------------
|
|
// Get Main Light with NiloToon Override Support
|
|
//------------------------------------------------------------------------------------------------------------------------------
|
|
Light GetMainLightWithNiloToonOverride()
|
|
{
|
|
Light mainLight = GetMainLight();
|
|
|
|
// Apply NiloToon MainLightOverrider if enabled
|
|
if (_GlobalUserOverriddenFinalMainLightDirWSParam.w > 0.5)
|
|
{
|
|
mainLight.direction = _GlobalUserOverriddenFinalMainLightDirWSParam.xyz;
|
|
}
|
|
if (_GlobalUserOverriddenFinalMainLightColorParam.w > 0.5)
|
|
{
|
|
mainLight.color = _GlobalUserOverriddenFinalMainLightColorParam.rgb;
|
|
}
|
|
|
|
return mainLight;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------------------------------------------------------
|
|
// CBUFFER for SRP Batcher
|
|
//------------------------------------------------------------------------------------------------------------------------------
|
|
CBUFFER_START(UnityPerMaterial)
|
|
// Base
|
|
float4 _BaseMap_ST;
|
|
half4 _BaseColor;
|
|
half _Cutoff;
|
|
|
|
// Normal Map
|
|
float4 _BumpMap_ST;
|
|
half _BumpScale;
|
|
|
|
// Fur Shape
|
|
float4 _FurNoiseMask_ST;
|
|
float4 _FurMask_ST;
|
|
float4 _FurLengthMask_ST;
|
|
float4 _FurVector;
|
|
float4 _FurVectorTex_ST;
|
|
half _FurVectorScale;
|
|
half _FurGravity;
|
|
half _FurRandomize;
|
|
half _FurAO;
|
|
half _FurLayerNum;
|
|
half _FurRootOffset;
|
|
|
|
// Fur Rim
|
|
half4 _FurRimColor;
|
|
half _FurRimFresnelPower;
|
|
half _FurRimAntiLight;
|
|
|
|
// Cel Shading
|
|
half _CelShadeMidPoint;
|
|
half _CelShadeSoftness;
|
|
|
|
// Shadow Color
|
|
half4 _ShadowColor;
|
|
half _ShadowBrightness;
|
|
half _ShadowHueShift;
|
|
half _ShadowSaturationBoost;
|
|
half _ShadowValueMultiplier;
|
|
|
|
// MatCap Add
|
|
float4 _MatCapAddMap_ST;
|
|
half4 _MatCapAddColor;
|
|
half _MatCapAddIntensity;
|
|
float4 _MatCapAddMask_ST;
|
|
|
|
// MatCap Multiply
|
|
float4 _MatCapMulMap_ST;
|
|
half _MatCapMulIntensity;
|
|
|
|
// Rim Light
|
|
half4 _RimLightColor;
|
|
half _RimLightPower;
|
|
half _RimLightIntensity;
|
|
|
|
// Emission
|
|
float4 _EmissionMap_ST;
|
|
half4 _EmissionColor;
|
|
half _EmissionIntensity;
|
|
|
|
// Occlusion
|
|
float4 _OcclusionMap_ST;
|
|
half _OcclusionStrength;
|
|
|
|
// Outline
|
|
half _OutlineWidth;
|
|
half4 _OutlineColor;
|
|
float4 _OutlineWidthMask_ST;
|
|
|
|
// Rendering
|
|
half _Cull;
|
|
half _FurCull;
|
|
|
|
// Dissolve
|
|
float _DissolveAmount;
|
|
float _DissolveMode;
|
|
float _DissolveThresholdMapTilingX;
|
|
float _DissolveThresholdMapTilingY;
|
|
float _DissolveNoiseStrength;
|
|
float _DissolveBorderRange;
|
|
half4 _DissolveBorderTintColor;
|
|
float _AllowPerCharacterDissolve;
|
|
|
|
// Per-Character Color Controls
|
|
half _PerCharacterBaseColorMultiply;
|
|
half4 _PerCharacterBaseColorTint;
|
|
half3 _PerCharEffectTintColor; // Set by NiloToonPerCharacterRenderController
|
|
half3 _PerCharEffectAddColor; // Set by NiloToonPerCharacterRenderController
|
|
half _PerCharEffectDesaturatePercentage;
|
|
half4 _PerCharEffectLerpColor;
|
|
|
|
// Per-Character Rim Light
|
|
half _UsePerCharacterRimLightIntensity;
|
|
half _PerCharacterRimLightIntensity;
|
|
half4 _PerCharacterRimLightColor;
|
|
half _PerCharacterRimLightSharpnessPower;
|
|
|
|
// BaseMap Override
|
|
half _PerCharacterBaseMapOverrideAmount;
|
|
half4 _PerCharacterBaseMapOverrideTintColor;
|
|
float4 _PerCharacterBaseMapOverrideMap_ST;
|
|
half _PerCharacterBaseMapOverrideBlendMode;
|
|
half _PerCharacterBaseMapOverrideUVOption;
|
|
|
|
// Character Area Color Fill
|
|
half _ShouldRenderCharacterAreaColorFill;
|
|
half4 _CharacterAreaColorFillColor;
|
|
float4 _CharacterAreaColorFillTexture_ST;
|
|
half _CharacterAreaColorFillUVOption;
|
|
|
|
// Dither Opacity
|
|
half _DitherOpacity;
|
|
|
|
// Dither Fadeout
|
|
half _DitherFadeoutAmount;
|
|
half _DitherFadeoutNormalScaleFix;
|
|
half _AllowPerCharacterDitherFadeout;
|
|
|
|
// Perspective Removal
|
|
half _PerspectiveRemovalAmount;
|
|
half _PerspectiveRemovalRadius;
|
|
half _PerspectiveRemovalStartHeight;
|
|
half _PerspectiveRemovalEndHeight;
|
|
|
|
// ZOffset
|
|
half _PerCharacterZOffset;
|
|
|
|
// Character Bound (for dissolve)
|
|
float _CharacterBoundRadius;
|
|
|
|
// Character ID (for accessing global arrays)
|
|
uint _CharacterID;
|
|
CBUFFER_END
|
|
|
|
//------------------------------------------------------------------------------------------------------------------------------
|
|
// NiloToon Global Per-Character Arrays
|
|
// For properties that change every frame, use global arrays instead of CBUFFER for performance
|
|
//------------------------------------------------------------------------------------------------------------------------------
|
|
#ifndef MAX_CHARACTER_COUNT
|
|
#define MAX_CHARACTER_COUNT 256
|
|
#endif
|
|
|
|
float3 _NiloToonGlobalPerCharHeadBonePosWSArray[MAX_CHARACTER_COUNT];
|
|
float3 _NiloToonGlobalPerCharFaceForwardDirWSArray[MAX_CHARACTER_COUNT];
|
|
float3 _NiloToonGlobalPerCharFaceUpwardDirWSArray[MAX_CHARACTER_COUNT];
|
|
float3 _NiloToonGlobalPerCharBoundCenterPosWSArray[MAX_CHARACTER_COUNT];
|
|
|
|
//------------------------------------------------------------------------------------------------------------------------------
|
|
// Texture Declarations (all textures declared unconditionally to avoid compilation issues)
|
|
//------------------------------------------------------------------------------------------------------------------------------
|
|
TEXTURE2D(_BaseMap); SAMPLER(sampler_BaseMap);
|
|
TEXTURE2D(_BumpMap); SAMPLER(sampler_BumpMap);
|
|
|
|
// Fur textures
|
|
TEXTURE2D(_FurNoiseMask); SAMPLER(sampler_FurNoiseMask);
|
|
TEXTURE2D(_FurMask); SAMPLER(sampler_FurMask);
|
|
TEXTURE2D(_FurLengthMask); SAMPLER(sampler_FurLengthMask);
|
|
TEXTURE2D(_FurVectorTex); SAMPLER(sampler_FurVectorTex);
|
|
|
|
// MatCap
|
|
TEXTURE2D(_MatCapAddMap); SAMPLER(sampler_MatCapAddMap);
|
|
TEXTURE2D(_MatCapAddMask); SAMPLER(sampler_MatCapAddMask);
|
|
TEXTURE2D(_MatCapMulMap); SAMPLER(sampler_MatCapMulMap);
|
|
|
|
// Emission
|
|
TEXTURE2D(_EmissionMap); SAMPLER(sampler_EmissionMap);
|
|
|
|
// Occlusion
|
|
TEXTURE2D(_OcclusionMap); SAMPLER(sampler_OcclusionMap);
|
|
|
|
// Outline
|
|
TEXTURE2D(_OutlineWidthMask); SAMPLER(sampler_OutlineWidthMask);
|
|
|
|
// Dissolve
|
|
#if _NILOTOON_DISSOLVE
|
|
TEXTURE2D(_DissolveThresholdMap); SAMPLER(sampler_DissolveThresholdMap);
|
|
#endif
|
|
|
|
// BaseMap Override
|
|
TEXTURE2D(_PerCharacterBaseMapOverrideMap); SAMPLER(sampler_PerCharacterBaseMapOverrideMap);
|
|
|
|
// Character Area Color Fill
|
|
TEXTURE2D(_CharacterAreaColorFillTexture); SAMPLER(sampler_CharacterAreaColorFillTexture);
|
|
|
|
//------------------------------------------------------------------------------------------------------------------------------
|
|
// Vertex Input Structure
|
|
//------------------------------------------------------------------------------------------------------------------------------
|
|
struct Attributes
|
|
{
|
|
float4 positionOS : POSITION;
|
|
float3 normalOS : NORMAL;
|
|
float4 tangentOS : TANGENT;
|
|
float2 uv : TEXCOORD0;
|
|
float2 uv2 : TEXCOORD1;
|
|
float4 color : COLOR;
|
|
uint vertexID : SV_VertexID;
|
|
UNITY_VERTEX_INPUT_INSTANCE_ID
|
|
};
|
|
|
|
//------------------------------------------------------------------------------------------------------------------------------
|
|
// Vertex to Geometry Structure (for Fur Shell Pass)
|
|
//------------------------------------------------------------------------------------------------------------------------------
|
|
struct V2G
|
|
{
|
|
float2 uv : TEXCOORD0;
|
|
float3 positionWS : TEXCOORD1;
|
|
float3 normalWS : TEXCOORD2;
|
|
float4 tangentWS : TEXCOORD3;
|
|
float3 furVector : TEXCOORD4;
|
|
float fogFactor : TEXCOORD5;
|
|
uint vertexID : TEXCOORD6;
|
|
float4 color : COLOR;
|
|
UNITY_VERTEX_INPUT_INSTANCE_ID
|
|
UNITY_VERTEX_OUTPUT_STEREO
|
|
};
|
|
|
|
//------------------------------------------------------------------------------------------------------------------------------
|
|
// Fragment Input Structure
|
|
//------------------------------------------------------------------------------------------------------------------------------
|
|
struct Varyings
|
|
{
|
|
float4 positionCS : SV_POSITION;
|
|
float2 uv : TEXCOORD0;
|
|
float3 positionWS : TEXCOORD1;
|
|
float3 normalWS : TEXCOORD2;
|
|
float4 tangentWS : TEXCOORD3;
|
|
float fogFactor : TEXCOORD4;
|
|
float furLayer : TEXCOORD5; // 0 = base, 1 = outer shell
|
|
float4 shadowCoord : TEXCOORD6;
|
|
UNITY_VERTEX_INPUT_INSTANCE_ID
|
|
UNITY_VERTEX_OUTPUT_STEREO
|
|
};
|
|
|
|
//------------------------------------------------------------------------------------------------------------------------------
|
|
// Color Space Conversion (RGB <-> HSV)
|
|
//------------------------------------------------------------------------------------------------------------------------------
|
|
float3 RGBToHSV(float3 rgb)
|
|
{
|
|
float4 K = float4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);
|
|
float4 p = lerp(float4(rgb.bg, K.wz), float4(rgb.gb, K.xy), step(rgb.b, rgb.g));
|
|
float4 q = lerp(float4(p.xyw, rgb.r), float4(rgb.r, p.yzx), step(p.x, rgb.r));
|
|
float d = q.x - min(q.w, q.y);
|
|
float e = 1.0e-10;
|
|
return float3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);
|
|
}
|
|
|
|
float3 HSVToRGB(float3 hsv)
|
|
{
|
|
float4 K = float4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
|
|
float3 p = abs(frac(hsv.xxx + K.xyz) * 6.0 - K.www);
|
|
return hsv.z * lerp(K.xxx, saturate(p - K.xxx), hsv.y);
|
|
}
|
|
|
|
//------------------------------------------------------------------------------------------------------------------------------
|
|
// Utility: Grayscale
|
|
//------------------------------------------------------------------------------------------------------------------------------
|
|
half Grayscale(half3 color)
|
|
{
|
|
return dot(color, half3(0.299, 0.587, 0.114));
|
|
}
|
|
|
|
//------------------------------------------------------------------------------------------------------------------------------
|
|
// Normal Map Unpacking
|
|
//------------------------------------------------------------------------------------------------------------------------------
|
|
half3 UnpackNormalWithScale(half4 packedNormal, half scale)
|
|
{
|
|
#if defined(UNITY_NO_DXT5nm)
|
|
half3 normal = packedNormal.xyz * 2.0 - 1.0;
|
|
#else
|
|
half3 normal;
|
|
normal.xy = packedNormal.ag * 2.0 - 1.0;
|
|
normal.z = sqrt(1.0 - saturate(dot(normal.xy, normal.xy)));
|
|
#endif
|
|
normal.xy *= scale;
|
|
return normalize(normal);
|
|
}
|
|
|
|
//------------------------------------------------------------------------------------------------------------------------------
|
|
// MatCap UV Calculation
|
|
//------------------------------------------------------------------------------------------------------------------------------
|
|
float2 GetMatCapUV(float3 normalWS, float3 viewDirWS)
|
|
{
|
|
float3 viewNormal = mul((float3x3)UNITY_MATRIX_V, normalWS);
|
|
return viewNormal.xy * 0.5 + 0.5;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------------------------------------------------------
|
|
// Apply HSV Change to Color
|
|
//------------------------------------------------------------------------------------------------------------------------------
|
|
half3 ApplyHSVChange(half3 color, half hueOffset, half saturationBoost, half valueMul)
|
|
{
|
|
float3 hsv = RGBToHSV(color);
|
|
hsv.x = frac(hsv.x + hueOffset);
|
|
hsv.y = saturate(hsv.y * saturationBoost);
|
|
hsv.z = hsv.z * valueMul;
|
|
return HSVToRGB(hsv);
|
|
}
|
|
|
|
//------------------------------------------------------------------------------------------------------------------------------
|
|
// NiloToon Style Cel Shading (Full Version)
|
|
//------------------------------------------------------------------------------------------------------------------------------
|
|
half3 ApplyNiloToonCelShading(
|
|
half3 baseColor,
|
|
half3 lightColor,
|
|
half3 lightDir,
|
|
half3 normalWS,
|
|
half3 viewDir,
|
|
half shadowAttenuation,
|
|
half occlusion
|
|
)
|
|
{
|
|
// Calculate NdotL
|
|
half NdotL = dot(normalWS, lightDir);
|
|
|
|
// Cel shading with configurable mid point and softness
|
|
half halfLambert = NdotL * 0.5 + 0.5;
|
|
half celShadeResult = smoothstep(
|
|
_CelShadeMidPoint + 0.5 - _CelShadeSoftness,
|
|
_CelShadeMidPoint + 0.5 + _CelShadeSoftness,
|
|
halfLambert
|
|
);
|
|
|
|
// Apply shadow map attenuation
|
|
celShadeResult *= shadowAttenuation;
|
|
|
|
// Apply occlusion
|
|
celShadeResult *= occlusion;
|
|
|
|
half3 finalColor = baseColor;
|
|
|
|
#if defined(_SHADOW_COLOR)
|
|
// Apply HSV adjustment to shadow
|
|
half3 shadowAlbedo = ApplyHSVChange(
|
|
baseColor,
|
|
_ShadowHueShift,
|
|
_ShadowSaturationBoost,
|
|
_ShadowValueMultiplier
|
|
);
|
|
|
|
// Apply shadow tint and brightness
|
|
shadowAlbedo *= _ShadowColor.rgb * _ShadowBrightness;
|
|
|
|
// Blend between shadow and lit based on cel shade result
|
|
finalColor = lerp(shadowAlbedo, baseColor, celShadeResult);
|
|
#else
|
|
// Simple brightness reduction in shadow
|
|
finalColor = lerp(baseColor * 0.5, baseColor, celShadeResult);
|
|
#endif
|
|
|
|
// Apply light color
|
|
finalColor *= lightColor;
|
|
|
|
return finalColor;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------------------------------------------------------
|
|
// Fur Vector Calculation (from lilToon)
|
|
//------------------------------------------------------------------------------------------------------------------------------
|
|
float3 CalculateFurVector(float3 normalOS, float4 tangentOS, float2 uv, float4 vertexColor, bool useVertexColor)
|
|
{
|
|
// Build TBN matrix
|
|
float3 bitangentOS = normalize(cross(normalOS, tangentOS.xyz)) * (tangentOS.w * length(normalOS));
|
|
float3x3 tbnOS = float3x3(tangentOS.xyz, bitangentOS, normalOS);
|
|
|
|
// Start with base fur vector
|
|
float3 furVector = _FurVector.xyz + float3(0, 0, 0.001);
|
|
|
|
// Optional: blend with vertex color
|
|
if (useVertexColor)
|
|
{
|
|
float3 vertexNormal = vertexColor.xyz * 2.0 - 1.0;
|
|
furVector = normalize(furVector + vertexNormal);
|
|
}
|
|
|
|
// Transform to tangent space, then apply fur direction texture
|
|
#if defined(NILOTOON_FUR_SHELL_PASS)
|
|
float4 furDirTex = SAMPLE_TEXTURE2D_LOD(_FurVectorTex, sampler_FurVectorTex, uv * _FurVectorTex_ST.xy + _FurVectorTex_ST.zw, 0);
|
|
float3 furDirFromTex = UnpackNormalWithScale(furDirTex, _FurVectorScale);
|
|
furVector = normalize(furVector + furDirFromTex);
|
|
#endif
|
|
|
|
// Transform to object space direction
|
|
furVector = mul(normalize(furVector), tbnOS);
|
|
furVector *= _FurVector.w;
|
|
|
|
// Apply gravity
|
|
float furLength = length(furVector);
|
|
furVector.y -= _FurGravity * furLength;
|
|
|
|
return furVector;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------------------------------------------------------
|
|
// Base Pass Vertex Shader
|
|
//------------------------------------------------------------------------------------------------------------------------------
|
|
#if defined(NILOTOON_FUR_BASE_PASS)
|
|
Varyings vert(Attributes input)
|
|
{
|
|
Varyings output = (Varyings)0;
|
|
|
|
UNITY_SETUP_INSTANCE_ID(input);
|
|
UNITY_TRANSFER_INSTANCE_ID(input, output);
|
|
UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(output);
|
|
|
|
// Transform
|
|
VertexPositionInputs vertexInput = GetVertexPositionInputs(input.positionOS.xyz);
|
|
VertexNormalInputs normalInput = GetVertexNormalInputs(input.normalOS, input.tangentOS);
|
|
|
|
output.positionCS = vertexInput.positionCS;
|
|
output.positionWS = vertexInput.positionWS;
|
|
output.normalWS = normalInput.normalWS;
|
|
output.tangentWS = float4(normalInput.tangentWS, input.tangentOS.w);
|
|
output.uv = TRANSFORM_TEX(input.uv, _BaseMap);
|
|
|
|
// Apply Perspective Removal
|
|
output.positionCS = NiloDoPerspectiveRemoval(
|
|
output.positionCS,
|
|
output.positionWS,
|
|
_NiloToonGlobalPerCharHeadBonePosWSArray[_CharacterID],
|
|
_PerspectiveRemovalRadius,
|
|
_PerspectiveRemovalAmount,
|
|
_PerspectiveRemovalStartHeight,
|
|
_PerspectiveRemovalEndHeight
|
|
);
|
|
|
|
// Apply per-character Z offset
|
|
if (_PerCharacterZOffset != 0)
|
|
{
|
|
output.positionCS.z += _PerCharacterZOffset * output.positionCS.w;
|
|
}
|
|
|
|
// Shadow coord
|
|
output.shadowCoord = GetShadowCoordSafe(vertexInput);
|
|
|
|
// Fog
|
|
output.fogFactor = ComputeFogFactor(vertexInput.positionCS.z);
|
|
|
|
// Base pass has no fur layer
|
|
output.furLayer = -1.0;
|
|
|
|
return output;
|
|
}
|
|
#endif
|
|
|
|
//------------------------------------------------------------------------------------------------------------------------------
|
|
// Fur Pass Vertex Shader (outputs to Geometry Shader)
|
|
//------------------------------------------------------------------------------------------------------------------------------
|
|
#if defined(NILOTOON_FUR_SHELL_PASS)
|
|
V2G vert_fur(Attributes input)
|
|
{
|
|
V2G output = (V2G)0;
|
|
|
|
UNITY_SETUP_INSTANCE_ID(input);
|
|
UNITY_TRANSFER_INSTANCE_ID(input, output);
|
|
UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(output);
|
|
|
|
// Transform position and normal to world space
|
|
// IMPORTANT: Use GetVertexPositionInputs to match Base Pass transformation exactly
|
|
VertexPositionInputs vertexInput = GetVertexPositionInputs(input.positionOS.xyz);
|
|
VertexNormalInputs normalInput = GetVertexNormalInputs(input.normalOS, input.tangentOS);
|
|
|
|
output.positionWS = vertexInput.positionWS;
|
|
output.normalWS = normalInput.normalWS;
|
|
output.tangentWS = float4(normalInput.tangentWS, input.tangentOS.w);
|
|
output.uv = TRANSFORM_TEX(input.uv, _BaseMap);
|
|
output.color = input.color;
|
|
output.vertexID = input.vertexID;
|
|
|
|
// Calculate fur vector in world space
|
|
float3 furVectorOS = CalculateFurVector(input.normalOS, input.tangentOS, input.uv, input.color, false);
|
|
output.furVector = TransformObjectToWorldDir(furVectorOS, false);
|
|
|
|
// Apply fur length mask
|
|
float furLengthMask = SAMPLE_TEXTURE2D_LOD(_FurLengthMask, sampler_FurLengthMask, input.uv * _FurLengthMask_ST.xy + _FurLengthMask_ST.zw, 0).r;
|
|
output.furVector *= furLengthMask;
|
|
|
|
// Note: Perspective Removal and Z offset will be applied in geometry shader
|
|
// We don't apply them here in vertex shader for fur shells
|
|
// because geometry shader generates multiple shells and needs to apply
|
|
// the transformations consistently to all generated vertices
|
|
|
|
// Fog
|
|
float4 posCS = TransformWorldToHClip(output.positionWS);
|
|
output.fogFactor = ComputeFogFactor(posCS.z);
|
|
|
|
return output;
|
|
}
|
|
#endif
|
|
|
|
#endif // NILOTOON_CHARACTER_FUR_SHARED_INCLUDED
|