diff --git a/.forgejo/01plates.png b/.forgejo/01plates.png new file mode 100644 index 0000000..e4f2679 --- /dev/null +++ b/.forgejo/01plates.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4474dfe2656785d8df368dfc61a0b6dd11021c229669c64f9eddd2f790fb6c68 +size 126061 diff --git a/.forgejo/02oceans.png b/.forgejo/02oceans.png new file mode 100644 index 0000000..2103f65 --- /dev/null +++ b/.forgejo/02oceans.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c8d2626d214f70432668b55e5a17960f3519a8ef0f3f2cf968f7f4d5147220ea +size 137088 diff --git a/.forgejo/03stresses.png b/.forgejo/03stresses.png new file mode 100644 index 0000000..67479dd --- /dev/null +++ b/.forgejo/03stresses.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:53835e85efba47bcaa1a281bae7ae418260a521bb6bf3264a895d8f850656707 +size 140915 diff --git a/.forgejo/04planet.png b/.forgejo/04planet.png new file mode 100644 index 0000000..b731a90 --- /dev/null +++ b/.forgejo/04planet.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:283cfaaec5b21c34108035f533be87dcb4a13cef421427830f4a0a800291c6b6 +size 224211 diff --git a/.forgejo/export.png b/.forgejo/export.png index 7fc3e36..c35cfe3 100644 --- a/.forgejo/export.png +++ b/.forgejo/export.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:47b72f11557cf5b2060054f1d640bb42279a58ba34b3d9b37e25af10101e6bbb -size 102368 +oid sha256:41ae2d919475771f50b155aab54e2dc6b2c3add357f3883908701f67c6922348 +size 613281 diff --git a/.forgejo/planet.png b/.forgejo/planet.png deleted file mode 100644 index 99fb00b..0000000 --- a/.forgejo/planet.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:2ce30336f743e552d2820d9b328c530d2de2666d0fa748c27a9255917c6b1909 -size 262214 diff --git a/.forgejo/projection.png b/.forgejo/projection.png index 8b2fe90..6d39d60 100644 --- a/.forgejo/projection.png +++ b/.forgejo/projection.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5a3dc6ce3038331d578f5f804ce02cda5cc4e7a722c0dc8bf63240a23b7e5839 -size 770350 +oid sha256:71b10ccdc61002f7d6bd9ed1c6e0276db0422b5216cd0dbff92b026d70c9dc3f +size 601515 diff --git a/.forgejo/time.png b/.forgejo/time.png new file mode 100644 index 0000000..77424a3 --- /dev/null +++ b/.forgejo/time.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9afa68b8851ca555076b0780734b0a03fe7af1ef4bfd6fed168d2c3c59518cd7 +size 208412 diff --git a/PlanetLow.mtl b/PlanetLow.mtl deleted file mode 100644 index 84f636a..0000000 --- a/PlanetLow.mtl +++ /dev/null @@ -1,2 +0,0 @@ -# Blender 5.0.1 MTL File: 'None' -# www.blender.org diff --git a/README.md b/README.md index c8dfb02..de93358 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,9 @@ # 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) Planet generation with simple plate tectonics. diff --git a/adatonic.sln.DotSettings.user b/adatonic.sln.DotSettings.user index ceb9423..5f589d5 100644 --- a/adatonic.sln.DotSettings.user +++ b/adatonic.sln.DotSettings.user @@ -1,6 +1,8 @@  + ForceIncluded ForceIncluded ForceIncluded ForceIncluded ForceIncluded - ForceIncluded \ No newline at end of file + ForceIncluded + ForceIncluded \ No newline at end of file diff --git a/project.godot b/project.godot index 23d21db..414f41a 100644 --- a/project.godot +++ b/project.godot @@ -50,5 +50,3 @@ mouse_secondary={ [rendering] rendering_device/driver.windows="d3d12" -renderer/rendering_method="gl_compatibility" -renderer/rendering_method.mobile="gl_compatibility" diff --git a/shaders/compute/PlateExpansion.glsl b/shaders/compute/PlateExpansion.glsl new file mode 100644 index 0000000..32990c4 --- /dev/null +++ b/shaders/compute/PlateExpansion.glsl @@ -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]; + } + } + } + +} diff --git a/shaders/compute/PlateExpansion.glsl.import b/shaders/compute/PlateExpansion.glsl.import new file mode 100644 index 0000000..8be2164 --- /dev/null +++ b/shaders/compute/PlateExpansion.glsl.import @@ -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] + diff --git a/shaders/compute/compute_example.glsl b/shaders/compute/compute_example.glsl new file mode 100644 index 0000000..c3e3ce3 --- /dev/null +++ b/shaders/compute/compute_example.glsl @@ -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; +} diff --git a/shaders/compute/compute_example.glsl.import b/shaders/compute/compute_example.glsl.import new file mode 100644 index 0000000..4dbf9d7 --- /dev/null +++ b/shaders/compute/compute_example.glsl.import @@ -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] + diff --git a/src/Main.cs b/src/Main.cs index 7d79a6d..9932642 100644 --- a/src/Main.cs +++ b/src/Main.cs @@ -1,10 +1,13 @@ #nullable enable using Godot; using System; +using System.Collections.Generic; using System.Globalization; using System.IO; using System.Linq; +using System.Threading.Tasks; using Godot.Collections; +using Array = System.Array; public partial class Main : Control { @@ -39,6 +42,43 @@ public partial class Main : Control Projector.GatherPoints(_planetHelper, int.Parse(GetNode("%Resolution").Text)); AxialTiltChanged(GetNode("%AxialTilt").Text); 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; diff --git a/src/Oct.cs b/src/Oct.cs index ce1722a..f1bf1fb 100644 --- a/src/Oct.cs +++ b/src/Oct.cs @@ -139,6 +139,10 @@ public class Oct } 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; } } \ No newline at end of file diff --git a/src/PlanetHelper.cs b/src/PlanetHelper.cs index 29efbf0..04f9a71 100644 --- a/src/PlanetHelper.cs +++ b/src/PlanetHelper.cs @@ -56,7 +56,7 @@ public class PlanetHelper } private bool StageComplete = true; - private int _plateCount = 14; + private int _plateCount = 12; private float _landRatio = 0.4f; public List Plates = new List(); @@ -101,6 +101,9 @@ public class PlanetHelper public Oct Octree = new Oct(); private Curve _remapCurve; + private RenderingDevice _rd; + private Rid _shader; + public PlanetHelper(MeshInstance3D meshInstance, TextureRect textureRect, Curve remapCurve) { _meshInstance = meshInstance; @@ -132,6 +135,11 @@ public class PlanetHelper textureShaderMaterial.SetShaderParameter("mode", 1); } UpdateMesh(); + + _rd = RenderingServer.CreateLocalRenderingDevice(); + var shaderFile = GD.Load("res://shaders/compute/PlateExpansion.glsl"); + var shaderBytecode = shaderFile.GetSpirV(); + _shader = _rd.ShaderCreateFromSpirV(shaderBytecode); } public void InitializeGeneration() @@ -156,7 +164,6 @@ public class PlanetHelper VertexData vertex = Vertices.Where(v => v.PlateId == -1).OrderBy(v => Guid.NewGuid()).First(); vertex.PlateId = i; 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]); plate.MovementAxis = GetRandomVector3(); @@ -168,7 +175,7 @@ public class PlanetHelper public IEnumerable GetNeighboringVertices(int vertexId, bool blackOnly = true) { - if (Stage != GenerationStage.Initialization) + if (Stage != GenerationStage.Initialization && Stage != GenerationStage.NotStarted) { if (blackOnly) return Vertices[vertexId].Neighbours.Where(n => Vertices[n].PlateId == -1); @@ -296,33 +303,84 @@ public class PlanetHelper public void PlateGeneration() { - var availableVerts = Vertices.Where(d => d.StageComplete == false && d.PlateId != -1).OrderBy(v => Guid.NewGuid()).ToList(); - foreach (PlateData plateData in Plates) - { - var plateVerts = availableVerts.Where(d => d.PlateId == plateData.Id); - foreach (VertexData vertexData in plateVerts.Take((int)((5 + plateVerts.Count() / 4) * plateData.PlateExpansion))) - { - int expandTo = GetFreeNeighbourIndex(vertexData); - if (expandTo != -1) - { - Vertices[expandTo].PlateId = plateData.Id; - plateData.Vertices.Add(expandTo); - ColorVertex(expandTo, plateData.Color); - } - else - { - vertexData.StageComplete = true; - } - } - } + // Prepare our data. We use floats in the shader, so we need 32 bit. + 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); - if (!availableVerts.Any()) + 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 { - foreach (VertexData vertexData in Vertices) - vertexData.StageComplete = false; - AssignOceanPlates(Plates); - CompleteStage(); + UniformType = RenderingDevice.UniformType.StorageBuffer, + 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) + { + Mdt.SetVertexColor(index, Plates[plate].Color); + Vertices[index].PlateId = plate; + } + index++; } + + _rd.FreeRid(pipeline); + _rd.FreeRid(uniformSet); + _rd.FreeRid(pointBuffer); + _rd.FreeRid(plateBuffer); + _rd.FreeRid(neighborBuffer); + + AssignOceanPlates(Plates); + CompleteStage(); } public void BorderSearch() {