Newer
Older
Hierarchical-Task-Network-Unity-3D / Assets / Shaders / HLSL / GrassBladeData.hlsl
#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
    );
}