Files
CartoonRPG/Assets/StixGames/GrassShader/GrassFallbackShader.shader
Caleb Sandford deQuincey 02c4b5ab66 Adding in new packages
2025-06-05 22:59:18 +01:00

306 lines
11 KiB
GLSL

Shader "Stix Games/GrassFallback"
{
Properties
{
_TextureAtlas ("Albedo (RGB)", 2D) = "white" {}
_SpecularSmooth ("Specular (RGB) Smoothness (A)", 2D) = "black" {}
_Depth ("Depth", 2D) = "white" {}
_Normal ("Normal", 2D) = "bump" {}
_Subsurface("Subsurface Scattering", Range(0, 1)) = 0.0
_WindParams("Wind WaveStrength(X), WaveSpeed(Y), RippleStrength(Z), RippleSpeed(W)", Vector) = (0.3, 1.2, 0.15, 1.3)
_WindRotation("Wind Rotation", Range(0, 6.28318530718)) = 0
_SoftnessFactor("SoftnessFactor", Float) = 1
_Cutoff("Cutoff", Range(0, 1)) = 0.2
_AtlasSize("Texture Atlas Size", Int) = 0
_AtlasOffset("Padding to prevent color leakage", Range(0, 0.5)) = 0.01
_InstanceAtlasIndices("Atlas Index for Instanced Rendering", Vector) = (0,0,0,0)
_InstancePosSmoothing("Center Position and Smoothing for Instanced Rendering", Vector) = (0,0,0,0)
_WindWobble("Wind Wobble", Range(0, 2)) = 0.5
_FinalAlphaCutoff("Internal alpha cutoff", Float) = 0.5
}
SubShader
{
Tags { "Queue"="AlphaTest" }
//LOD 200
//This setting isn't allowed, as it removes shadow casting in surface shadows
//AlphaToMask On
CGPROGRAM
// Physically based Standard lighting model, and enable shadows on all light types
#pragma surface surf FallbackGrass fullforwardshadows vertex:vert addshadow //alphatest:_FinalAlphaCutoff
#pragma multi_compile_instancing
#pragma multi_compile __ SMOOTH_TEXTURE
#pragma multi_compile __ SMOOTH_WIDTH
#pragma multi_compile __ SMOOTH_HEIGHT
#pragma multi_compile __ GRASS_RENDERTEXTURE_INTERACTION
// Use shader model 3.0 target, to get nicer looking lighting
#pragma target 3.0
#include "UnityPBSLighting.cginc"
sampler2D _TextureAtlas;
sampler2D _SpecularSmooth;
sampler2D _Depth;
sampler2D _Normal;
half _Subsurface;
half4 _WindParams;
half _WindRotation;
half _Cutoff;
half _SoftnessFactor;
half _WindWobble;
float _AtlasSize;
float _AtlasOffset;
#ifdef GRASS_RENDERTEXTURE_INTERACTION
sampler2D _GrassRenderTextureInteraction;
sampler2D _GrassRenderTextureBurn;
//This is the area the interaction camera is currently rendering. xy is left bottom, wz is width and height.
float4 _GrassRenderTextureArea;
#endif
UNITY_INSTANCING_BUFFER_START(InstancedProps)
UNITY_DEFINE_INSTANCED_PROP(float4, _InstanceAtlasIndices)
#define _InstanceAtlasIndices_arr InstancedProps
UNITY_DEFINE_INSTANCED_PROP(float4, _InstancePosSmoothing)
#define _InstancePosSmoothing_arr InstancedProps
UNITY_INSTANCING_BUFFER_END(InstancedProps)
#include "GrassWind.hlsl"
struct vert_inout
{
float4 vertex : POSITION; // The vertex position in model space.
float3 normal : NORMAL; // The vertex normal in model space.
float4 texcoord : TEXCOORD0; // The first UV coordinate.
float2 texcoord1 : TEXCOORD1; // The second UV coordinate.
float2 texcoord2 : TEXCOORD2; // The third UV coordinate.
float4 tangent : TANGENT; // The tangent vector in Model Space (used for normal mapping).
float4 color : COLOR; // World position (XZ) Grass Height (Y) Smoothing (A)
UNITY_VERTEX_INPUT_INSTANCE_ID
};
#if defined(UNITY_INSTANCING_ENABLED) || defined(UNITY_PROCEDURAL_INSTANCING_ENABLED) || defined(UNITY_STEREO_INSTANCING_ENABLED)
#define GRASS_USE_INSTANCING
#endif
inline half4 LightingFallbackGrass(SurfaceOutputStandardSpecular s, half3 viewDir, UnityGI gi)
{
half4 c = LightingStandardSpecular(s, viewDir, gi);
half oneMinusReflectivity;
half3 diffColor = EnergyConservationBetweenDiffuseAndSpecular(s.Albedo, s.Specular, /*out*/ oneMinusReflectivity);
half3 subsurfaceScattering = diffColor * _Subsurface * (saturate(1 - LambertTerm(s.Normal, gi.light.dir)) * gi.light.color);
c.rgb += subsurfaceScattering;
return c;
}
inline void LightingFallbackGrass_GI(SurfaceOutputStandardSpecular s, UnityGIInput data, inout UnityGI gi)
{
//Regular GI
LightingStandardSpecular_GI(s, data, gi);
//Subsurface GI
s.Normal = -s.Normal;
UnityGI subsurfGi = (UnityGI) 0;
LightingStandardSpecular_GI(s, data, subsurfGi);
half oneMinusReflectivity;
half3 diffColor = EnergyConservationBetweenDiffuseAndSpecular(s.Albedo, s.Specular, /*out*/ oneMinusReflectivity);
gi.indirect.diffuse += diffColor * _Subsurface * subsurfGi.indirect.diffuse;
s.Normal = -s.Normal;
}
struct Input
{
float2 uv_TextureAtlas;
//I am misusing the UV coordinates to contain the indices for each grass type
float2 uv2_SpecularSmooth;
float2 uv3_Depth;
//The fallback script saves the world position (unchanged by smoothing) in the vertex color
float4 color : COLOR;
float3 burnColor;
};
void vert (inout vert_inout v, out Input o)
{
UNITY_SETUP_INSTANCE_ID(v);
UNITY_INITIALIZE_OUTPUT(Input,o);
//Calculate smoothing for instancing
#if defined(GRASS_USE_INSTANCING)
float3 originalPos = UNITY_ACCESS_INSTANCED_PROP(_InstancePosSmoothing_arr, _InstancePosSmoothing).xyz;
originalPos.y = v.color.y;
float smoothing = UNITY_ACCESS_INSTANCED_PROP(_InstancePosSmoothing_arr, _InstancePosSmoothing).w;
#if defined(SMOOTH_HEIGHT)
v.vertex.y *= smoothing;
#endif
#if defined(SMOOTH_WIDTH)
v.vertex.xz *= smoothing;
#endif
#else
float3 originalPos = v.color.xyz;
#endif
//Calculate interaction
#if defined(GRASS_RENDERTEXTURE_INTERACTION)
float2 coords = (originalPos.xz - _GrassRenderTextureArea.xy) / _GrassRenderTextureArea.zw;
half4 interactionTexture = tex2Dlod(_GrassRenderTextureInteraction, float4(coords, 0, 0));
half3 interaction = normalize(interactionTexture.rgb * 2 - float3(1, 1, 1));
half4 burnFactor = tex2Dlod(_GrassRenderTextureBurn, float4(coords, 0, 0));
#else
half3 interaction = half3(0, 0, 1);
half4 burnFactor = half4(1, 1, 1, 1);
#endif
//Apply burn
o.burnColor = burnFactor.rgb;
v.vertex.y *= burnFactor.a;
//Calculations for wind and interaction
half2 windDir = wind(originalPos, _WindRotation);
half segment = originalPos.y;
half sqrSegment = segment * segment;
//Wind wobble
#if defined(GRASS_USE_INSTANCING)
float2 offset = float2(0,0);
#else
float2 offset = mul(unity_WorldToObject, float4(originalPos, 1)).xz;
#endif
v.vertex.xz -= offset;
#if defined(GRASS_RENDERTEXTURE_INTERACTION)
float interactionHeight = pow(interaction.z, 2);
v.vertex.xz *= 1 + segment * length(windDir.xy) * interactionHeight * _WindWobble;
#else
v.vertex.xz *= 1 + segment * length(windDir.xy) * _WindWobble;
#endif
v.vertex.xz += offset;
float3 pos = mul(unity_ObjectToWorld, v.vertex).xyz;
//Apply interaction
#if defined(GRASS_RENDERTEXTURE_INTERACTION)
pos.xz += (windDir.xy * interactionHeight + interaction.xy) * sqrSegment * _SoftnessFactor;
pos.y -= length(windDir.xy + interaction.xy) * sqrSegment * 0.5f * _SoftnessFactor;
pos.y *= max(interactionHeight, 0.01);
#else
pos.xz += windDir.xy * sqrSegment * _SoftnessFactor;
pos.y -= length(windDir) * sqrSegment * 0.5f * _SoftnessFactor;
#endif
//Use original grass height, to prevent vertices at the floor from moving
v.vertex.xyz = mul(unity_WorldToObject, float4(pos, 1)).xyz;
//Discard the triangle if it's burned away
if (burnFactor.a < 0.1f)
{
v.vertex = float4(0, 0, 0, 0);
}
}
void surf (Input IN, inout SurfaceOutputStandardSpecular o)
{
_AtlasSize = max(_AtlasSize, 1);
float size = 1.0 / _AtlasSize;
float tilesPerGrassType = round(_AtlasSize * (_AtlasSize / 4));
//Apply the color leakage preventing _AtlasOffset
float2 offset = float2(_AtlasOffset, _AtlasOffset);
float sizeOffset = 1 - 2 * _AtlasOffset;
#if defined(GRASS_USE_INSTANCING)
float4 indices = UNITY_ACCESS_INSTANCED_PROP(_InstanceAtlasIndices_arr, _InstanceAtlasIndices);
#else
float4 indices = float4(IN.uv2_SpecularSmooth, IN.uv3_Depth);
#endif
//Calculate texture coordinates for each grass type
float index0 = round(indices.x);
float2 texCoord0 = (offset + float2(fmod(index0, _AtlasSize), floor(index0 / _AtlasSize)) + IN.uv_TextureAtlas * sizeOffset) * size;
float index1 = round(indices.y);
float2 texCoord1 = (offset + float2(fmod(index1, _AtlasSize), floor(index1 / _AtlasSize)) + IN.uv_TextureAtlas * sizeOffset) * size;
float index2 = round(indices.z);
float2 texCoord2 = (offset + float2(fmod(index2, _AtlasSize), floor(index2 / _AtlasSize)) + IN.uv_TextureAtlas * sizeOffset) * size;
float index3 = round(indices.w);
float2 texCoord3 = (offset + float2(fmod(index3, _AtlasSize), floor(index3 / _AtlasSize)) + IN.uv_TextureAtlas * sizeOffset) * size;
float isVisible0 = step(0, index0);
float isVisible1 = step(0, index1);
float isVisible2 = step(0, index2);
float isVisible3 = step(0, index3);
//Depth
float depth0, depth1, depth2, depth3;
depth0 = DecodeFloatRGBA(tex2D(_Depth, texCoord0)) + (1-isVisible0);
depth1 = DecodeFloatRGBA(tex2D(_Depth, texCoord1)) + (1-isVisible1);
depth2 = DecodeFloatRGBA(tex2D(_Depth, texCoord2)) + (1-isVisible2);
depth3 = DecodeFloatRGBA(tex2D(_Depth, texCoord3)) + (1-isVisible3);
float minDepth = min(depth0, min(depth1, min(depth2, depth3)));
//Get the color of the texture that is closest to the camera at this point
half4 c0 = tex2D (_TextureAtlas, texCoord0) * isVisible0;
half4 c1 = tex2D (_TextureAtlas, texCoord1) * isVisible1;
half4 c2 = tex2D (_TextureAtlas, texCoord2) * isVisible2;
half4 c3 = tex2D (_TextureAtlas, texCoord3) * isVisible3;
half4 c = c0 * step(depth0, minDepth) + c1 * step(depth1, minDepth) + c2 * step(depth2, minDepth) + c3 * step(depth3, minDepth);
o.Albedo = c.rgb * IN.burnColor;
//Alpha cutoff
#if defined(GRASS_USE_INSTANCING)
float smoothing = UNITY_ACCESS_INSTANCED_PROP(_InstancePosSmoothing_arr, _InstancePosSmoothing).a;
#else
float smoothing = IN.color.a;
#endif
#if defined(SMOOTH_TEXTURE)
c.a *= smoothing;
#endif
clip(c.a - _Cutoff);
o.Alpha = 1;
//o.Alpha = (c.a - _Cutoff) / max(fwidth(c.a) * 2, 0.0001) + 0.5f;
//Specular and smoothness
half4 ss0 = tex2D (_SpecularSmooth, texCoord0);
half4 ss1 = tex2D (_SpecularSmooth, texCoord1);
half4 ss2 = tex2D (_SpecularSmooth, texCoord2);
half4 ss3 = tex2D (_SpecularSmooth, texCoord3);
half4 ss = ss0 * step(depth0, minDepth) + ss1 * step(depth1, minDepth) + ss2 * step(depth2, minDepth) + ss3 * step(depth3, minDepth);
o.Specular = ss.rgb;
o.Smoothness = ss.a;
//Normal
float4 normal0 = tex2D(_Normal, texCoord0);
float4 normal1 = tex2D(_Normal, texCoord1);
float4 normal2 = tex2D(_Normal, texCoord2);
float4 normal3 = tex2D(_Normal, texCoord3);
//Normal
float4 normal = normal0 * step(depth0, minDepth) + normal1 * step(depth1, minDepth) + normal2 * step(depth2, minDepth) + normal3 * step(depth3, minDepth);
o.Normal = UnpackNormal(normal);
}
ENDCG
}
}