ToriaAssets/Sources/Shaders/GrassInstancedIndirect_Vertex.cginc

229 lines
8.1 KiB
HLSL
Raw Normal View History

2026-05-19 12:20:15 +02:00
// Vertex Functions
float2 _WindMultiplier;
// Simple random function
inline float nrand(float2 pos) {
return frac(sin(dot(pos, half2(12.9898f, 78.233f))) * 43758.5453f);
//return frac((dot(pos, half2(12.9898f, 78.233f))) );
}
// Our vertex function which handles wind and culling
#if defined(DEPTHNORMAL)
void vertgrass(inout appdata_full v, in float3 terrainNormal, in float InstanceScale) {
#elif defined(DEPTHONLY)
void vertgrass(inout appdata_grassinstanced_depth v, in float3 terrainNormal, in float InstanceScale) {
#else
void vertgrass(inout appdata_grassinstanced v, out Input o) {
UNITY_INITIALIZE_OUTPUT(Input, o);
#endif
// Scale contains some perlin noise  so we use it to add any perlin noise based variation
//float3 unitvec = mul( (float3x3 )unity_ObjectToWorld, float3(1,0,0)); // float4 would be 0,1,0, 0 !!!!!
//float scale = length( unitvec );
float scale = InstanceScale;
const float3 pivot = float3(unity_ObjectToWorld[0].w, unity_ObjectToWorld[1].w, unity_ObjectToWorld[2].w);
const float3 dist = pivot
//+ scale.xxx * 4 // lets break up the boring distance - skipped as it might break smooth fading.
#if defined(DONOTUSE_ATGSETUP)
- _WorldSpaceCameraPos.xyz; // vs shader version
#elif !defined(UNITY_PROCEDURAL_INSTANCING_ENABLED)
- _WorldSpaceCameraPos.xyz; // for wind setup
#else
- _AtgSurfaceCameraPosition.xyz; // atg original shader: we have to use a custom cam pos to make it match compute.
#endif
const float SqrDist = dot(dist, dist);
// Calculate far fade factor
#if defined (UNITY_PASS_SHADOWCASTER)
float fade = 1;
// Depth Pass
if (unity_LightShadowBias.z == 0.0) {
fade = saturate(( _AtgGrassFadeProps.x - SqrDist) * _AtgGrassFadeProps.y);
}
// Shadow Pass
else {
// TODO: Check why i can't revert this as well? Clip?
fade = 1.0f - saturate((SqrDist - _AtgGrassShadowFadeProps.x) * _AtgGrassShadowFadeProps.y);
}
#else
float fade = saturate(( _AtgGrassFadeProps.x - SqrDist) * _AtgGrassFadeProps.y);
#endif
// Cull based on far culling distance
if (fade == 0.0f) {
v.vertex = 0.0f;
return;
}
// Get some random value per instance
// random = nrand(randPivot); // Due to compute and floating origin issues we use the baked scale:
fixed random = nrand( float2(scale, 1.0 - scale) );
//random = nrand(float2(unity_ObjectToWorld[0].x, unity_ObjectToWorld[1].y));
// Calculate near fade factor / reversed!
const float smallScaleClipping = saturate(( SqrDist - _AtgGrassFadeProps.z) * _AtgGrassFadeProps.w);
float clip = (random < _Clip)? 1 : 0;
// Debug: Colorize instances which would be culled early on
fixed4 color = 1;
#if defined(_PARALLAXMAP)
color.rgb = lerp(o.color.rgb, _DebugColor, clip);
#endif
clip = 1.0f - smallScaleClipping * clip;
half farNear = (clip < 1) ? 1 : 0;
// Cull based on near culling distance
if (clip == 0.0f) {
v.vertex = 0.0f;
return;
}
fade *= clip;
// Set color variation
float normalizedScale = (scale - _MinMaxScales.x) * _MinMaxScales.y;
normalizedScale = saturate(normalizedScale);
#if defined(GRASSUSESTEXTUREARRAYS) && defined(_MIXMODE_RANDOM)
color *= lerp(_HealthyColor, _DryColor, nrand(pivot.zx).xxxx); // PS4 lerp
#else
color *= lerp(_HealthyColor, _DryColor, normalizedScale.xxxx); // PS4 lerp
#endif
// Set random bend strength
const float mainBending = v.color.a * color.a;
// Apply fading
// Always use xyz at far distances
float3 targetPos = (_ScaleMode + farNear == 2) ? float3(0, v.vertex.y, 0) : float3(0,0,0);
v.vertex.xyz = lerp(v.vertex.xyz, targetPos, (1.0 - fade).xxx); // PS4 lerp
// ---------------------
// Wind
#if defined(_METALLICGLOSSMAP)
// Read wind at pivot
float4 wind = tex2Dlod(_AtgWindRT, float4( pivot.xz * _AtgWindDirSize.w + (1 - v.color.r).xx + scale * 0.025, 0, _WindLOD) );
#else
// Read wind texture at vertex world position
float3 wPos = mul(unity_ObjectToWorld, v.vertex).xyz;
float4 wind = tex2Dlod(_AtgWindRT, float4( wPos.xz * _AtgWindDirSize.w + (1 - v.color.r).xx + scale * 0.025, 0, _WindLOD) );
#endif
wind.r = wind.r * (wind.g * 2.0f - 0.24376f /* not a "real" normal as we want to keep the base direction*/);
// If not procedural instanced drawn swap direction as we have a proper WorldToObject matrix
#if !defined (UNITY_PROCEDURAL_INSTANCING_ENABLED)
wind.r *= -1;
#endif
// Add bending from wind
const float windStrength = wind.r * _AtgWindStrengthMultipliers.x * _WindMultiplier.x * mainBending;
float3 bend = UnityWorldToObjectDir(_AtgWindDirSize.xyz) * windStrength;
#if !defined(DEPTHNORMAL)
v.vertex.xz -= bend.xz;
#else
v.vertex.xz += bend.xz;
#endif
// Add none directional "jitter"  this helps to hide the quantized wind from the texture lookup.
float2 jitter = lerp( float2 (_AtgSinTime.x, 0), _AtgSinTime.yz, float2(random, windStrength) ); // PS4 lerp - already
#if !defined(DEPTHNORMAL)
v.vertex.xz +=
(jitter.x + jitter.y * _WindMultiplier.y)
* (0.075 + _AtgSinTime.w) * saturate(windStrength)
;
#else
// Crazy?!
float jitterFactor = (0.075 + _AtgSinTime.w) * saturate(windStrength);
v.vertex.zx += jitter.y * _WindMultiplier.y * jitterFactor;
v.vertex.xz -= jitter.x * jitterFactor;
#endif
// Get/set normal
#if !defined(DEPTHONLY)
#if defined(_NORMAL)
v.normal = terrainNormal;
#else
v.normal = half3(0,1,0);
#endif
// Bend normal
v.normal.xz -= (bend.xz * UNITY_PI) * _NormalBend;
// per pixel normalize is applied in lighting function // v.normal = normalize(v.normal);
#endif
// Derive ambient occlusion from baked bending
#if !defined(DEPTHNORMAL) && !defined(DEPTHONLY)
o.occ = saturate( 0.85 + v.color.a);
#endif
// Calcualte texture array layer based on a new random value
#if defined(GRASSUSESTEXTUREARRAYS)
#if defined(_MIXMODE_BYSIZE)
#if defined(DEPTHONLY)
v.texcoord.x = floor(normalizedScale * _Layers + _SizeThreshold);
#else
o.layer = floor(normalizedScale * _Layers + _SizeThreshold);
#endif
#elif defined(_MIXMODE_RANDOM)
// We must not use the same random value here as for the culling! -> nope: floating origin...
random = nrand( float2(1.0 - scale, scale) ); // nrand(pivot.zx); //
#if defined(DEPTHONLY)
v.texcoord.x = floor(random * _Layers + 0.5 );
#else
o.layer = floor(random * _Layers + 0.5 );
#endif
// here middle texture wins most of the time...
// o.layer = floor( (random + normalizedScale) * 0.5 * _Layers + 0.5);
#endif
#endif
// Store smoothness variation
scale = lerp(0.6, 1.0, random);
color.a = v.color.a;
// Set outputs needed by the Surface shaders
#if !defined(DEPTHNORMAL) && !defined(DEPTHONLY)
o.scale = scale;
o.color = color;
#endif
}
// ----------------------------------------------
// Currently unsused functions
void rotate2D(inout float2 v, float r) {
float s, c;
sincos(r, s, c);
v = float2(v.x * c - v.y * s, v.x * s + v.y * c);
}
// http://answers.unity3d.com/questions/218333/shader-inversefloat4x4-function.html
inline float4x4 inverseMat(float4x4 input) {
#define minor(a,b,c) determinant(float3x3(input.a, input.b, input.c))
float4x4 cofactors = float4x4(
minor(_22_23_24, _32_33_34, _42_43_44),
-minor(_21_23_24, _31_33_34, _41_43_44),
minor(_21_22_24, _31_32_34, _41_42_44),
-minor(_21_22_23, _31_32_33, _41_42_43),
-minor(_12_13_14, _32_33_34, _42_43_44),
minor(_11_13_14, _31_33_34, _41_43_44),
-minor(_11_12_14, _31_32_34, _41_42_44),
minor(_11_12_13, _31_32_33, _41_42_43),
minor(_12_13_14, _22_23_24, _42_43_44),
-minor(_11_13_14, _21_23_24, _41_43_44),
minor(_11_12_14, _21_22_24, _41_42_44),
-minor(_11_12_13, _21_22_23, _41_42_43),
-minor(_12_13_14, _22_23_24, _32_33_34),
minor(_11_13_14, _21_23_24, _31_33_34),
-minor(_11_12_14, _21_22_24, _31_32_34),
minor(_11_12_13, _21_22_23, _31_32_33)
);
#undef minor
return transpose(cofactors) / determinant(input);
}