Editor/TerrainShapes/Planetary.cs
using Editor;
using Sandbox;
using System;
using System.Collections.Generic;
namespace Sturnus.TerrainGenerationTool;
public static class Planetary
{
public static float Sharded(
int x,
int y,
int width,
int height,
long seed,
float minHeight,
bool warp, // Apply domain warping
float warpSize, // Warp scale
float warpStrength // Warp strength
)
{
Random random = new Random( (int)(seed & 0xFFFFFFFF) );
float nx = (x / (float)width) * 2 - 1; // Normalize x to range [-1, 1]
float ny = (y / (float)height) * 2 - 1; // Normalize y to range [-1, 1]
float shardHeight = 10f;
float crackDepth = 1f;
float noiseStrength = 0.05f;
int cellCount = 5;
// Apply domain warping for irregularity
if ( warp )
{
float warpX = OpenSimplex2S.Noise2( seed + 10, nx * warpSize, ny * warpSize ) * warpStrength;
float warpY = OpenSimplex2S.Noise2( seed + 11, nx * warpSize, ny * warpSize ) * warpStrength;
nx += warpX;
ny += warpY;
}
// Generate cracks
float minDist = float.MaxValue;
float secondaryDist = float.MaxValue;
float cellSize = 2.0f / cellCount; // Normalize the cell size
for ( int i = 0; i < cellCount; i++ )
{
for ( int j = 0; j < cellCount; j++ )
{
float cellX = -1 + i * cellSize + OpenSimplex2S.Noise2( seed + 20, i, j ) * cellSize * 0.5f;
float cellY = -1 + j * cellSize + OpenSimplex2S.Noise2( seed + 21, i, j ) * cellSize * 0.5f;
float distance = MathF.Sqrt( (nx - cellX) * (nx - cellX) + (ny - cellY) * (ny - cellY) );
if ( distance < minDist )
{
secondaryDist = minDist;
minDist = distance;
}
else if ( distance < secondaryDist )
{
secondaryDist = distance;
}
}
}
// Compute shard height based on the secondary distance
float shardNoise = OpenSimplex2S.Noise2( seed + 30, nx, ny ) * noiseStrength;
float heightValue = MathF.Max( secondaryDist - minDist, 0f ) * shardHeight + shardNoise;
// Apply crack depth at borders between shards
if ( secondaryDist - minDist < 0.03f ) // Control the width of cracks
{
heightValue -= crackDepth;
}
// Add a baseline value to ensure no flat zero areas
//heightValue = MathF.Max( heightValue, minHeight );
// Clamp height to avoid negative values
heightValue = Math.Clamp( heightValue, 0, 1 );
float baseline = minHeight; // Minimum height
float heightValueCombined = MathF.Max( heightValue, baseline );
// Clamp the final height to valid range
return heightValueCombined;
}
public static float Craters(
int x,
int y,
int width,
int height,
long seed,
float minHeight,
bool warp, // Apply domain warping for irregularity
float warpSize, // Warp scale
float warpStrength // Warp strength
)
{
Random random = new Random( (int)(seed & 0xFFFFFFFF) );
float nx = (x / (float)width) * 2 - 1; // Normalize x to range [-1, 1]
float ny = (y / (float)height) * 2 - 1; // Normalize y to range [-1, 1]
int craterCount = 100;
float minCraterSize = 0.1f;
float maxCraterSize = 0.3f;
float craterDepth = 0.05f;
float rimHeight = 0.05f;
float rimWidthRatio = 0.2f;
float noiseStrength = 0.05f;
float largeCraterRatio = 0.2f;
float slopeFalloff = 0.9f; // Controls smoothness of ramps
// Apply domain warping for irregularity
if ( warp )
{
float warpX = OpenSimplex2S.Noise2( seed + 10, nx * warpSize, ny * warpSize ) * warpStrength;
float warpY = OpenSimplex2S.Noise2( seed + 11, nx * warpSize, ny * warpSize ) * warpStrength;
nx += warpX;
ny += warpY;
}
// Base terrain noise
float baseTerrain = OpenSimplex2S.Noise2( seed + 1, nx * 2.0f, ny * 2.0f ) * noiseStrength;
baseTerrain = (baseTerrain + 1) * 0.5f; // Normalize to [0, 1]
float heightValue = baseTerrain;
// Iterate through craters in reverse order to overwrite previous craters
for ( int i = craterCount - 1; i >= 0; i-- )
{
// Randomize crater properties
float craterX = random.Next( -100000, 100000 ) / 50000.0f;
float craterY = random.Next( -100000, 100000 ) / 50000.0f;
float craterRadius = (i < craterCount * largeCraterRatio)
? random.Next( (int)(maxCraterSize * 500), (int)(maxCraterSize * 1000) ) / 1000.0f // Large craters
: random.Next( (int)(minCraterSize * 500), (int)(minCraterSize * 1000) ) / 1000.0f; // Small craters
// Distance from the current point to the crater center
float distance = MathF.Sqrt( (nx - craterX) * (nx - craterX) + (ny - craterY) * (ny - craterY) );
if ( distance < craterRadius )
{
float rimStart = craterRadius * (1f - rimWidthRatio);
float rimEnd = craterRadius;
// Inside the pit
if ( distance < rimStart )
{
float pitFalloff = Math.Clamp( 1f - (distance / rimStart), 0f, 1f );
heightValue = baseTerrain - MathF.Pow( pitFalloff, slopeFalloff ) * craterDepth; // Smooth ramp to the center
}
// Raised rim
else if ( distance >= rimStart && distance < rimEnd )
{
float rimFalloff = Math.Clamp( (distance - rimStart) / (rimEnd - rimStart), 0f, 1f );
heightValue = baseTerrain + MathF.Pow( 1f - rimFalloff, slopeFalloff ) * rimHeight; // Rounded rim
}
// Reset terrain below the rim to prevent intersecting ridges
if ( distance >= rimEnd )
{
heightValue = baseTerrain;
}
// Exit the loop once the current crater is applied
break;
}
}
// Ensure height values are clamped to [0, 1]
heightValue = Math.Clamp( heightValue, 0, 1 );
return heightValue;
}
}