Project_WL/Assets/ResWork/Map/ProceduralGrass/Shaders/GrassInit.compute

177 lines
7.1 KiB
Plaintext

#pragma kernel Main
struct GrassOriginPoint {
float3 position;
uint clumpSecondaryID;
float clumpBaseToSecondaryRatio;
};
struct ClumpPoint {
float3 position;
float moveToCenter;
float pointInSameDirection;
float pointInSameDirectionAngle;
float pointInSameDirectionRelativeCenter;
float pointInSameDirectionAngleRelativeCenter;
float height;
float heightRandom;
float width;
float widthRandom;
float tilt;
float tiltRandom;
float bend;
float bendRandom;
};
struct GrassBlade {
float3 position;
float height;
float width;
float rotationAngle;
float rotationAngleCurrent;
float hash;
float tilt;
float bend;
float windStrength;
float3 surfaceNorm;
float clumpBaseToSecondaryRatio;
};
StructuredBuffer<GrassOriginPoint> _GrassOriginPoints;
RWStructuredBuffer<GrassBlade> _GrassBlades;
StructuredBuffer<ClumpPoint> _ClumpPoints;
uint grassOriginPointCount;
uint grassBladesPerPoint;
float bladeInstanceRadius;
Texture2D _HeightMap;
SamplerState sampler_HeightMap;
float _TerrainRotation;
float _TerrainForce;
float _MinX;
float _MinZ;
float _MaxX;
float _MaxZ;
float2 RotateUV(float2 uv, float angleDegrees) {
float angleRadians = radians(angleDegrees);
float cosA = cos(angleRadians);
float sinA = sin(angleRadians);
uv -= 0.5;
return float2(uv.x * cosA - uv.y * sinA, uv.x * sinA + uv.y * cosA) + 0.5;
}
float3 GetHeightAtWorldPosition(float2 WPosXZ){
float2 minWorldPos = float2(_MinX, _MinZ);
float2 maxWorldPos = float2(_MaxX, _MaxZ);
float2 birdViewUV = (WPosXZ - minWorldPos) / (maxWorldPos - minWorldPos);
birdViewUV = RotateUV(birdViewUV, _TerrainRotation);
birdViewUV = saturate(birdViewUV);
float height = _HeightMap.SampleLevel(sampler_HeightMap, birdViewUV, 0).x;
return float3(WPosXZ.x, height * _TerrainForce, WPosXZ.y);
}
float hash0To1(float3 co)
{
return frac(sin(dot(co.xyz, float3(12.9898, 78.233, 53.539))) * 43758.5453);
}
float LerpAngle(float angle1, float angle2, float t)
{
angle1 = fmod(angle1, 360.0);
angle2 = fmod(angle2, 360.0);
float angleDiff = abs(angle1 - angle2);
if (angleDiff > 180.0)
{
if (angle1 < angle2)
angle1 += 360.0;
else
angle2 += 360.0;
}
return lerp(angle1, angle2, t);
}
[numthreads(128,1,1)]
void Main (uint id : SV_DispatchThreadID)
{
if (id >= grassOriginPointCount) // No more grass to process
{
return;
}
GrassOriginPoint originPoint = _GrassOriginPoints[id.x];
float3 originPosition = originPoint.position;
float2 center = originPosition.xz;
float circumference = 2 * 3.14159265359 * bladeInstanceRadius;
float2 finalPosition;
ClumpPoint clumpBase = _ClumpPoints[0];
ClumpPoint clumpSecondary = _ClumpPoints[originPoint.clumpSecondaryID];
float startHeight = lerp(clumpBase.height, clumpSecondary.height, originPoint.clumpBaseToSecondaryRatio);
float randomHeight = lerp(clumpBase.heightRandom, clumpSecondary.heightRandom, originPoint.clumpBaseToSecondaryRatio);
float startWidth = lerp(clumpBase.width, clumpSecondary.width, originPoint.clumpBaseToSecondaryRatio);
float randomWidth = lerp(clumpBase.widthRandom, clumpSecondary.widthRandom, originPoint.clumpBaseToSecondaryRatio);
float startTilt = lerp(clumpBase.tilt, clumpSecondary.tilt, originPoint.clumpBaseToSecondaryRatio);
float randomTilt = lerp(clumpBase.tiltRandom, clumpSecondary.tiltRandom, originPoint.clumpBaseToSecondaryRatio);
float startBend = lerp(clumpBase.bend, clumpSecondary.bend, originPoint.clumpBaseToSecondaryRatio);
float randomBend = lerp(clumpBase.bendRandom, clumpSecondary.bendRandom, originPoint.clumpBaseToSecondaryRatio);
float clumpAngleRatio = lerp (0,clumpSecondary.pointInSameDirection, originPoint.clumpBaseToSecondaryRatio);
float clumpAngleRelativeCenterRatio = lerp (0,clumpSecondary.pointInSameDirectionRelativeCenter, originPoint.clumpBaseToSecondaryRatio);
for (uint i; i < grassBladesPerPoint; i++){
GrassBlade blade;
blade.hash = hash0To1(float3(originPosition.z, i, originPosition.x));
float angleHash = hash0To1(float3(originPosition.x, id.x, originPosition.z));
if (grassBladesPerPoint == 1){
finalPosition = originPosition.xz;
blade.rotationAngle = lerp(0.0f,360.0f, blade.hash);
}
else{
// Calculate the angle for the current point
float randomAngle = radians(360 * angleHash);
float angleMin = randomAngle + (float(i) / float(grassBladesPerPoint)) * 2 * 3.14159265359;
float angleMax = randomAngle + (float(i+1) / float(grassBladesPerPoint)) * 2 * 3.14159265359;
float angle = LerpAngle(angleMin, angleMax, blade.hash);
// Calculate the position of the point based on angle
float x = center.x + bladeInstanceRadius * cos(angle);
float y = center.y - bladeInstanceRadius * sin(angle);
float bladeRadiusMin = 0.0f; // Minimum radius value, Lower it to make it possible to be nearer the center.
float bladeRadiusMax = 1.0f;
finalPosition = lerp(originPosition.xz, float2(x, y), lerp(bladeRadiusMin, bladeRadiusMax, blade.hash)); // bring it towards center
blade.rotationAngle = degrees(angle);
}
finalPosition = lerp(finalPosition, clumpSecondary.position.xz , clumpSecondary.moveToCenter);
float2 directionToCenter = finalPosition - clumpSecondary.position.xz;
float angleToCenter = atan2(directionToCenter.y, directionToCenter.x);
blade.rotationAngle = LerpAngle(blade.rotationAngle, clumpSecondary.pointInSameDirectionAngle, clumpAngleRatio);
blade.rotationAngle = LerpAngle(blade.rotationAngle, degrees(-angleToCenter) - clumpSecondary.pointInSameDirectionAngleRelativeCenter, clumpAngleRelativeCenterRatio);
float randomAngleRatio = blade.hash * 2.0 - 1.0;
blade.rotationAngle = fmod(blade.rotationAngle, 360.0);
blade.rotationAngleCurrent = blade.rotationAngle;
blade.position = GetHeightAtWorldPosition(finalPosition);
blade.height = startHeight + randomHeight * blade.hash;
blade.width = startWidth + randomWidth * blade.hash;
blade.tilt = startTilt + randomTilt * blade.hash;
blade.bend = startBend + randomBend * blade.hash;
blade.windStrength = 0; // this gets calculated in update.
float2 bitangent = float2(1, 0);
float2 tangent = float2(0, 1);
float3 vertexBitangent = GetHeightAtWorldPosition(finalPosition + bitangent*0.01);
float3 vertexTangent = GetHeightAtWorldPosition(finalPosition + tangent*0.01);
float3 newBitangent = (vertexBitangent-blade.position ).xyz;
float3 newTangent = (vertexTangent-blade.position).xyz;
float3 norm = normalize(cross(newTangent,newBitangent));
blade.surfaceNorm = norm; // TODO calculate normals via texture
blade.clumpBaseToSecondaryRatio = originPoint.clumpBaseToSecondaryRatio; // TODO calculate normals via texture
_GrassBlades[id.x * grassBladesPerPoint + i] = blade;
}
}