Compare commits

..

3 commits

Author SHA1 Message Date
Aada
b0caa8c8ad readme update 2026-03-09 11:47:59 +02:00
Aada
9ab7191c95 1030% faster comp shader 2026-03-09 08:01:39 +02:00
Aada
47ca1265e6 Initial Compute Shader for Plate Generation. 2026-03-09 07:09:52 +02:00
19 changed files with 242 additions and 41 deletions

BIN
.forgejo/01plates.png (Stored with Git LFS) Normal file

Binary file not shown.

BIN
.forgejo/02oceans.png (Stored with Git LFS) Normal file

Binary file not shown.

BIN
.forgejo/03stresses.png (Stored with Git LFS) Normal file

Binary file not shown.

BIN
.forgejo/04planet.png (Stored with Git LFS) Normal file

Binary file not shown.

BIN
.forgejo/export.png (Stored with Git LFS)

Binary file not shown.

BIN
.forgejo/planet.png (Stored with Git LFS)

Binary file not shown.

BIN
.forgejo/projection.png (Stored with Git LFS)

Binary file not shown.

BIN
.forgejo/time.png (Stored with Git LFS) Normal file

Binary file not shown.

View file

@ -1,2 +0,0 @@
# Blender 5.0.1 MTL File: 'None'
# www.blender.org

View file

@ -1,5 +1,9 @@
# Adatonics # Adatonics
![Planet View](.forgejo/planet.png?raw=true) ![Plates View](.forgejo/01plates.png?raw=true)
![Oceans View](.forgejo/02oceans.png?raw=true)
![Stresses View](.forgejo/03stresses.png?raw=true)
![Planet View](.forgejo/04planet.png?raw=true)
![Time View](.forgejo/time.png?raw=true)
![Projection View](.forgejo/projection.png?raw=true) ![Projection View](.forgejo/projection.png?raw=true)
Planet generation with simple plate tectonics. Planet generation with simple plate tectonics.

View file

@ -1,6 +1,8 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation"> <wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ABuffer_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003Fhome_003Fade9_003F_002Econfig_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F2e87203df15b4d60b9c670dd76fb5ed8dba400_003Fda_003Fba7fca04_003FBuffer_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AMain_005FScriptMethods_002Egenerated_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003Fhome_003Fade9_003F_002Econfig_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FSourcesCache_003Fb637bee5badc9b536d43ca23ca5744325c67bb7_003FMain_005FScriptMethods_002Egenerated_002Ecs/@EntryIndexedValue">ForceIncluded</s:String> <s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AMain_005FScriptMethods_002Egenerated_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003Fhome_003Fade9_003F_002Econfig_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FSourcesCache_003Fb637bee5badc9b536d43ca23ca5744325c67bb7_003FMain_005FScriptMethods_002Egenerated_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ARandom_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003Fhome_003Fade9_003F_002Econfig_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F2e87203df15b4d60b9c670dd76fb5ed8dba400_003F3a_003F5188629f_003FRandom_002Ecs/@EntryIndexedValue">ForceIncluded</s:String> <s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ARandom_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003Fhome_003Fade9_003F_002Econfig_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F2e87203df15b4d60b9c670dd76fb5ed8dba400_003F3a_003F5188629f_003FRandom_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AThrowHelpers_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003Fhome_003Fade9_003F_002Econfig_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F2e87203df15b4d60b9c670dd76fb5ed8dba400_003F61_003Fd1d5ae77_003FThrowHelpers_002Ecs/@EntryIndexedValue">ForceIncluded</s:String> <s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AThrowHelpers_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003Fhome_003Fade9_003F_002Econfig_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F2e87203df15b4d60b9c670dd76fb5ed8dba400_003F61_003Fd1d5ae77_003FThrowHelpers_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AThrowHelper_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003Fhome_003Fade9_003F_002Econfig_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F2e87203df15b4d60b9c670dd76fb5ed8dba400_003F8c_003F9b15e004_003FThrowHelper_002Ecs/@EntryIndexedValue">ForceIncluded</s:String> <s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AThrowHelper_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003Fhome_003Fade9_003F_002Econfig_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F2e87203df15b4d60b9c670dd76fb5ed8dba400_003F8c_003F9b15e004_003FThrowHelper_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AThrowHelper_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003Fhome_003Fade9_003F_002Econfig_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fa7769c42125c450287f439cf7637d25b83800_003F36_003F88fa510a_003FThrowHelper_002Ecs_002Fz_003A2_002D1/@EntryIndexedValue">ForceIncluded</s:String></wpf:ResourceDictionary> <s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AThrowHelper_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003Fhome_003Fade9_003F_002Econfig_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fa7769c42125c450287f439cf7637d25b83800_003F36_003F88fa510a_003FThrowHelper_002Ecs_002Fz_003A2_002D1/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AVector3_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003Fhome_003Fade9_003F_002Econfig_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fe75fb6fe099340ae9d8990439df61a4e5e7a00_003F1b_003F5a8b8bc4_003FVector3_002Ecs/@EntryIndexedValue">ForceIncluded</s:String></wpf:ResourceDictionary>

