#include "MathUtils.hlsl" StructuredBuffer<float4x4> _GrassBladeData; void GetBladeMatrix_float(float instanceID, out float4x4 bladeMatrix) { uint id = (uint) instanceID; bladeMatrix = _GrassBladeData[id]; } void GetBladeHeight_float(float instanceID, out float height) { uint id = (uint) instanceID; float4x4 m = _GrassBladeData[id]; // Second column of the matrix = rotated/scaled Y-axis vector float3 upVec = float3(m[0][1], m[1][1], m[2][1]); // Length of the Y vector = scale in Y height = length(upVec); } void CalculateGrassVertexParams_float(float vertexID, float vertexNumber, out float heightPercent, out float XSide, out float ZSide) { XSide = mod(vertexID, 2); ZSide = -(floor(vertexID / vertexNumber) * 2.0 - 1.0); heightPercent = (vertexID - XSide) / vertexNumber; } void ColorVertex_float(float vertexID, float vertexNumber, out float3 c) { float result = frac(vertexID / vertexNumber); c = float3(result, result, result); } void ApplyBladeMatrix_float(float4x4 m, float3 position, out float3 transformedPos) { float4 pos = mul( m, float4(position, 1.0)); transformedPos = pos.xyz; } void ApplyBladeTransformWithRotation_float( float4x4 instanceMatrix, float3x3 rotation, float3 position, out float3 transformedPos) { // 1. Apply wind/player rotation first (object space) float3 rotatedPos = mul(rotation, position); // 2. Then apply instance transformation (to world space) float4 worldPos = mul(instanceMatrix, float4(rotatedPos, 1.0)); transformedPos = worldPos.xyz; } float Hash01_float(float id, out float result) { uint _id = (uint) id; _id = (_id ^ 61) ^ (_id >> 16); _id *= 9; _id = _id ^ (_id >> 4); _id *= 0x27d4eb2d; _id = _id ^ (_id >> 15); result = frac(_id / 4294967296.0); return result; } // Cubic Bezier curve function (4 control points) float3 Bezier(float3 p0, float3 p1, float3 p2, float3 p3, float t) { float u = 1 - t; float tt = t * t; float uu = u * u; float uuu = uu * u; float ttt = tt * t; float3 p = uuu * p0; // (1-t)^3 * p0 p += 3 * uu * t * p1; // 3(1-t)^2 * t * p1 p += 3 * u * tt * p2; // 3(1-t) * t^2 * p2 p += ttt * p3; // t^3 * p3 return p; } void ApplyBezierWind_float( float3 worldPos, float4 vertex, float3 curveStart, float3 curveCtrl1, float3 curveCtrl2, float3 curveEnd, float windTime, float windStrength, float windRadius, out float3 offset) { // Slower, more natural wave progression float t = frac(windTime * 0.05 + worldPos.x * 0.005); // Smoother curve sampling float3 curvePos = Bezier(curveStart, curveCtrl1, curveCtrl2, curveEnd, smoothstep(0, 1, t)); // More organic falloff float distanceToCurve = distance(worldPos.xz, curvePos.xz); float influence = pow(saturate(1.0 - distanceToCurve / windRadius), 2); offset = float3(0, 0, 0); if (influence > 0.01) // Small threshold prevents micro-movements { // Add slight upward bias to mimic natural grass bending float3 windDirection = normalize(curvePos - worldPos + float3(0, 0.3, 0)); float bendAmount = windStrength * influence * pow(vertex.y, 1.5); offset = windDirection * bendAmount; } } void ApplyWindWaves_float( float3 worldPos, float3 windDir, float grassHeight, float time, float2 rippleFreq, // x = base freq, y = directional freq float2 rippleSpeed, // x = base speed, y = directional speed float rippleStrength, // overall wave intensity float verticalFactor, // Y axis motion factor out float3 waveOffset) { // Normalize horizontal wind direction (XZ) float2 windXZ = normalize(float2(windDir.x, windDir.z)); float2 posXZ = float2(worldPos.x, worldPos.z); float windAlignment = dot(posXZ, windXZ); // Directional wave (along wind direction) float directionalWave = sin(windAlignment * rippleFreq.y + time * rippleSpeed.y); // Base ambient wave float baseWave = sin(worldPos.x * rippleFreq.x + time * rippleSpeed.x) * cos(worldPos.z * rippleFreq.x + time * rippleSpeed.x); // Final wave strength with combined ripple effect float waveStrength = (baseWave * 0.7 + directionalWave * 0.3) * grassHeight * rippleStrength; // Offset calculation waveOffset = float3( windDir.x * waveStrength, windDir.y * waveStrength * verticalFactor, windDir.z * waveStrength ); }