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" }