Skip to content

Instantly share code, notes, and snippets.

@ChrisPritchard
Last active October 12, 2025 23:49
Show Gist options
  • Select an option

  • Save ChrisPritchard/2f907fdf743d7362824fbad5da7bbca0 to your computer and use it in GitHub Desktop.

Select an option

Save ChrisPritchard/2f907fdf743d7362824fbad5da7bbca0 to your computer and use it in GitHub Desktop.
Godot node script to generate cubes using two different approaches.
using System.Collections.Generic;
using Godot;
public partial class CubeTest : Node3D
{
private MeshInstance3D meshInstance;
private static readonly Color[] colour_set = [Colors.Red, Colors.Green, Colors.Blue, Colors.Yellow];
const int tower_width = 20;
const int tower_height = 200;
const int tower_depth = 20;
const float block_size = 1;
private int rerender_on_process = 0;
public override void _Ready()
{
meshInstance = new MeshInstance3D();
var material = new StandardMaterial3D()
{
VertexColorUseAsAlbedo = true,
ShadingMode = BaseMaterial3D.ShadingModeEnum.Unshaded
};
meshInstance.MaterialOverride = material;
AddChild(meshInstance);
meshInstance.Mesh = DrawTowerWithSurfaceTool();
GetNode<OptionButton>("%ProcessOptions").ItemSelected += index => rerender_on_process = (int)index;
GetNode<Button>("%RenderWithST").Pressed += () => meshInstance.Mesh = DrawTowerWithSurfaceTool();
GetNode<Button>("%RenderWithArrays").Pressed += () => meshInstance.Mesh = DrawTowerWithArrays();
}
public override void _Process(double delta)
{
if (rerender_on_process == 1)
meshInstance.Mesh = DrawTowerWithSurfaceTool();
else if (rerender_on_process == 2)
meshInstance.Mesh = DrawTowerWithArrays();
}
private static ArrayMesh DrawTowerWithArrays()
{
var vertices = new List<Vector3>(tower_width * tower_depth * tower_height * 8);
var colours = new List<Color>(vertices.Count);
var normals = new List<Vector3>(vertices.Count);
var indices = new List<int>(vertices.Count);
for (var x = 0; x < tower_width; x++)
for (var y = 0; y < tower_height; y++)
for (var z = 0; z < tower_depth; z++)
{
var blockPosition = new Vector3(x * block_size, y * block_size, z * block_size);
CreateBlockData(blockPosition, block_size, vertices, colours, normals, indices);
}
var arrays = new Godot.Collections.Array();
arrays.Resize((int)Mesh.ArrayType.Max);
arrays[(int)Mesh.ArrayType.Vertex] = vertices.ToArray();
arrays[(int)Mesh.ArrayType.Color] = colours.ToArray();
arrays[(int)Mesh.ArrayType.Normal] = normals.ToArray();
arrays[(int)Mesh.ArrayType.Index] = indices.ToArray();
var arrayMesh = new ArrayMesh();
arrayMesh.AddSurfaceFromArrays(Mesh.PrimitiveType.Triangles, arrays);
return arrayMesh;
}
private static void CreateBlockData(Vector3 position, float size, List<Vector3> vertices, List<Color> colours, List<Vector3> normals, List<int> indices)
{
var halfSize = size / 2.0f;
var corners = new[] {
new Vector3(-halfSize, -halfSize, -halfSize) + position,
new Vector3( halfSize, -halfSize, -halfSize) + position,
new Vector3( halfSize, -halfSize, halfSize) + position,
new Vector3(-halfSize, -halfSize, halfSize) + position,
new Vector3(-halfSize, halfSize, -halfSize) + position,
new Vector3( halfSize, halfSize, -halfSize) + position,
new Vector3( halfSize, halfSize, halfSize) + position,
new Vector3(-halfSize, halfSize, halfSize) + position
};
var faces = new (Vector3 normal, int[] corner_indices, bool should_render)[]
{
(Vector3.Down, new int[] {3, 2, 1, 0}, position.Y <= 0),
(Vector3.Up, new int[] {4, 5, 6, 7}, position.Y >= (tower_height - 1) * block_size),
(Vector3.Forward, new int[] {7, 6, 2, 3}, position.Z >= (tower_depth - 1) * block_size),
(Vector3.Back, new int[] {0, 1, 5, 4}, position.Z <= 0),
(Vector3.Left, new int[] {4, 7, 3, 0}, position.X <= 0),
(Vector3.Right, new int[] {1, 2, 6, 5}, position.X >= (tower_width - 1) * block_size)
};
foreach (var (normal, corner_indices, should_render) in faces)
{
if (!should_render)
continue;
var k = vertices.Count;
var colour_index = 0;
foreach (var index in corner_indices)
{
vertices.Add(corners[index]);
colours.Add(colour_set[colour_index++]);
normals.Add(normal);
}
indices.Add(k);
indices.Add(k + 1);
indices.Add(k + 2);
indices.Add(k + 2);
indices.Add(k + 3);
indices.Add(k);
}
}
private static ArrayMesh DrawTowerWithSurfaceTool()
{
var st = new SurfaceTool();
st.Begin(Mesh.PrimitiveType.Triangles);
var vertexIndex = 0;
for (var x = 0; x < tower_width; x++)
for (var y = 0; y < tower_height; y++)
for (var z = 0; z < tower_depth; z++)
{
var blockPosition = new Vector3(x * block_size, y * block_size, z * block_size);
CreateBlock(st, ref vertexIndex, blockPosition, block_size);
}
return st.Commit();
}
private static void CreateBlock(SurfaceTool st, ref int vertexIndex, Vector3 position, float size)
{
var halfSize = size / 2.0f;
var corners = new[] {
new Vector3(-halfSize, -halfSize, -halfSize) + position,
new Vector3( halfSize, -halfSize, -halfSize) + position,
new Vector3( halfSize, -halfSize, halfSize) + position,
new Vector3(-halfSize, -halfSize, halfSize) + position,
new Vector3(-halfSize, halfSize, -halfSize) + position,
new Vector3( halfSize, halfSize, -halfSize) + position,
new Vector3( halfSize, halfSize, halfSize) + position,
new Vector3(-halfSize, halfSize, halfSize) + position
};
var quads = new (Vector3 normal, Vector3[] corner_vertices, bool should_render)[]
{
(Vector3.Down, new [] {corners[3], corners[2], corners[1], corners[0]}, position.Y <= 0),
(Vector3.Up, new [] {corners[4], corners[5], corners[6], corners[7]}, position.Y >= (tower_height - 1) * block_size),
(Vector3.Forward, new [] {corners[7], corners[6], corners[2], corners[3]}, position.Z >= (tower_depth - 1) * block_size),
(Vector3.Back, new [] {corners[0], corners[1], corners[5], corners[4]}, position.Z <= 0),
(Vector3.Left, new [] {corners[4], corners[7], corners[3], corners[0]}, position.X <= 0),
(Vector3.Right, new [] {corners[1], corners[2], corners[6], corners[5]}, position.X >= (tower_width - 1) * block_size)
};
foreach (var quad in quads)
DrawQuad(st, ref vertexIndex, quad);
}
private static void DrawQuad(SurfaceTool st, ref int k, (Vector3 normal, Vector3[] corner_vertices, bool should_render) quad)
{
if (!quad.should_render)
return;
var colour_index = 0;
foreach (var corner in quad.corner_vertices)
{
st.SetColor(colour_set[colour_index++]);
st.SetNormal(quad.normal);
st.AddVertex(corner);
}
st.AddIndex(k);
st.AddIndex(k + 1);
st.AddIndex(k + 2);
st.AddIndex(k + 2);
st.AddIndex(k + 3);
st.AddIndex(k);
k += 4;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment