97ac0f71f5
https://assetstore.unity.com/packages/tools/generative-ai/synaptic-ai-pro-natural-language-control-for-unity-336030
875 lines
32 KiB
Plaintext
875 lines
32 KiB
Plaintext
Shader "Synaptic/GrassPro"
|
|
{
|
|
Properties
|
|
{
|
|
[Header(Base)]
|
|
_MainTex ("Albedo", 2D) = "white" {}
|
|
_BaseColor ("Base Color", Color) = (0.2, 0.6, 0.2, 1)
|
|
_TipColor ("Tip Color", Color) = (0.5, 0.9, 0.3, 1)
|
|
_GradientPower ("Gradient Power", Range(0.1, 3)) = 1
|
|
|
|
[Header(Wind Animation)]
|
|
[Toggle(_WIND_ON)] _WindEnabled ("Enable Wind", Float) = 1
|
|
_WindStrength ("Wind Strength", Range(0, 2)) = 0.5
|
|
_WindSpeed ("Wind Speed", Float) = 1
|
|
_WindFrequency ("Wind Frequency", Float) = 1
|
|
_WindDirection ("Wind Direction", Vector) = (1, 0, 0.5, 0)
|
|
_WindNoiseTex ("Wind Noise", 2D) = "grey" {}
|
|
_WindNoiseScale ("Wind Noise Scale", Float) = 0.1
|
|
_WindGustStrength ("Gust Strength", Range(0, 2)) = 0.3
|
|
_WindGustFrequency ("Gust Frequency", Float) = 0.5
|
|
|
|
[Header(Player Interaction)]
|
|
[Toggle(_INTERACTION_ON)] _InteractionEnabled ("Enable Interaction", Float) = 1
|
|
_InteractionRadius ("Interaction Radius", Float) = 2
|
|
_InteractionStrength ("Interaction Strength", Range(0, 2)) = 1
|
|
_InteractionFalloff ("Interaction Falloff", Range(0.1, 5)) = 2
|
|
|
|
[Header(Subsurface Scattering)]
|
|
[Toggle(_SSS_ON)] _SSSEnabled ("Enable SSS", Float) = 1
|
|
_SSSColor ("SSS Color", Color) = (0.8, 1.0, 0.5, 1)
|
|
_SSSStrength ("SSS Strength", Range(0, 2)) = 1
|
|
_SSSDistortion ("SSS Distortion", Range(0, 1)) = 0.5
|
|
_SSSPower ("SSS Power", Range(1, 16)) = 4
|
|
|
|
[Header(Detail)]
|
|
_AO ("Ambient Occlusion", Range(0, 1)) = 0.5
|
|
_AOPower ("AO Power", Range(0.1, 3)) = 1
|
|
_Roughness ("Roughness", Range(0, 1)) = 0.8
|
|
|
|
[Header(Specular)]
|
|
[Toggle(_SPECULAR_ON)] _SpecularEnabled ("Enable Specular", Float) = 1
|
|
_SpecularColor ("Specular Color", Color) = (1, 1, 0.8, 1)
|
|
_SpecularIntensity ("Specular Intensity", Range(0, 3)) = 0.5
|
|
_SpecularPower ("Specular Power", Range(1, 128)) = 32
|
|
|
|
[Header(Distance Fade)]
|
|
[Toggle(_DISTANCE_FADE_ON)] _DistanceFadeEnabled ("Enable Distance Fade", Float) = 1
|
|
_FadeStart ("Fade Start", Float) = 30
|
|
_FadeEnd ("Fade End", Float) = 50
|
|
_FadeMinScale ("Fade Min Scale", Range(0, 1)) = 0.3
|
|
|
|
[Header(Cutout)]
|
|
_Cutoff ("Alpha Cutoff", Range(0, 1)) = 0.5
|
|
|
|
[Header(Rendering)]
|
|
[Enum(UnityEngine.Rendering.CullMode)] _Cull ("Cull Mode", Float) = 0
|
|
}
|
|
|
|
SubShader
|
|
{
|
|
PackageRequirements { "com.unity.render-pipelines.universal" }
|
|
Tags
|
|
{
|
|
"RenderType" = "TransparentCutout"
|
|
"Queue" = "AlphaTest"
|
|
"RenderPipeline" = "UniversalPipeline"
|
|
}
|
|
|
|
Pass
|
|
{
|
|
Name "GrassForward"
|
|
Tags { "LightMode" = "UniversalForward" }
|
|
|
|
Cull [_Cull]
|
|
AlphaToMask On
|
|
|
|
HLSLPROGRAM
|
|
#pragma target 4.5
|
|
#pragma vertex vert
|
|
#pragma fragment frag
|
|
|
|
#pragma multi_compile _ _MAIN_LIGHT_SHADOWS _MAIN_LIGHT_SHADOWS_CASCADE
|
|
#pragma multi_compile_fragment _ _SHADOWS_SOFT
|
|
#pragma multi_compile _ _ADDITIONAL_LIGHTS
|
|
#pragma multi_compile_fog
|
|
#pragma multi_compile_instancing
|
|
|
|
#pragma shader_feature_local _WIND_ON
|
|
#pragma shader_feature_local _INTERACTION_ON
|
|
#pragma shader_feature_local _SSS_ON
|
|
#pragma shader_feature_local _SPECULAR_ON
|
|
#pragma shader_feature_local _DISTANCE_FADE_ON
|
|
|
|
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
|
|
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"
|
|
|
|
TEXTURE2D(_MainTex);
|
|
TEXTURE2D(_WindNoiseTex);
|
|
SAMPLER(sampler_MainTex);
|
|
SAMPLER(sampler_WindNoiseTex);
|
|
|
|
// Interaction positions (set from script)
|
|
float4 _InteractionPositions[16];
|
|
int _InteractionCount;
|
|
|
|
CBUFFER_START(UnityPerMaterial)
|
|
float4 _MainTex_ST;
|
|
float4 _BaseColor;
|
|
float4 _TipColor;
|
|
float _GradientPower;
|
|
|
|
float _WindStrength;
|
|
float _WindSpeed;
|
|
float _WindFrequency;
|
|
float4 _WindDirection;
|
|
float4 _WindNoiseTex_ST;
|
|
float _WindNoiseScale;
|
|
float _WindGustStrength;
|
|
float _WindGustFrequency;
|
|
|
|
float _InteractionRadius;
|
|
float _InteractionStrength;
|
|
float _InteractionFalloff;
|
|
|
|
float4 _SSSColor;
|
|
float _SSSStrength;
|
|
float _SSSDistortion;
|
|
float _SSSPower;
|
|
|
|
float _AO;
|
|
float _AOPower;
|
|
float _Roughness;
|
|
|
|
float4 _SpecularColor;
|
|
float _SpecularIntensity;
|
|
float _SpecularPower;
|
|
|
|
float _FadeStart;
|
|
float _FadeEnd;
|
|
float _FadeMinScale;
|
|
|
|
float _Cutoff;
|
|
CBUFFER_END
|
|
|
|
struct Attributes
|
|
{
|
|
float4 positionOS : POSITION;
|
|
float3 normalOS : NORMAL;
|
|
float2 uv : TEXCOORD0;
|
|
float4 color : COLOR; // R = height, G = AO, B = unused, A = stiffness
|
|
UNITY_VERTEX_INPUT_INSTANCE_ID
|
|
};
|
|
|
|
struct Varyings
|
|
{
|
|
float4 positionCS : SV_POSITION;
|
|
float2 uv : TEXCOORD0;
|
|
float3 worldPos : TEXCOORD1;
|
|
float3 worldNormal : TEXCOORD2;
|
|
float4 vertexColor : TEXCOORD3;
|
|
float4 shadowCoord : TEXCOORD4;
|
|
float fogFactor : TEXCOORD5;
|
|
float heightGradient : TEXCOORD6;
|
|
UNITY_VERTEX_INPUT_INSTANCE_ID
|
|
};
|
|
|
|
// Wind functions
|
|
float3 WindAnimation(float3 worldPos, float height, float stiffness, float time)
|
|
{
|
|
#if defined(_WIND_ON)
|
|
float3 windDir = normalize(_WindDirection.xyz);
|
|
|
|
// Sample wind noise
|
|
float2 noiseUV = worldPos.xz * _WindNoiseScale + time * _WindSpeed * 0.1;
|
|
float noise = SAMPLE_TEXTURE2D_LOD(_WindNoiseTex, sampler_WindNoiseTex, noiseUV, 0).r;
|
|
|
|
// Main wind wave
|
|
float windPhase = dot(worldPos.xz, windDir.xz) * _WindFrequency + time * _WindSpeed;
|
|
float wave = sin(windPhase) * 0.5 + 0.5;
|
|
|
|
// Gust
|
|
float gustPhase = time * _WindGustFrequency;
|
|
float gust = sin(gustPhase) * sin(gustPhase * 2.3) * _WindGustStrength;
|
|
|
|
// Combined wind
|
|
float windFactor = (wave + gust + noise - 0.5) * _WindStrength;
|
|
windFactor *= height * height; // Quadratic falloff from root
|
|
windFactor *= (1 - stiffness); // Stiffness reduces wind effect
|
|
|
|
return windDir * windFactor;
|
|
#else
|
|
return float3(0, 0, 0);
|
|
#endif
|
|
}
|
|
|
|
// Player interaction
|
|
float3 InteractionDisplacement(float3 worldPos, float height)
|
|
{
|
|
#if defined(_INTERACTION_ON)
|
|
float3 totalDisplacement = float3(0, 0, 0);
|
|
|
|
for (int i = 0; i < _InteractionCount && i < 16; i++)
|
|
{
|
|
float3 interactorPos = _InteractionPositions[i].xyz;
|
|
float3 toGrass = worldPos - interactorPos;
|
|
toGrass.y = 0;
|
|
|
|
float dist = length(toGrass);
|
|
float influence = 1 - saturate(pow(dist / _InteractionRadius, _InteractionFalloff));
|
|
|
|
if (influence > 0.001)
|
|
{
|
|
float3 pushDir = normalize(toGrass + float3(0.001, 0, 0.001));
|
|
totalDisplacement += pushDir * influence * _InteractionStrength * height;
|
|
}
|
|
}
|
|
|
|
return totalDisplacement;
|
|
#else
|
|
return float3(0, 0, 0);
|
|
#endif
|
|
}
|
|
|
|
Varyings vert(Attributes IN)
|
|
{
|
|
Varyings OUT;
|
|
UNITY_SETUP_INSTANCE_ID(IN);
|
|
UNITY_TRANSFER_INSTANCE_ID(IN, OUT);
|
|
|
|
float height = IN.color.r; // Height along blade (0 = root, 1 = tip)
|
|
float stiffness = IN.color.a;
|
|
float time = _Time.y;
|
|
|
|
float3 posOS = IN.positionOS.xyz;
|
|
float3 worldPosBase = TransformObjectToWorld(float3(0, 0, 0));
|
|
|
|
// Distance fade
|
|
#if defined(_DISTANCE_FADE_ON)
|
|
float distToCam = distance(worldPosBase, _WorldSpaceCameraPos);
|
|
float fadeFactor = saturate((distToCam - _FadeStart) / (_FadeEnd - _FadeStart));
|
|
float scale = lerp(1, _FadeMinScale, fadeFactor);
|
|
posOS *= scale;
|
|
#endif
|
|
|
|
float3 worldPos = TransformObjectToWorld(posOS);
|
|
|
|
// Apply wind
|
|
float3 windOffset = WindAnimation(worldPos, height, stiffness, time);
|
|
worldPos += windOffset;
|
|
|
|
// Apply interaction
|
|
float3 interactOffset = InteractionDisplacement(worldPos, height);
|
|
worldPos += interactOffset;
|
|
|
|
OUT.worldPos = worldPos;
|
|
OUT.positionCS = TransformWorldToHClip(worldPos);
|
|
OUT.uv = TRANSFORM_TEX(IN.uv, _MainTex);
|
|
OUT.worldNormal = TransformObjectToWorldNormal(IN.normalOS);
|
|
OUT.vertexColor = IN.color;
|
|
OUT.shadowCoord = TransformWorldToShadowCoord(worldPos);
|
|
OUT.fogFactor = ComputeFogFactor(OUT.positionCS.z);
|
|
OUT.heightGradient = height;
|
|
|
|
return OUT;
|
|
}
|
|
|
|
// SSS function
|
|
float3 SubsurfaceScattering(float3 viewDir, float3 lightDir, float3 normal, float3 lightColor)
|
|
{
|
|
#if defined(_SSS_ON)
|
|
float3 H = normalize(lightDir + normal * _SSSDistortion);
|
|
float VdotH = pow(saturate(dot(viewDir, -H)), _SSSPower);
|
|
return _SSSColor.rgb * VdotH * _SSSStrength * lightColor;
|
|
#else
|
|
return float3(0, 0, 0);
|
|
#endif
|
|
}
|
|
|
|
float4 frag(Varyings IN) : SV_Target
|
|
{
|
|
UNITY_SETUP_INSTANCE_ID(IN);
|
|
|
|
// Sample texture
|
|
float4 texColor = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, IN.uv);
|
|
clip(texColor.a - _Cutoff);
|
|
|
|
float3 viewDir = normalize(_WorldSpaceCameraPos - IN.worldPos);
|
|
float3 normal = normalize(IN.worldNormal);
|
|
|
|
// Height-based color gradient
|
|
float gradientFactor = pow(IN.heightGradient, _GradientPower);
|
|
float3 albedo = lerp(_BaseColor.rgb, _TipColor.rgb, gradientFactor) * texColor.rgb;
|
|
|
|
// Ambient occlusion from vertex color
|
|
float ao = lerp(1, IN.vertexColor.g, _AO);
|
|
ao = pow(ao, _AOPower);
|
|
|
|
// Lighting
|
|
Light mainLight = GetMainLight(IN.shadowCoord);
|
|
float3 lightDir = mainLight.direction;
|
|
float3 lightColor = mainLight.color;
|
|
float shadow = mainLight.shadowAttenuation;
|
|
|
|
// Wrapped diffuse for softer look
|
|
float NdotL = dot(normal, lightDir);
|
|
float wrappedNdotL = NdotL * 0.5 + 0.5;
|
|
float3 diffuse = albedo * lightColor * wrappedNdotL * shadow;
|
|
|
|
// SSS
|
|
float3 sss = SubsurfaceScattering(viewDir, lightDir, normal, lightColor);
|
|
sss *= (1 - IN.heightGradient) * shadow; // More SSS at base
|
|
|
|
// Specular
|
|
float3 specular = float3(0, 0, 0);
|
|
#if defined(_SPECULAR_ON)
|
|
float3 halfDir = normalize(lightDir + viewDir);
|
|
float NdotH = saturate(dot(normal, halfDir));
|
|
float spec = pow(NdotH, _SpecularPower) * _SpecularIntensity;
|
|
specular = _SpecularColor.rgb * spec * shadow * IN.heightGradient; // More specular at tip
|
|
#endif
|
|
|
|
// Additional lights
|
|
float3 additionalLights = float3(0, 0, 0);
|
|
#if defined(_ADDITIONAL_LIGHTS)
|
|
uint pixelLightCount = GetAdditionalLightsCount();
|
|
for (uint i = 0; i < pixelLightCount; i++)
|
|
{
|
|
Light light = GetAdditionalLight(i, IN.worldPos);
|
|
float addNdotL = saturate(dot(normal, light.direction));
|
|
additionalLights += albedo * light.color * light.distanceAttenuation * addNdotL * 0.5;
|
|
}
|
|
#endif
|
|
|
|
// Ambient
|
|
float3 ambient = albedo * 0.1;
|
|
|
|
// Combine
|
|
float3 finalColor = (diffuse + sss + specular + additionalLights + ambient) * ao;
|
|
|
|
// Fog
|
|
finalColor = MixFog(finalColor, IN.fogFactor);
|
|
|
|
return float4(finalColor, texColor.a);
|
|
}
|
|
ENDHLSL
|
|
}
|
|
|
|
// Shadow caster pass
|
|
Pass
|
|
{
|
|
Name "ShadowCaster"
|
|
Tags { "LightMode" = "ShadowCaster" }
|
|
|
|
ZWrite On
|
|
ZTest LEqual
|
|
ColorMask 0
|
|
Cull Off
|
|
|
|
HLSLPROGRAM
|
|
#pragma target 4.5
|
|
#pragma vertex ShadowVert
|
|
#pragma fragment ShadowFrag
|
|
|
|
#pragma multi_compile_instancing
|
|
#pragma shader_feature_local _WIND_ON
|
|
#pragma shader_feature_local _DISTANCE_FADE_ON
|
|
|
|
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
|
|
|
|
float3 _LightDirection;
|
|
|
|
float3 ApplyShadowBiasCustom(float3 positionWS, float3 normalWS, float3 lightDirection)
|
|
{
|
|
float invNdotL = 1.0 - saturate(dot(lightDirection, normalWS));
|
|
float scale = invNdotL * 0.001;
|
|
positionWS = lightDirection * 0.001 + positionWS;
|
|
positionWS = normalWS * scale.xxx + positionWS;
|
|
return positionWS;
|
|
}
|
|
|
|
TEXTURE2D(_MainTex);
|
|
TEXTURE2D(_WindNoiseTex);
|
|
SAMPLER(sampler_MainTex);
|
|
SAMPLER(sampler_WindNoiseTex);
|
|
|
|
CBUFFER_START(UnityPerMaterial)
|
|
float4 _MainTex_ST;
|
|
float _WindStrength;
|
|
float _WindSpeed;
|
|
float _WindFrequency;
|
|
float4 _WindDirection;
|
|
float _WindNoiseScale;
|
|
float _WindGustStrength;
|
|
float _WindGustFrequency;
|
|
float _FadeStart;
|
|
float _FadeEnd;
|
|
float _FadeMinScale;
|
|
float _Cutoff;
|
|
CBUFFER_END
|
|
|
|
struct Attributes
|
|
{
|
|
float4 positionOS : POSITION;
|
|
float3 normalOS : NORMAL;
|
|
float2 uv : TEXCOORD0;
|
|
float4 color : COLOR;
|
|
UNITY_VERTEX_INPUT_INSTANCE_ID
|
|
};
|
|
|
|
struct Varyings
|
|
{
|
|
float4 positionCS : SV_POSITION;
|
|
float2 uv : TEXCOORD0;
|
|
UNITY_VERTEX_INPUT_INSTANCE_ID
|
|
};
|
|
|
|
float3 WindAnimation(float3 worldPos, float height, float stiffness, float time)
|
|
{
|
|
#if defined(_WIND_ON)
|
|
float3 windDir = normalize(_WindDirection.xyz);
|
|
float windPhase = dot(worldPos.xz, windDir.xz) * _WindFrequency + time * _WindSpeed;
|
|
float wave = sin(windPhase) * 0.5 + 0.5;
|
|
float gustPhase = time * _WindGustFrequency;
|
|
float gust = sin(gustPhase) * sin(gustPhase * 2.3) * _WindGustStrength;
|
|
float windFactor = (wave + gust - 0.25) * _WindStrength;
|
|
windFactor *= height * height;
|
|
windFactor *= (1 - stiffness);
|
|
return windDir * windFactor;
|
|
#else
|
|
return float3(0, 0, 0);
|
|
#endif
|
|
}
|
|
|
|
Varyings ShadowVert(Attributes IN)
|
|
{
|
|
Varyings OUT;
|
|
UNITY_SETUP_INSTANCE_ID(IN);
|
|
UNITY_TRANSFER_INSTANCE_ID(IN, OUT);
|
|
|
|
float height = IN.color.r;
|
|
float stiffness = IN.color.a;
|
|
|
|
float3 posOS = IN.positionOS.xyz;
|
|
|
|
#if defined(_DISTANCE_FADE_ON)
|
|
float3 worldPosBase = TransformObjectToWorld(float3(0, 0, 0));
|
|
float distToCam = distance(worldPosBase, _WorldSpaceCameraPos);
|
|
float fadeFactor = saturate((distToCam - _FadeStart) / (_FadeEnd - _FadeStart));
|
|
float scale = lerp(1, _FadeMinScale, fadeFactor);
|
|
posOS *= scale;
|
|
#endif
|
|
|
|
float3 worldPos = TransformObjectToWorld(posOS);
|
|
worldPos += WindAnimation(worldPos, height, stiffness, _Time.y);
|
|
|
|
float3 worldNormal = TransformObjectToWorldNormal(IN.normalOS);
|
|
worldPos = ApplyShadowBiasCustom(worldPos, worldNormal, _LightDirection);
|
|
float4 posCS = TransformWorldToHClip(worldPos);
|
|
|
|
#if UNITY_REVERSED_Z
|
|
posCS.z = min(posCS.z, UNITY_NEAR_CLIP_VALUE);
|
|
#else
|
|
posCS.z = max(posCS.z, UNITY_NEAR_CLIP_VALUE);
|
|
#endif
|
|
|
|
OUT.positionCS = posCS;
|
|
OUT.uv = TRANSFORM_TEX(IN.uv, _MainTex);
|
|
|
|
return OUT;
|
|
}
|
|
|
|
float4 ShadowFrag(Varyings IN) : SV_Target
|
|
{
|
|
float alpha = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, IN.uv).a;
|
|
clip(alpha - _Cutoff);
|
|
return 0;
|
|
}
|
|
ENDHLSL
|
|
}
|
|
|
|
// Depth pass
|
|
Pass
|
|
{
|
|
Name "DepthOnly"
|
|
Tags { "LightMode" = "DepthOnly" }
|
|
|
|
ZWrite On
|
|
ColorMask 0
|
|
Cull Off
|
|
|
|
HLSLPROGRAM
|
|
#pragma target 4.5
|
|
#pragma vertex DepthVert
|
|
#pragma fragment DepthFrag
|
|
|
|
#pragma multi_compile_instancing
|
|
#pragma shader_feature_local _WIND_ON
|
|
#pragma shader_feature_local _DISTANCE_FADE_ON
|
|
|
|
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
|
|
|
|
TEXTURE2D(_MainTex);
|
|
SAMPLER(sampler_MainTex);
|
|
|
|
CBUFFER_START(UnityPerMaterial)
|
|
float4 _MainTex_ST;
|
|
float _WindStrength;
|
|
float _WindSpeed;
|
|
float _WindFrequency;
|
|
float4 _WindDirection;
|
|
float _WindGustStrength;
|
|
float _WindGustFrequency;
|
|
float _FadeStart;
|
|
float _FadeEnd;
|
|
float _FadeMinScale;
|
|
float _Cutoff;
|
|
CBUFFER_END
|
|
|
|
struct Attributes
|
|
{
|
|
float4 positionOS : POSITION;
|
|
float2 uv : TEXCOORD0;
|
|
float4 color : COLOR;
|
|
UNITY_VERTEX_INPUT_INSTANCE_ID
|
|
};
|
|
|
|
struct Varyings
|
|
{
|
|
float4 positionCS : SV_POSITION;
|
|
float2 uv : TEXCOORD0;
|
|
};
|
|
|
|
float3 WindAnimation(float3 worldPos, float height, float stiffness, float time)
|
|
{
|
|
#if defined(_WIND_ON)
|
|
float3 windDir = normalize(_WindDirection.xyz);
|
|
float windPhase = dot(worldPos.xz, windDir.xz) * _WindFrequency + time * _WindSpeed;
|
|
float wave = sin(windPhase) * 0.5 + 0.5;
|
|
float gustPhase = time * _WindGustFrequency;
|
|
float gust = sin(gustPhase) * sin(gustPhase * 2.3) * _WindGustStrength;
|
|
float windFactor = (wave + gust - 0.25) * _WindStrength;
|
|
windFactor *= height * height;
|
|
windFactor *= (1 - stiffness);
|
|
return windDir * windFactor;
|
|
#else
|
|
return float3(0, 0, 0);
|
|
#endif
|
|
}
|
|
|
|
Varyings DepthVert(Attributes IN)
|
|
{
|
|
Varyings OUT;
|
|
UNITY_SETUP_INSTANCE_ID(IN);
|
|
|
|
float height = IN.color.r;
|
|
float stiffness = IN.color.a;
|
|
float3 posOS = IN.positionOS.xyz;
|
|
|
|
#if defined(_DISTANCE_FADE_ON)
|
|
float3 worldPosBase = TransformObjectToWorld(float3(0, 0, 0));
|
|
float distToCam = distance(worldPosBase, _WorldSpaceCameraPos);
|
|
float fadeFactor = saturate((distToCam - _FadeStart) / (_FadeEnd - _FadeStart));
|
|
posOS *= lerp(1, _FadeMinScale, fadeFactor);
|
|
#endif
|
|
|
|
float3 worldPos = TransformObjectToWorld(posOS);
|
|
worldPos += WindAnimation(worldPos, height, stiffness, _Time.y);
|
|
|
|
OUT.positionCS = TransformWorldToHClip(worldPos);
|
|
OUT.uv = TRANSFORM_TEX(IN.uv, _MainTex);
|
|
|
|
return OUT;
|
|
}
|
|
|
|
float4 DepthFrag(Varyings IN) : SV_Target
|
|
{
|
|
float alpha = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, IN.uv).a;
|
|
clip(alpha - _Cutoff);
|
|
return 0;
|
|
}
|
|
ENDHLSL
|
|
}
|
|
}
|
|
|
|
// ==================== Built-in Pipeline SubShader ====================
|
|
SubShader
|
|
{
|
|
Tags { "RenderType" = "TransparentCutout" "Queue" = "AlphaTest" }
|
|
|
|
Pass
|
|
{
|
|
Name "GrassBuiltIn"
|
|
Tags { "LightMode" = "ForwardBase" }
|
|
Cull Off
|
|
|
|
CGPROGRAM
|
|
#pragma target 3.0
|
|
#pragma vertex vert
|
|
#pragma fragment frag
|
|
#pragma multi_compile_fwdbase
|
|
#pragma multi_compile_fog
|
|
#pragma multi_compile_instancing
|
|
|
|
#pragma shader_feature_local _WIND_ON
|
|
#pragma shader_feature_local _SSS_ON
|
|
#pragma shader_feature_local _SPECULAR_ON
|
|
|
|
#include "UnityCG.cginc"
|
|
#include "Lighting.cginc"
|
|
#include "AutoLight.cginc"
|
|
|
|
sampler2D _MainTex;
|
|
float4 _MainTex_ST;
|
|
float4 _BaseColor;
|
|
float4 _TipColor;
|
|
float _GradientPower;
|
|
float _WindStrength;
|
|
float _WindSpeed;
|
|
float _WindFrequency;
|
|
float4 _WindDirection;
|
|
float _WindGustStrength;
|
|
float _WindGustFrequency;
|
|
float4 _SSSColor;
|
|
float _SSSStrength;
|
|
float _SSSDistortion;
|
|
float _SSSPower;
|
|
float4 _SpecularColor;
|
|
float _SpecularIntensity;
|
|
float _SpecularPower;
|
|
float _AO;
|
|
float _AOPower;
|
|
float _Cutoff;
|
|
|
|
struct appdata
|
|
{
|
|
float4 vertex : POSITION;
|
|
float3 normal : NORMAL;
|
|
float2 uv : TEXCOORD0;
|
|
float4 color : COLOR;
|
|
UNITY_VERTEX_INPUT_INSTANCE_ID
|
|
};
|
|
|
|
struct v2f
|
|
{
|
|
float4 pos : SV_POSITION;
|
|
float2 uv : TEXCOORD0;
|
|
float3 worldPos : TEXCOORD1;
|
|
float3 worldNormal : TEXCOORD2;
|
|
float4 vertexColor : TEXCOORD3;
|
|
float heightGradient : TEXCOORD4;
|
|
SHADOW_COORDS(5)
|
|
UNITY_FOG_COORDS(6)
|
|
UNITY_VERTEX_INPUT_INSTANCE_ID
|
|
};
|
|
|
|
float3 WindAnimation(float3 worldPos, float height, float stiffness, float time)
|
|
{
|
|
#if defined(_WIND_ON)
|
|
float3 windDir = normalize(_WindDirection.xyz);
|
|
float windPhase = dot(worldPos.xz, windDir.xz) * _WindFrequency + time * _WindSpeed;
|
|
float wave = sin(windPhase) * 0.5 + 0.5;
|
|
float gustPhase = time * _WindGustFrequency;
|
|
float gust = sin(gustPhase) * sin(gustPhase * 2.3) * _WindGustStrength;
|
|
float windFactor = (wave + gust - 0.25) * _WindStrength;
|
|
windFactor *= height * height * (1 - stiffness);
|
|
return windDir * windFactor;
|
|
#else
|
|
return float3(0, 0, 0);
|
|
#endif
|
|
}
|
|
|
|
v2f vert(appdata v)
|
|
{
|
|
v2f o;
|
|
UNITY_SETUP_INSTANCE_ID(v);
|
|
UNITY_TRANSFER_INSTANCE_ID(v, o);
|
|
|
|
float height = v.color.r;
|
|
float stiffness = v.color.a;
|
|
float3 worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;
|
|
worldPos += WindAnimation(worldPos, height, stiffness, _Time.y);
|
|
|
|
o.pos = mul(UNITY_MATRIX_VP, float4(worldPos, 1));
|
|
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
|
|
o.worldPos = worldPos;
|
|
o.worldNormal = UnityObjectToWorldNormal(v.normal);
|
|
o.vertexColor = v.color;
|
|
o.heightGradient = height;
|
|
TRANSFER_SHADOW(o)
|
|
UNITY_TRANSFER_FOG(o, o.pos);
|
|
return o;
|
|
}
|
|
|
|
float4 frag(v2f i) : SV_Target
|
|
{
|
|
UNITY_SETUP_INSTANCE_ID(i);
|
|
|
|
float4 texColor = tex2D(_MainTex, i.uv);
|
|
clip(texColor.a - _Cutoff);
|
|
|
|
float3 viewDir = normalize(_WorldSpaceCameraPos - i.worldPos);
|
|
float3 normal = normalize(i.worldNormal);
|
|
|
|
float gradientFactor = pow(i.heightGradient, _GradientPower);
|
|
float3 albedo = lerp(_BaseColor.rgb, _TipColor.rgb, gradientFactor) * texColor.rgb;
|
|
|
|
float ao = pow(lerp(1, i.vertexColor.g, _AO), _AOPower);
|
|
|
|
float3 lightDir = normalize(_WorldSpaceLightPos0.xyz);
|
|
float3 lightColor = _LightColor0.rgb;
|
|
float shadow = SHADOW_ATTENUATION(i);
|
|
|
|
float NdotL = saturate(dot(normal, lightDir));
|
|
float3 diffuse = albedo * lightColor * NdotL * shadow;
|
|
|
|
float3 sss = float3(0, 0, 0);
|
|
#if defined(_SSS_ON)
|
|
float3 H = normalize(lightDir + normal * _SSSDistortion);
|
|
float VdotH = pow(saturate(dot(viewDir, -H)), _SSSPower);
|
|
sss = _SSSColor.rgb * VdotH * _SSSStrength * lightColor * shadow;
|
|
#endif
|
|
|
|
float3 specular = float3(0, 0, 0);
|
|
#if defined(_SPECULAR_ON)
|
|
float3 halfDir = normalize(lightDir + viewDir);
|
|
float NdotH = saturate(dot(normal, halfDir));
|
|
float spec = pow(NdotH, _SpecularPower);
|
|
specular = _SpecularColor.rgb * spec * _SpecularIntensity * lightColor * shadow;
|
|
#endif
|
|
|
|
float3 ambient = albedo * 0.1;
|
|
float3 finalColor = (diffuse + sss + specular + ambient) * ao;
|
|
UNITY_APPLY_FOG(i.fogCoord, finalColor);
|
|
|
|
return float4(finalColor, texColor.a);
|
|
}
|
|
ENDCG
|
|
}
|
|
}
|
|
|
|
// ==================== HDRP SubShader ====================
|
|
SubShader
|
|
{
|
|
PackageRequirements { "com.unity.render-pipelines.high-definition" }
|
|
Tags { "RenderType" = "TransparentCutout" "Queue" = "AlphaTest" "RenderPipeline" = "HDRenderPipeline" }
|
|
|
|
Pass
|
|
{
|
|
Name "GrassHDRP"
|
|
Tags { "LightMode" = "Forward" }
|
|
Cull Off
|
|
|
|
HLSLPROGRAM
|
|
#pragma target 4.5
|
|
#pragma vertex vert
|
|
#pragma fragment frag
|
|
#pragma multi_compile_instancing
|
|
#pragma shader_feature_local _WIND_ON
|
|
#pragma shader_feature_local _SSS_ON
|
|
|
|
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl"
|
|
#include "Packages/com.unity.render-pipelines.high-definition/Runtime/ShaderLibrary/ShaderVariables.hlsl"
|
|
|
|
TEXTURE2D(_MainTex);
|
|
SAMPLER(sampler_MainTex);
|
|
|
|
CBUFFER_START(UnityPerMaterial)
|
|
float4 _MainTex_ST;
|
|
float4 _BaseColor;
|
|
float4 _TipColor;
|
|
float _GradientPower;
|
|
float _WindStrength;
|
|
float _WindSpeed;
|
|
float _WindFrequency;
|
|
float4 _WindDirection;
|
|
float _WindGustStrength;
|
|
float _WindGustFrequency;
|
|
float4 _SSSColor;
|
|
float _SSSStrength;
|
|
float _SSSDistortion;
|
|
float _SSSPower;
|
|
float _AO;
|
|
float _AOPower;
|
|
float _Cutoff;
|
|
CBUFFER_END
|
|
|
|
struct Attributes
|
|
{
|
|
float4 positionOS : POSITION;
|
|
float3 normalOS : NORMAL;
|
|
float2 uv : TEXCOORD0;
|
|
float4 color : COLOR;
|
|
UNITY_VERTEX_INPUT_INSTANCE_ID
|
|
};
|
|
|
|
struct Varyings
|
|
{
|
|
float4 positionCS : SV_POSITION;
|
|
float2 uv : TEXCOORD0;
|
|
float3 worldPos : TEXCOORD1;
|
|
float3 worldNormal : TEXCOORD2;
|
|
float4 vertexColor : TEXCOORD3;
|
|
float heightGradient : TEXCOORD4;
|
|
UNITY_VERTEX_INPUT_INSTANCE_ID
|
|
};
|
|
|
|
float3 WindAnimation(float3 worldPos, float height, float stiffness, float time)
|
|
{
|
|
#if defined(_WIND_ON)
|
|
float3 windDir = normalize(_WindDirection.xyz);
|
|
float windPhase = dot(worldPos.xz, windDir.xz) * _WindFrequency + time * _WindSpeed;
|
|
float wave = sin(windPhase) * 0.5 + 0.5;
|
|
float gust = sin(time * _WindGustFrequency) * sin(time * _WindGustFrequency * 2.3) * _WindGustStrength;
|
|
float windFactor = (wave + gust - 0.25) * _WindStrength * height * height * (1 - stiffness);
|
|
return windDir * windFactor;
|
|
#else
|
|
return float3(0, 0, 0);
|
|
#endif
|
|
}
|
|
|
|
Varyings vert(Attributes IN)
|
|
{
|
|
Varyings OUT;
|
|
UNITY_SETUP_INSTANCE_ID(IN);
|
|
UNITY_TRANSFER_INSTANCE_ID(IN, OUT);
|
|
|
|
float height = IN.color.r;
|
|
float stiffness = IN.color.a;
|
|
float3 worldPos = TransformObjectToWorld(IN.positionOS.xyz);
|
|
worldPos += WindAnimation(worldPos, height, stiffness, _Time.y);
|
|
|
|
OUT.positionCS = TransformWorldToHClip(worldPos);
|
|
OUT.uv = IN.uv * _MainTex_ST.xy + _MainTex_ST.zw;
|
|
OUT.worldPos = worldPos;
|
|
OUT.worldNormal = TransformObjectToWorldNormal(IN.normalOS);
|
|
OUT.vertexColor = IN.color;
|
|
OUT.heightGradient = height;
|
|
return OUT;
|
|
}
|
|
|
|
float4 frag(Varyings IN) : SV_Target
|
|
{
|
|
UNITY_SETUP_INSTANCE_ID(IN);
|
|
|
|
float4 texColor = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, IN.uv);
|
|
clip(texColor.a - _Cutoff);
|
|
|
|
float3 viewDir = GetWorldSpaceNormalizeViewDir(IN.worldPos);
|
|
float3 normal = normalize(IN.worldNormal);
|
|
|
|
float gradientFactor = pow(IN.heightGradient, _GradientPower);
|
|
float3 albedo = lerp(_BaseColor.rgb, _TipColor.rgb, gradientFactor) * texColor.rgb;
|
|
float ao = pow(lerp(1, IN.vertexColor.g, _AO), _AOPower);
|
|
|
|
float3 lightDir = float3(0.5, 0.8, 0.2);
|
|
float NdotL = saturate(dot(normal, lightDir));
|
|
float3 diffuse = albedo * NdotL;
|
|
|
|
float3 sss = float3(0, 0, 0);
|
|
#if defined(_SSS_ON)
|
|
float3 H = normalize(lightDir + normal * _SSSDistortion);
|
|
float VdotH = pow(saturate(dot(viewDir, -H)), _SSSPower);
|
|
sss = _SSSColor.rgb * VdotH * _SSSStrength;
|
|
#endif
|
|
|
|
float3 finalColor = (diffuse + sss + albedo * 0.1) * ao;
|
|
return float4(finalColor, texColor.a);
|
|
}
|
|
ENDHLSL
|
|
}
|
|
}
|
|
|
|
FallBack "Universal Render Pipeline/Unlit"
|
|
}
|