View file

@ -50,5 +50,3 @@ mouse_secondary={
[rendering] [rendering]
rendering_device/driver.windows="d3d12" rendering_device/driver.windows="d3d12"
renderer/rendering_method="gl_compatibility"
renderer/rendering_method.mobile="gl_compatibility"

View file

@ -0,0 +1,40 @@
#[compute]
#version 450
// Invocations in the (x, y, z) dimension
layout(local_size_x = 25, local_size_y = 1, local_size_z = 1) in;
// A binding to the buffer we create in our script
layout(set = 0, binding = 0, std430) restrict buffer PointBuffer {
int points[];
}
pointbuffer;
layout(set = 0, binding = 1, std430) restrict buffer NeighborBuffer {
int neighbors[];
}
neighborbuffer;
layout(set = 0, binding = 2, std430) restrict buffer PlateBuffer {
int plateid[];
}
platebuffer;
// The code we want to execute in each invocation
void main() {
// Iteration is gl_GlobalInvocationID.x
// Neighbors for Point gl_GlobalInvocationID.y
for (int point = 0; point < int(gl_WorkGroupSize.x); point++)
{
int localpoint = int(gl_WorkGroupID.x)*int(gl_WorkGroupSize.x) + point;
for (int neighbor = 0; neighbor < 6; neighbor++) {
if (neighborbuffer.neighbors[localpoint*6+neighbor] == -1)
{
continue;
}
if (platebuffer.plateid[localpoint] != -1 && platebuffer.plateid[neighborbuffer.neighbors[localpoint*6+neighbor]] == -1)
{
// Neighbor unclaimed, and we can claim it.
platebuffer.plateid[neighborbuffer.neighbors[localpoint*6+neighbor]] = platebuffer.plateid[localpoint];
}
}
}
}

View file

@ -0,0 +1,14 @@
[remap]
importer="glsl"
type="RDShaderFile"
uid="uid://cypd2lshixd17"
path="res://.godot/imported/PlateExpansion.glsl-9047ef54068b6d1a50f93c2cd303b382.res"
[deps]
source_file="res://shaders/compute/PlateExpansion.glsl"
dest_files=["res://.godot/imported/PlateExpansion.glsl-9047ef54068b6d1a50f93c2cd303b382.res"]
[params]

View file

@ -0,0 +1,17 @@
#[compute]
#version 450
// Invocations in the (x, y, z) dimension
layout(local_size_x = 2, local_size_y = 1, local_size_z = 1) in;
// A binding to the buffer we create in our script
layout(set = 0, binding = 0, std430) restrict buffer MyDataBuffer {
float data[];
}
my_data_buffer;
// The code we want to execute in each invocation
void main() {
// gl_GlobalInvocationID.x uniquely identifies this invocation across all work groups
my_data_buffer.data[gl_GlobalInvocationID.x] *= 2.0;
}

View file

@ -0,0 +1,14 @@
[remap]
importer="glsl"
type="RDShaderFile"
uid="uid://du2kf2vmf800w"
path="res://.godot/imported/compute_example.glsl-3f04b63d0b43774004ed10776fd05117.res"
[deps]
source_file="res://shaders/compute/compute_example.glsl"
dest_files=["res://.godot/imported/compute_example.glsl-3f04b63d0b43774004ed10776fd05117.res"]
[params]

View file

@ -1,10 +1,13 @@
#nullable enable #nullable enable
using Godot; using Godot;
using System; using System;
using System.Collections.Generic;
using System.Globalization; using System.Globalization;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Threading.Tasks;
using Godot.Collections; using Godot.Collections;
using Array = System.Array;
public partial class Main : Control public partial class Main : Control
{ {
@ -39,6 +42,43 @@ public partial class Main : Control
Projector.GatherPoints(_planetHelper, int.Parse(GetNode<LineEdit>("%Resolution").Text)); Projector.GatherPoints(_planetHelper, int.Parse(GetNode<LineEdit>("%Resolution").Text));
AxialTiltChanged(GetNode<LineEdit>("%AxialTilt").Text); AxialTiltChanged(GetNode<LineEdit>("%AxialTilt").Text);
UpdateTime(); UpdateTime();
_planetHelper.InitializeGeneration();
_planetHelper.Plates[0].Color = _planetHelper.GetInitialColor(true);
//_planetHelper.Plates[1].Color = _planetHelper.GetInitialColor(true);
//_planetHelper.Plates[2].Color = _planetHelper.GetInitialColor(false);
//_planetHelper.Plates[3].Color = _planetHelper.GetInitialColor(false);
// for (int i = 0; i < 1; i++)
// {
// for (int point = 0; point < points.Length; point++)
// {
// for (int neighbor = 0; neighbor < 6; neighbor++)
// {
// if (neighbors[point * 6 + neighbor] == -1)
// {
// continue;
// }
//
// int x = plateids[point];
// int y = neighbors[point * 6 + neighbor];
// int z = plateids[y];
// if (x != -1 && z == -1)
// {
// // Neighbor unclaimed, and we can claim it.
// plateids[neighbors[point * 6 +neighbor]] = plateids[point];
// }
// }
// }
// }
// int index = 0;
// foreach (int plate in plateids)
// {
// if (plate != -1)
// _planetHelper.Mdt.SetVertexColor(index, _planetHelper.Plates[plate].Color);
// index++;
// }
// _planetHelper.UpdateMesh();
} }
Vector3 _pointerPosition = Vector3.Zero; Vector3 _pointerPosition = Vector3.Zero;

View file

@ -139,6 +139,10 @@ public class Oct
} }
public bool IsInside(Vector3 position) public bool IsInside(Vector3 position)
{ {
return position > Start && position < Start + Extent; Vector3 max = Start + Extent;
return position.X >= Start.X && position.X <= max.X &&
position.Y >= Start.Y && position.Y <= max.Y &&
position.Z >= Start.Z && position.Z <= max.Z;
} }
} }

