Files
Emberwild/Assets/GAME/Shaders/StylizedLeaves.shader
T
2026-06-22 16:18:34 +02:00

516 lines
21 KiB
Plaintext

Shader "GAME/StylizedLeaves"
{
Properties
{
[Header(Surface)][Space]
_MainTex("Leaf Albedo (alpha = mask)", 2D) = "white" {}
[Normal] _NormalMap("Normal Map", 2D) = "bump" {}
_NormalStrength("Normal Strength", Range(0,2)) = 1
_NormalSphereBlend("Canopy Sphere Normal (puffy)", Range(0,1)) = 0.7
[Toggle(_MASKMAP)] _UseMaskMap("Use Mask Map (R:Metallic G:AO A:Smooth)", Float) = 0
_MaskMap("Mask Map", 2D) = "white" {}
_Smoothness("Smoothness", Range(0,1)) = 0.15
_Metallic("Metallic", Range(0,1)) = 0
_Occlusion("Occlusion", Range(0,1)) = 1
_Cutoff("Alpha Cutoff", Range(0,1)) = 0.5
[Header(Stylized Lighting)][Space]
_ShadowLift("Shadow Lift (lighten shadows)", Range(0,0.6)) = 0.25
[HDR] _TranslucencyColor("Translucency Color", Color) = (0.35,0.65,0.18,1)
_TranslucencyStrength("Translucency Strength", Range(0,3)) = 1.2
_TranslucencyPower("Translucency Power", Range(1,16)) = 4
[Header(Season Color A and B per season for variation)][Space]
_LeafVariation("Per-Leaf Variation Scale", Float) = 0.3
_TextureColorInfluence("Texture Color Influence (0 = season drives color)", Range(0,1)) = 0
[HDR] _SummerColorA("Summer A", Color) = (0.22,0.50,0.14,1)
[HDR] _SummerColorB("Summer B", Color) = (0.34,0.62,0.18,1)
[HDR] _AutumnColorA("Autumn A", Color) = (0.78,0.34,0.08,1)
[HDR] _AutumnColorB("Autumn B", Color) = (0.85,0.58,0.14,1)
[HDR] _WinterColorA("Winter A (dry)", Color) = (0.40,0.30,0.18,1)
[HDR] _WinterColorB("Winter B (dry)", Color) = (0.52,0.42,0.28,1)
_WinterThinning("Winter Thinning (leaves fall)", Range(0,1)) = 0.4
[Header(Wind canopy sway)][Space]
_WindDirection("Wind Direction (xy)", Vector) = (1,0,0,0)
_WindStrength("Sway Strength", Float) = 0.15
_WindSpeed("Sway Speed", Float) = 1.2
_WindFrequency("Sway Frequency", Float) = 0.3
_WindHeight("Sway Height Mask", Float) = 3
_WindWinterStiffness("Winter Wind Stiffness", Range(0,1)) = 0.5
[Header(Wind leaf flutter)][Space]
_FlutterStrength("Flutter Strength", Float) = 0.05
_FlutterSpeed("Flutter Speed", Float) = 6
_FlutterFreq("Flutter Frequency", Float) = 2
[Header(Rendering)][Space]
[Enum(UnityEngine.Rendering.CullMode)] _Cull("Cull (Off = double sided)", Float) = 0
}
SubShader
{
Tags
{
"RenderType" = "Opaque"
"RenderPipeline" = "UniversalPipeline"
"Queue" = "AlphaTest"
"UniversalMaterialType" = "Lit"
}
// =================================================================================
// ForwardLit
// =================================================================================
Pass
{
Name "ForwardLit"
Tags { "LightMode" = "UniversalForward" }
Cull [_Cull]
ZWrite On
ZTest LEqual
HLSLPROGRAM
#pragma target 3.0
#pragma vertex LeafForwardVertex
#pragma fragment LeafForwardFragment
#pragma shader_feature_local _NORMALMAP
#pragma shader_feature_local _MASKMAP
#pragma multi_compile _ _MAIN_LIGHT_SHADOWS _MAIN_LIGHT_SHADOWS_CASCADE _MAIN_LIGHT_SHADOWS_SCREEN
#pragma multi_compile _ _ADDITIONAL_LIGHTS_VERTEX _ADDITIONAL_LIGHTS
#pragma multi_compile _ EVALUATE_SH_MIXED EVALUATE_SH_VERTEX
#pragma multi_compile_fragment _ _ADDITIONAL_LIGHT_SHADOWS
#pragma multi_compile_fragment _ _REFLECTION_PROBE_BLENDING
#pragma multi_compile_fragment _ _REFLECTION_PROBE_BOX_PROJECTION
#pragma multi_compile_fragment _ _REFLECTION_PROBE_ATLAS
#pragma multi_compile_fragment _ _SHADOWS_SOFT _SHADOWS_SOFT_LOW _SHADOWS_SOFT_MEDIUM _SHADOWS_SOFT_HIGH
#pragma multi_compile_fragment _ _SCREEN_SPACE_OCCLUSION
#pragma multi_compile_fragment _ _LIGHT_COOKIES
#pragma multi_compile _ _LIGHT_LAYERS
#pragma multi_compile _ _CLUSTER_LIGHT_LOOP
#pragma multi_compile _ LIGHTMAP_SHADOW_MIXING
#pragma multi_compile _ SHADOWS_SHADOWMASK
#pragma multi_compile _ DIRLIGHTMAP_COMBINED
#pragma multi_compile _ LIGHTMAP_ON
#pragma multi_compile_fog
#pragma multi_compile_instancing
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"
#include "StylizedLeavesCommon.hlsl"
struct Attributes
{
float4 positionOS : POSITION;
float3 normalOS : NORMAL;
float4 tangentOS : TANGENT;
float2 uv : TEXCOORD0;
float2 staticLightmapUV : TEXCOORD1;
UNITY_VERTEX_INPUT_INSTANCE_ID
};
struct Varyings
{
float4 positionCS : SV_POSITION;
float2 uv : TEXCOORD0;
float3 positionWS : TEXCOORD1;
float3 positionOS : TEXCOORD2;
half3 normalWS : TEXCOORD3;
half4 tangentWS : TEXCOORD4;
DECLARE_LIGHTMAP_OR_SH(staticLightmapUV, vertexSH, 5);
float fogFactor : TEXCOORD6;
UNITY_VERTEX_INPUT_INSTANCE_ID
UNITY_VERTEX_OUTPUT_STEREO
};
Varyings LeafForwardVertex(Attributes IN)
{
Varyings OUT = (Varyings)0;
UNITY_SETUP_INSTANCE_ID(IN);
UNITY_TRANSFER_INSTANCE_ID(IN, OUT);
UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(OUT);
float3 positionWS = TransformObjectToWorld(IN.positionOS.xyz);
positionWS = LeafApplyWind(positionWS, IN.positionOS.xyz);
VertexNormalInputs normalInput = GetVertexNormalInputs(IN.normalOS, IN.tangentOS);
OUT.positionWS = positionWS;
OUT.positionOS = IN.positionOS.xyz;
OUT.positionCS = TransformWorldToHClip(positionWS);
OUT.uv = TRANSFORM_TEX(IN.uv, _MainTex);
OUT.normalWS = normalInput.normalWS;
real sign = IN.tangentOS.w * GetOddNegativeScale();
OUT.tangentWS = half4(normalInput.tangentWS, sign);
OUT.fogFactor = ComputeFogFactor(OUT.positionCS.z);
OUTPUT_LIGHTMAP_UV(IN.staticLightmapUV, unity_LightmapST, OUT.staticLightmapUV);
OUTPUT_SH(OUT.normalWS, OUT.vertexSH);
return OUT;
}
half4 LeafForwardFragment(Varyings IN, FRONT_FACE_TYPE faceSign : FRONT_FACE_SEMANTIC) : SV_Target
{
UNITY_SETUP_INSTANCE_ID(IN);
UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(IN);
half alpha = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, IN.uv).a;
clip(LeafAlphaTest(alpha, IN.positionWS));
half metallic = _Metallic;
half smoothness = _Smoothness;
half occlusion = _Occlusion;
#ifdef _MASKMAP
half4 mask = SAMPLE_TEXTURE2D(_MaskMap, sampler_MaskMap, IN.uv);
metallic *= mask.r;
occlusion *= mask.g;
smoothness *= mask.a;
#endif
half3 normalWS = normalize(IN.normalWS);
#ifdef _NORMALMAP
half3 normalTS = UnpackNormalScale(
SAMPLE_TEXTURE2D(_NormalMap, sampler_NormalMap, IN.uv), _NormalStrength);
float sgn = IN.tangentWS.w;
float3 bitangent = sgn * cross(normalWS, IN.tangentWS.xyz);
half3x3 tbn = half3x3(IN.tangentWS.xyz, bitangent, normalWS);
normalWS = normalize(TransformTangentToWorld(normalTS, tbn));
#endif
normalWS *= IS_FRONT_VFACE(faceSign, 1.0, -1.0);
// Normale sphérique (canopée puffy) : direction depuis le centre de l'objet.
half3 sphereN = normalize(TransformObjectToWorldNormal(IN.positionOS));
normalWS = normalize(lerp(normalWS, sphereN, _NormalSphereBlend));
half3 albedo = LeafColor(IN.uv, IN.positionWS);
InputData inputData = (InputData)0;
inputData.positionWS = IN.positionWS;
inputData.normalWS = normalWS;
inputData.viewDirectionWS = normalize(GetWorldSpaceViewDir(IN.positionWS));
inputData.shadowCoord = TransformWorldToShadowCoord(IN.positionWS);
inputData.fogCoord = IN.fogFactor;
inputData.bakedGI = SAMPLE_GI(IN.staticLightmapUV, IN.vertexSH, normalWS);
inputData.normalizedScreenSpaceUV = GetNormalizedScreenSpaceUV(IN.positionCS);
inputData.shadowMask = SAMPLE_SHADOWMASK(IN.staticLightmapUV);
SurfaceData surfaceData = (SurfaceData)0;
surfaceData.albedo = albedo;
surfaceData.metallic = metallic;
surfaceData.smoothness = smoothness;
surfaceData.occlusion = occlusion;
surfaceData.normalTS = half3(0, 0, 1);
surfaceData.alpha = 1.0;
half4 color = UniversalFragmentPBR(inputData, surfaceData);
// Translucency (lumière qui traverse la feuille, à contre-jour).
Light mainLight = GetMainLight(inputData.shadowCoord, inputData.positionWS, inputData.shadowMask);
half trans = pow(saturate(dot(inputData.viewDirectionWS, -mainLight.direction)), _TranslucencyPower);
half lightAtten = mainLight.shadowAttenuation * mainLight.distanceAttenuation;
color.rgb += albedo * _TranslucencyColor.rgb * (_TranslucencyStrength * trans * lightAtten) * mainLight.color;
// Shadow lift : garde la couleur des feuilles à l'ombre.
color.rgb = max(color.rgb, albedo * _ShadowLift);
color.rgb = MixFog(color.rgb, inputData.fogCoord);
color.a = 1.0;
return color;
}
ENDHLSL
}
// =================================================================================
// ShadowCaster
// =================================================================================
Pass
{
Name "ShadowCaster"
Tags { "LightMode" = "ShadowCaster" }
ZWrite On
ZTest LEqual
Cull [_Cull]
ColorMask 0
HLSLPROGRAM
#pragma target 3.0
#pragma vertex LeafShadowVertex
#pragma fragment LeafShadowFragment
#pragma multi_compile_vertex _ _CASTING_PUNCTUAL_LIGHT_SHADOW
#pragma multi_compile_instancing
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Shadows.hlsl"
#include "StylizedLeavesCommon.hlsl"
float3 _LightDirection;
float3 _LightPosition;
struct Attributes
{
float4 positionOS : POSITION;
float3 normalOS : NORMAL;
float2 uv : TEXCOORD0;
UNITY_VERTEX_INPUT_INSTANCE_ID
};
struct Varyings
{
float4 positionCS : SV_POSITION;
float2 uv : TEXCOORD0;
float3 positionWS : TEXCOORD1;
UNITY_VERTEX_INPUT_INSTANCE_ID
};
float4 GetShadowClipPos(float3 positionWS, float3 normalWS)
{
#if _CASTING_PUNCTUAL_LIGHT_SHADOW
float3 lightDirectionWS = normalize(_LightPosition - positionWS);
#else
float3 lightDirectionWS = _LightDirection;
#endif
float4 positionCS = TransformWorldToHClip(ApplyShadowBias(positionWS, normalWS, lightDirectionWS));
#if UNITY_REVERSED_Z
positionCS.z = min(positionCS.z, UNITY_NEAR_CLIP_VALUE);
#else
positionCS.z = max(positionCS.z, UNITY_NEAR_CLIP_VALUE);
#endif
return positionCS;
}
Varyings LeafShadowVertex(Attributes IN)
{
Varyings OUT = (Varyings)0;
UNITY_SETUP_INSTANCE_ID(IN);
UNITY_TRANSFER_INSTANCE_ID(IN, OUT);
float3 positionWS = TransformObjectToWorld(IN.positionOS.xyz);
positionWS = LeafApplyWind(positionWS, IN.positionOS.xyz);
float3 normalWS = TransformObjectToWorldNormal(IN.normalOS);
OUT.positionWS = positionWS;
OUT.positionCS = GetShadowClipPos(positionWS, normalWS);
OUT.uv = TRANSFORM_TEX(IN.uv, _MainTex);
return OUT;
}
half4 LeafShadowFragment(Varyings IN) : SV_Target
{
UNITY_SETUP_INSTANCE_ID(IN);
half alpha = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, IN.uv).a;
clip(LeafAlphaTest(alpha, IN.positionWS));
return 0;
}
ENDHLSL
}
// =================================================================================
// DepthOnly
// =================================================================================
Pass
{
Name "DepthOnly"
Tags { "LightMode" = "DepthOnly" }
ZWrite On
ColorMask R
Cull [_Cull]
HLSLPROGRAM
#pragma target 3.0
#pragma vertex LeafDepthVertex
#pragma fragment LeafDepthFragment
#pragma multi_compile_instancing
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
#include "StylizedLeavesCommon.hlsl"
struct Attributes
{
float4 positionOS : POSITION;
float2 uv : TEXCOORD0;
UNITY_VERTEX_INPUT_INSTANCE_ID
};
struct Varyings
{
float4 positionCS : SV_POSITION;
float2 uv : TEXCOORD0;
float3 positionWS : TEXCOORD1;
UNITY_VERTEX_INPUT_INSTANCE_ID
UNITY_VERTEX_OUTPUT_STEREO
};
Varyings LeafDepthVertex(Attributes IN)
{
Varyings OUT = (Varyings)0;
UNITY_SETUP_INSTANCE_ID(IN);
UNITY_TRANSFER_INSTANCE_ID(IN, OUT);
UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(OUT);
float3 positionWS = TransformObjectToWorld(IN.positionOS.xyz);
positionWS = LeafApplyWind(positionWS, IN.positionOS.xyz);
OUT.positionWS = positionWS;
OUT.positionCS = TransformWorldToHClip(positionWS);
OUT.uv = TRANSFORM_TEX(IN.uv, _MainTex);
return OUT;
}
half4 LeafDepthFragment(Varyings IN) : SV_Target
{
UNITY_SETUP_INSTANCE_ID(IN);
half alpha = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, IN.uv).a;
clip(LeafAlphaTest(alpha, IN.positionWS));
return 0;
}
ENDHLSL
}
// =================================================================================
// DepthNormals
// =================================================================================
Pass
{
Name "DepthNormals"
Tags { "LightMode" = "DepthNormals" }
ZWrite On
Cull [_Cull]
HLSLPROGRAM
#pragma target 3.0
#pragma vertex LeafDepthNormalsVertex
#pragma fragment LeafDepthNormalsFragment
#pragma shader_feature_local _NORMALMAP
#pragma multi_compile_instancing
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"
#include "StylizedLeavesCommon.hlsl"
struct Attributes
{
float4 positionOS : POSITION;
float3 normalOS : NORMAL;
float4 tangentOS : TANGENT;
float2 uv : TEXCOORD0;
UNITY_VERTEX_INPUT_INSTANCE_ID
};
struct Varyings
{
float4 positionCS : SV_POSITION;
float2 uv : TEXCOORD0;
float3 positionOS : TEXCOORD1;
half3 normalWS : TEXCOORD2;
half4 tangentWS : TEXCOORD3;
float3 positionWS : TEXCOORD4;
UNITY_VERTEX_INPUT_INSTANCE_ID
UNITY_VERTEX_OUTPUT_STEREO
};
Varyings LeafDepthNormalsVertex(Attributes IN)
{
Varyings OUT = (Varyings)0;
UNITY_SETUP_INSTANCE_ID(IN);
UNITY_TRANSFER_INSTANCE_ID(IN, OUT);
UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(OUT);
float3 positionWS = TransformObjectToWorld(IN.positionOS.xyz);
positionWS = LeafApplyWind(positionWS, IN.positionOS.xyz);
VertexNormalInputs normalInput = GetVertexNormalInputs(IN.normalOS, IN.tangentOS);
OUT.positionCS = TransformWorldToHClip(positionWS);
OUT.uv = TRANSFORM_TEX(IN.uv, _MainTex);
OUT.positionOS = IN.positionOS.xyz;
OUT.positionWS = positionWS;
OUT.normalWS = normalInput.normalWS;
real sign = IN.tangentOS.w * GetOddNegativeScale();
OUT.tangentWS = half4(normalInput.tangentWS, sign);
return OUT;
}
half4 LeafDepthNormalsFragment(Varyings IN, FRONT_FACE_TYPE faceSign : FRONT_FACE_SEMANTIC) : SV_Target
{
UNITY_SETUP_INSTANCE_ID(IN);
half alpha = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, IN.uv).a;
clip(LeafAlphaTest(alpha, IN.positionWS));
half3 normalWS = normalize(IN.normalWS);
#ifdef _NORMALMAP
half3 normalTS = UnpackNormalScale(
SAMPLE_TEXTURE2D(_NormalMap, sampler_NormalMap, IN.uv), _NormalStrength);
float sgn = IN.tangentWS.w;
float3 bitangent = sgn * cross(normalWS, IN.tangentWS.xyz);
half3x3 tbn = half3x3(IN.tangentWS.xyz, bitangent, normalWS);
normalWS = normalize(TransformTangentToWorld(normalTS, tbn));
#endif
normalWS *= IS_FRONT_VFACE(faceSign, 1.0, -1.0);
half3 sphereN = normalize(TransformObjectToWorldNormal(IN.positionOS));
normalWS = normalize(lerp(normalWS, sphereN, _NormalSphereBlend));
return half4(NormalizeNormalPerPixel(normalWS), 0.0);
}
ENDHLSL
}
// =================================================================================
// Meta (lightmapping)
// =================================================================================
Pass
{
Name "Meta"
Tags { "LightMode" = "Meta" }
Cull Off
HLSLPROGRAM
#pragma target 3.0
#pragma vertex LeafMetaVertex
#pragma fragment LeafMetaFragment
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/MetaInput.hlsl"
#include "StylizedLeavesCommon.hlsl"
struct Attributes
{
float4 positionOS : POSITION;
float2 uv0 : TEXCOORD0;
float2 uv1 : TEXCOORD1;
float2 uv2 : TEXCOORD2;
};
struct Varyings
{
float4 positionCS : SV_POSITION;
float2 uv : TEXCOORD0;
};
Varyings LeafMetaVertex(Attributes IN)
{
Varyings OUT = (Varyings)0;
OUT.positionCS = UnityMetaVertexPosition(IN.positionOS.xyz, IN.uv1, IN.uv2);
OUT.uv = TRANSFORM_TEX(IN.uv0, _MainTex);
return OUT;
}
half4 LeafMetaFragment(Varyings IN) : SV_Target
{
half4 baseSample = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, IN.uv);
clip(baseSample.a - _Cutoff);
MetaInput metaInput = (MetaInput)0;
metaInput.Albedo = baseSample.rgb * _SummerColorA.rgb;
metaInput.Emission = 0;
return UnityMetaFragment(metaInput);
}
ENDHLSL
}
}
FallBack "Universal Render Pipeline/Lit"
}