// // conventions // left = coord.x - 1 // right = coord.x + 1 // top = coord.y + 1 // bottom = coord.y - 1 // //#include "../../../Shaders/NoiseLib/Noise.hlsl" //Texture2D PrecipMask; //defines where rainfall will occur Texture2D ReposeMask; Texture2D Collision; Texture2D TerrainHeightPrev; //previous frame Texture2D SedimentPrev; Texture2D Hardness; //outputs RWTexture2D TerrainHeight; //terrain heightmap RWTexture2D Sediment; //suspended sediment concentration (being transported by the water) float dt; //the time step for the simulation float EffectScalar; float4 texDim; //the dimensions of all of our textures (they must all be the same dimensions) float3 terrainDim; //the dimensions of the terrain in world units #define LEFT(C) C.y #define RIGHT(C) C.x #define TOP(C) C.z #define BOTTOM(C) C.w uint4 getSafeNeighbors(uint2 coord) { return uint4( (coord.x < (uint)texDim[0] - 1) ? coord.x + 1 : coord.x, //right index (coord.x > 0) ? coord.x - 1 : coord.x, //left index (coord.y < (uint)texDim[1] - 1) ? coord.y + 1 : coord.y, //top index (coord.y > 0) ? coord.y - 1 : coord.y //bottom index ); } // // Thermal Erosion // float4 angleOfRepose; //actually tan(theta), which is slope (m) float4 dxdy; // float InvDiagMag; void simulateThermalErosion(uint2 coord) { uint4 neigh = getSafeNeighbors(coord); float4 hCardinal = float4(TerrainHeightPrev[uint2(LEFT(neigh), coord.y)], //left TerrainHeightPrev[uint2(RIGHT(neigh), coord.y)], //right TerrainHeightPrev[uint2(coord.x, TOP(neigh))], //up TerrainHeightPrev[uint2(coord.x, BOTTOM(neigh))]); //down float4 hDiagonal = float4(TerrainHeightPrev[uint2(LEFT(neigh), TOP(neigh))], //top left TerrainHeightPrev[uint2(RIGHT(neigh), TOP(neigh))], //top right TerrainHeightPrev[uint2(LEFT(neigh), BOTTOM(neigh))], //bottom left TerrainHeightPrev[uint2(RIGHT(neigh), BOTTOM(neigh))]); //bottom right /* float4 hardnessCardinal = saturate(float4(Hardness[uint2(neigh.y, coord.y)], Hardness[uint2(neigh.x, coord.y)], Hardness[uint2(coord.x, neigh.z)], Hardness[uint2(coord.x, neigh.w)])); float4 hardnessDiagonal = saturate(float4(Hardness[uint2(neigh.y, neigh.z)], Hardness[uint2(neigh.x, neigh.z)], Hardness[uint2(neigh.y, neigh.w)], Hardness[uint2(neigh.x, neigh.w)])); */ float4 h = float4(TerrainHeightPrev[coord], TerrainHeightPrev[coord], TerrainHeightPrev[coord], TerrainHeightPrev[coord]); float4 dhCardinal = terrainDim[1] * (h - hCardinal); float4 dhDiagonal = terrainDim[1] * (h - hDiagonal); float4 sCardinal = -1.0f * min(sign(dhCardinal), 0.0f); float4 sDiagonal = -1.0f * min(sign(dhDiagonal), 0.0f); /* float4 cHardness = saturate(Hardness[coord]); float4 hardness = lerp(cHardness, hardnessCardinal, sCardinal); dhCardinal *= 1.0f - hardness; hardness = lerp(cHardness, hardnessDiagonal, sDiagonal); dhDiagonal *= 1.0f - hardness; */ //compute slopes float4 mCardinal = abs(dhCardinal * float4(dxdy.z, dxdy.z, dxdy.w, dxdy.w)); float4 mDiagonal = abs(dhDiagonal * float4(InvDiagMag, InvDiagMag, InvDiagMag, InvDiagMag)); float tau = angleOfRepose.x; float dv = 0.0f; //volume of sediment moved //could probably vectorize this and eliminate the ifs... if (mCardinal.x > tau) { dv += dhCardinal.x; } if (mCardinal.y > tau) { dv += dhCardinal.y; } if (mCardinal.z > tau) { dv += dhCardinal.z; } if (mCardinal.w > tau) { dv += dhCardinal.w; } if (mDiagonal.x > tau) { dv += 0.707f * dhDiagonal.x; } if (mDiagonal.y > tau) { dv += 0.707f * dhDiagonal.y; } if (mDiagonal.z > tau) { dv += 0.707f * dhDiagonal.z; } if (mDiagonal.w > tau) { dv += 0.707f * dhDiagonal.w; } float halfHeight = 0.5f * TerrainHeightPrev[coord]; dv = clamp(0.0625f * dt * dv, -halfHeight, halfHeight); TerrainHeight[coord] = TerrainHeightPrev[coord] - dv; Sediment[coord] += dv; } #pragma kernel ThermalErosion [numthreads(8, 8, 1)] void ThermalErosion(uint3 id : SV_DispatchThreadID) { simulateThermalErosion(id.xy); }