Hello,
I’m working on a fully destructible shooter, and I recently switched from Marching Cubes to Surface Nets (and C#!) for increased performance. For whatever reason, my st.GenerateNormals() is NOT working. I don’t know why. I couldn’t find anything in the documentation (I swear to freak if there’s something I missed, I’ll lose it), so if there happens to be any SurfaceTool users here who know, I’d appreciate the help. I’ll paste all the code just in case it’s a weird bug, but it should mostly just be in the draw function, I would assume.
using Godot;
using System;
using System.Linq;
using System.Reflection.Metadata.Ecma335;
using System.Resources;
[Tool]
public partial class LevelManager : Node
{
[Export] Vector3I chunksNeeded = new Vector3I(1, 1, 1);
[Export] ...
Hello,
I’m working on a fully destructible shooter, and I recently switched from Marching Cubes to Surface Nets (and C#!) for increased performance. For whatever reason, my st.GenerateNormals() is NOT working. I don’t know why. I couldn’t find anything in the documentation (I swear to freak if there’s something I missed, I’ll lose it), so if there happens to be any SurfaceTool users here who know, I’d appreciate the help. I’ll paste all the code just in case it’s a weird bug, but it should mostly just be in the draw function, I would assume.
using Godot;
using System;
using System.Linq;
using System.Reflection.Metadata.Ecma335;
using System.Resources;
[Tool]
public partial class LevelManager : Node
{
[Export] Vector3I chunksNeeded = new Vector3I(1, 1, 1);
[Export] Vector3I chunkSize = new Vector3I(16, 16, 16);
[Export] float voxelSize = 1.5f;
[Export] OrmMaterial3D texture;
PackedScene chunkPrefab = ResourceLoader.Load<PackedScene>("res://prefabs/LevelChunk.tscn");
Vector3I totalSize;
Vector3I implementSize;
int[] chunkList;
byte[] voxelData;
Vector3[] vertices;
public override void _Ready()
{
totalSize = chunkSize * chunksNeeded;
implementSize = chunkSize + Vector3I.One;
GenerateVoxels();
GenerateChunks();
}
private void GenerateVoxels()
{
voxelData = new byte[totalSize.X * totalSize.Y * totalSize.Z];
Random rand = new Random();
for (int x = 0; x < totalSize.X; x++)
{
for (int y = 0; y < totalSize.Y; y++)
{
for (int z = 0; z < totalSize.Z; z++)
{
voxelData[VoxelIndex(x, y, z)] = (byte)1;
}
}
}
}
private void GenerateChunks()
{
chunkList = new int[chunksNeeded.X * chunksNeeded.Y * chunksNeeded.Z];
for (int x = 0; x < chunksNeeded.X; x++)
{
for (int y = 0; y < chunksNeeded.Y; y++)
{
for (int z = 0; z < chunksNeeded.Z; z++)
{
MeshInstance3D instance = chunkPrefab.Instantiate<MeshInstance3D>();
instance.Position = new Vector3(x, y, z) * chunkSize * voxelSize;
chunkList[ChunkIndex(x, y, z)] = GetChildCount();
AddChild(instance);
DrawChunk(GetChildCount() - 1);
}
}
}
}
private void DrawChunk(int chunkNum)
{
MeshInstance3D chunk = GetChild<MeshInstance3D>(chunkNum);
SurfaceTool st = new SurfaceTool();
st.Begin(Mesh.PrimitiveType.Triangles);
Vector3I chunkPos = (Vector3I)(chunk.Position / voxelSize);
vertices = new Vector3[implementSize.X * implementSize.Y * implementSize.Z];
for (int x = implementSize.X - 1; x > -1; x--)
{
for (int y = implementSize.Y - 1; y > -1; y--)
{
for (int z = implementSize.Z - 1; z > -1; z--)
{
Vector3 avg = Vector3.Zero;
int total = 0;
int v0 = GetVoxel(x + chunkPos.X, y + chunkPos.Y, z + chunkPos.Z);
int v1 = GetVoxel(x + chunkPos.X + 1, y + chunkPos.Y, z + chunkPos.Z);
int v2 = GetVoxel(x + chunkPos.X, y + chunkPos.Y + 1, z + chunkPos.Z);
int v3 = GetVoxel(x + chunkPos.X, y + chunkPos.Y, z + chunkPos.Z + 1);
int v4 = GetVoxel(x + chunkPos.X + 1, y + chunkPos.Y + 1, z + chunkPos.Z);
int v5 = GetVoxel(x + chunkPos.X, y + chunkPos.Y + 1, z + chunkPos.Z + 1);
int v6 = GetVoxel(x + chunkPos.X + 1, y + chunkPos.Y, z + chunkPos.Z + 1);
int v7 = GetVoxel(x + chunkPos.X + 1, y + chunkPos.Y + 1, z + chunkPos.Z + 1);
if (v0 != v1)
{
avg += new Vector3(1, 0, 0);
total++;
}
if (v0 != v2)
{
avg += new Vector3(0, 1, 0);
total++;
}
if (v0 != v3)
{
avg += new Vector3(0, 0, 1);
total++;
}
if (v0 != v4)
{
avg += new Vector3(1, 1, 0);
total++;
}
if (v0 != v5)
{
avg += new Vector3(0, 1, 1);
total++;
}
if (v0 != v6)
{
avg += new Vector3(1, 0, 1);
total++;
}
if (v0 != v7)
{
avg += new Vector3(1, 1, 1);
total++;
}
if (total != 0)
{
vertices[VertexIndex(x, y, z)] = avg / total;
}
}
}
}
// second pass because i was too stupid to get the one pass running, sorry guys
for (int x = implementSize.X - 1; x > -1; x--)
{
for (int y = implementSize.Y - 1; y > -1; y--)
{
for (int z = implementSize.Z - 1; z > -1; z--)
{
if (GetVertex(x, y, z) != Vector3.Zero)
{
if (GetVertex(x + 1, y, z) != Vector3.Zero && GetVertex(x, y, z + 1) != Vector3.Zero && GetVertex(x + 1, y, z + 1) != Vector3.Zero)
{
st.AddVertex((new Vector3(x, y, z) + GetVertex(x, y, z)) * voxelSize);
st.AddVertex((new Vector3(x + 1, y, z) + GetVertex(x + 1, y, z)) * voxelSize);
st.AddVertex((new Vector3(x, y, z + 1) + GetVertex(x, y, z + 1)) * voxelSize);
st.AddVertex((new Vector3(x + 1, y, z) + GetVertex(x + 1, y, z)) * voxelSize);
st.AddVertex((new Vector3(x + 1, y, z + 1) + GetVertex(x + 1, y, z + 1)) * voxelSize);
st.AddVertex((new Vector3(x, y, z + 1) + GetVertex(x, y, z + 1)) * voxelSize);
st.AddVertex((new Vector3(x + 1, y, z) + GetVertex(x + 1, y, z)) * voxelSize);
st.AddVertex((new Vector3(x, y, z) + GetVertex(x, y, z)) * voxelSize);
st.AddVertex((new Vector3(x, y, z + 1) + GetVertex(x, y, z + 1)) * voxelSize);
st.AddVertex((new Vector3(x + 1, y, z + 1) + GetVertex(x + 1, y, z + 1)) * voxelSize);
st.AddVertex((new Vector3(x + 1, y, z) + GetVertex(x + 1, y, z)) * voxelSize);
st.AddVertex((new Vector3(x, y, z + 1) + GetVertex(x, y, z + 1)) * voxelSize);
}
if (GetVertex(x + 1, y, z) != Vector3.Zero && GetVertex(x, y + 1, z) != Vector3.Zero && GetVertex(x + 1, y + 1, z) != Vector3.Zero)
{
st.AddVertex((new Vector3(x + 1, y, z) + GetVertex(x + 1, y, z)) * voxelSize);
st.AddVertex((new Vector3(x, y, z) + GetVertex(x, y, z)) * voxelSize);
st.AddVertex((new Vector3(x, y + 1, z) + GetVertex(x, y + 1, z)) * voxelSize);
st.AddVertex((new Vector3(x + 1, y + 1, z) + GetVertex(x + 1, y + 1, z)) * voxelSize);
st.AddVertex((new Vector3(x + 1, y, z) + GetVertex(x + 1, y, z)) * voxelSize);
st.AddVertex((new Vector3(x, y + 1, z) + GetVertex(x, y + 1, z)) * voxelSize);
st.AddVertex((new Vector3(x, y, z) + GetVertex(x, y, z)) * voxelSize);
st.AddVertex((new Vector3(x + 1, y, z) + GetVertex(x + 1, y, z)) * voxelSize);
st.AddVertex((new Vector3(x, y + 1, z) + GetVertex(x, y + 1, z)) * voxelSize);
st.AddVertex((new Vector3(x + 1, y, z) + GetVertex(x + 1, y, z)) * voxelSize);
st.AddVertex((new Vector3(x + 1, y + 1, z) + GetVertex(x + 1, y + 1, z)) * voxelSize);
st.AddVertex((new Vector3(x, y + 1, z) + GetVertex(x, y + 1, z)) * voxelSize);
}
if (GetVertex(x, y, z + 1) != Vector3.Zero && GetVertex(x, y + 1, z) != Vector3.Zero && GetVertex(x, y + 1, z + 1) != Vector3.Zero)
{
st.AddVertex((new Vector3(x, y, z) + GetVertex(x, y, z)) * voxelSize);
st.AddVertex((new Vector3(x, y, z + 1) + GetVertex(x, y, z + 1)) * voxelSize);
st.AddVertex((new Vector3(x, y + 1, z) + GetVertex(x, y + 1, z)) * voxelSize);
st.AddVertex((new Vector3(x, y, z + 1) + GetVertex(x, y, z + 1)) * voxelSize);
st.AddVertex((new Vector3(x, y + 1, z + 1) + GetVertex(x, y + 1, z + 1)) * voxelSize);
st.AddVertex((new Vector3(x, y + 1, z) + GetVertex(x, y + 1, z)) * voxelSize);
st.AddVertex((new Vector3(x, y, z + 1) + GetVertex(x, y, z + 1)) * voxelSize);
st.AddVertex((new Vector3(x, y, z) + GetVertex(x, y, z)) * voxelSize);
st.AddVertex((new Vector3(x, y + 1, z) + GetVertex(x, y + 1, z)) * voxelSize);
st.AddVertex((new Vector3(x, y + 1, z + 1) + GetVertex(x, y + 1, z + 1)) * voxelSize);
st.AddVertex((new Vector3(x, y, z + 1) + GetVertex(x, y, z + 1)) * voxelSize);
st.AddVertex((new Vector3(x, y + 1, z) + GetVertex(x, y + 1, z)) * voxelSize);
}
}
}
}
}
st.SetMaterial(texture);
st.Index();
st.GenerateNormals();
chunk.Mesh = st.Commit();
chunk.Call("bake");
}
private int ChunkIndex(int x, int y, int z)
{
return x + (y * chunksNeeded.X) + (z * chunksNeeded.X * chunksNeeded.Y);
}
private int VertexIndex(int x, int y, int z)
{
return x + (y * implementSize.X) + (z * implementSize.X * implementSize.Y);
}
private Vector3 GetVertex(int x, int y, int z)
{
if (x > -1 && y > -1 && z > -1 && x < implementSize.X && y < implementSize.Y && z < implementSize.Z)
{
return vertices[x + (y * implementSize.X) + (z * implementSize.X * implementSize.Y)];
}
return Vector3.Zero;
}
private int VoxelIndex(int x, int y, int z)
{
return x + (y * totalSize.X) + (z * totalSize.X * totalSize.Y);
}
private int GetVoxel(int x, int y, int z)
{
if (x > -1 && y > -1 && z > -1 && x < totalSize.X && y < totalSize.Y && z < totalSize.Z)
{
return voxelData[x + (y * totalSize.X) + (z * totalSize.X * totalSize.Y)];
}
return 0;
}
public void Hit(Vector3 hitPos)
{
Vector3I voxelPos = (Vector3I)(hitPos / voxelSize);
voxelData[VoxelIndex(voxelPos.X, voxelPos.Y, voxelPos.Z)] = 0;
voxelData[VoxelIndex(voxelPos.X, voxelPos.Y + 1, voxelPos.Z)] = 0;
voxelData[VoxelIndex(voxelPos.X, voxelPos.Y - 1, voxelPos.Z)] = 0;
Vector3I chunkPos = new Vector3I(
voxelPos.X / chunkSize.X,
voxelPos.Y / chunkSize.Y,
voxelPos.Z / chunkSize.Z
);
int chunkId = chunkList[ChunkIndex(chunkPos.X, chunkPos.Y, chunkPos.Z)];
DrawChunk(chunkId);
}
}