View file

@ -56,7 +56,7 @@ public class PlanetHelper
} }
private bool StageComplete = true; private bool StageComplete = true;
private int _plateCount = 14; private int _plateCount = 12;
private float _landRatio = 0.4f; private float _landRatio = 0.4f;
public List<PlateData> Plates = new List<PlateData>(); public List<PlateData> Plates = new List<PlateData>();
@ -101,6 +101,9 @@ public class PlanetHelper
public Oct Octree = new Oct(); public Oct Octree = new Oct();
private Curve _remapCurve; private Curve _remapCurve;
private RenderingDevice _rd;
private Rid _shader;
public PlanetHelper(MeshInstance3D meshInstance, TextureRect textureRect, Curve remapCurve) public PlanetHelper(MeshInstance3D meshInstance, TextureRect textureRect, Curve remapCurve)
{ {
_meshInstance = meshInstance; _meshInstance = meshInstance;
@ -132,6 +135,11 @@ public class PlanetHelper
textureShaderMaterial.SetShaderParameter("mode", 1); textureShaderMaterial.SetShaderParameter("mode", 1);
} }
UpdateMesh(); UpdateMesh();
_rd = RenderingServer.CreateLocalRenderingDevice();
var shaderFile = GD.Load<RDShaderFile>("res://shaders/compute/PlateExpansion.glsl");
var shaderBytecode = shaderFile.GetSpirV();
_shader = _rd.ShaderCreateFromSpirV(shaderBytecode);
} }
public void InitializeGeneration() public void InitializeGeneration()
@ -156,7 +164,6 @@ public class PlanetHelper
VertexData vertex = Vertices.Where(v => v.PlateId == -1).OrderBy(v => Guid.NewGuid()).First(); VertexData vertex = Vertices.Where(v => v.PlateId == -1).OrderBy(v => Guid.NewGuid()).First();
vertex.PlateId = i; vertex.PlateId = i;
var color = new Color(RandF(0f, 1f), RandF(0f, 1f), RandF(0f, 1f)); var color = new Color(RandF(0f, 1f), RandF(0f, 1f), RandF(0f, 1f));
ColorVertex(vertex.Id, color);
PlateData plate = new PlateData(i, color, false, [vertex.Id]); PlateData plate = new PlateData(i, color, false, [vertex.Id]);
plate.MovementAxis = GetRandomVector3(); plate.MovementAxis = GetRandomVector3();
@ -168,7 +175,7 @@ public class PlanetHelper
public IEnumerable<int> GetNeighboringVertices(int vertexId, bool blackOnly = true) public IEnumerable<int> GetNeighboringVertices(int vertexId, bool blackOnly = true)
{ {
if (Stage != GenerationStage.Initialization) if (Stage != GenerationStage.Initialization && Stage != GenerationStage.NotStarted)
{ {
if (blackOnly) if (blackOnly)
return Vertices[vertexId].Neighbours.Where(n => Vertices[n].PlateId == -1); return Vertices[vertexId].Neighbours.Where(n => Vertices[n].PlateId == -1);
@ -296,33 +303,84 @@ public class PlanetHelper
public void PlateGeneration() public void PlateGeneration()
{ {
var availableVerts = Vertices.Where(d => d.StageComplete == false && d.PlateId != -1).OrderBy(v => Guid.NewGuid()).ToList(); // Prepare our data. We use floats in the shader, so we need 32 bit.
foreach (PlateData plateData in Plates) int[] points = Enumerable.Range(0, Mdt.GetVertexCount()).ToArray();
var sizePoints = points.Length * sizeof(int);
int[] neighbors = Vertices.SelectMany(v => v.Neighbours.Count < 6 ? [..v.Neighbours.ToArray(),-1] : v.Neighbours.ToArray()).ToArray();
var sizeNeighbors = neighbors.Length * sizeof(int);
int[] plateids = Vertices.Select(v => v.PlateId).ToArray();
var sizePlateids = plateids.Length * sizeof(int);
var pointBytes = new byte[sizePoints];
byte[] neighborBytes = new byte[sizeNeighbors];
var plateBytes = new byte[sizePlateids];
Buffer.BlockCopy(points, 0, pointBytes, 0, pointBytes.Length);
Buffer.BlockCopy(neighbors, 0, neighborBytes, 0, neighborBytes.Length);
Buffer.BlockCopy(plateids, 0, plateBytes, 0, plateBytes.Length);
// Create a uniform to assign the buffer to the rendering device
var pointUniform = new RDUniform
{ {
var plateVerts = availableVerts.Where(d => d.PlateId == plateData.Id); UniformType = RenderingDevice.UniformType.StorageBuffer,
foreach (VertexData vertexData in plateVerts.Take((int)((5 + plateVerts.Count() / 4) * plateData.PlateExpansion))) Binding = 0
};
var pointBuffer = _rd.StorageBufferCreate((uint)pointBytes.Length, pointBytes);
pointUniform.AddId(pointBuffer);
var neighborUniform = new RDUniform
{
UniformType = RenderingDevice.UniformType.StorageBuffer,
Binding = 1
};
var neighborBuffer = _rd.StorageBufferCreate((uint)neighborBytes.Length, neighborBytes);
neighborUniform.AddId(neighborBuffer);
var plateUniform = new RDUniform
{
UniformType = RenderingDevice.UniformType.StorageBuffer,
Binding = 2
};
var plateBuffer = _rd.StorageBufferCreate((uint)plateBytes.Length, plateBytes);
plateUniform.AddId(plateBuffer);
var uniformSet = _rd.UniformSetCreate([pointUniform, neighborUniform, plateUniform], _shader, 0);
// Create a compute pipeline
var pipeline = _rd.ComputePipelineCreate(_shader);
var computeList = _rd.ComputeListBegin();
_rd.ComputeListBindComputePipeline(computeList, pipeline);
_rd.ComputeListBindUniformSet(computeList, uniformSet, 0);
uint xgroups = (uint)(Mathf.Ceil((double)points.Length / 25.0));
_rd.ComputeListDispatch(computeList, xGroups: xgroups, yGroups: 50, zGroups: 1);
_rd.ComputeListEnd();
_rd.Submit();
_rd.Sync();
// Read back the data from the buffers
var outputBytes = _rd.BufferGetData(plateBuffer);
var output = new int[plateids.Length];
Buffer.BlockCopy(outputBytes, 0, output, 0, plateBytes.Length);
int index = 0;
foreach (int plate in output)
{
if (plate != -1)
{ {
int expandTo = GetFreeNeighbourIndex(vertexData); Mdt.SetVertexColor(index, Plates[plate].Color);
if (expandTo != -1) Vertices[index].PlateId = plate;
{
Vertices[expandTo].PlateId = plateData.Id;
plateData.Vertices.Add(expandTo);
ColorVertex(expandTo, plateData.Color);
}
else
{
vertexData.StageComplete = true;
}
} }
index++;
} }
if (!availableVerts.Any()) _rd.FreeRid(pipeline);
{ _rd.FreeRid(uniformSet);
foreach (VertexData vertexData in Vertices) _rd.FreeRid(pointBuffer);
vertexData.StageComplete = false; _rd.FreeRid(plateBuffer);
AssignOceanPlates(Plates); _rd.FreeRid(neighborBuffer);
CompleteStage();
} AssignOceanPlates(Plates);
CompleteStage();
} }
public void BorderSearch() public void BorderSearch()
{ {