Recently I was moving code to different scripts in my project, and it caused weird triangles to generate. The world was procedurally generated, and for some reason it was the same triangles in the same position everytime, despite the seed. I used gizmos to draw the weights that are sent into a compute shader and it was working properly. I tried to see if the new changes had caused something to execute later than expected, but that was also working just fine. I checked if the creation of the mesh from the values returned from the compute shader caused it, but the values were as expected. I know the chunks of code where the issue is in, but not what is going wrong. Here is the code where it is going wrong:
C# side:
//converts a 3d coordinate to a single int for a 1d array of floats
int indexFromCoord(int x, int y, int z)
{
return x + (main.chunkSize+1) * (y + (main.chunkSize+1) * z);
}
//set values and execute compute shader, then begin mesh creation
Mesh ConstructMesh(int chunkID) {
MarchingShader.SetBuffer(0, "_Triangles", _trianglesBuffer);
MarchingShader.SetBuffer(0, "_Weights", _weightsBuffer);
MarchingShader.SetBuffer(0, "_Materials", _materialBuffer);
MarchingShader.SetInt("_chunkSize", 16);
MarchingShader.SetFloat("_IsoLevel", .5f);
MarchingShader.SetInt("_LOD", GridMetrics.PointsPerChunk(LOD));
MarchingShader.SetInt("_LODID", LOD);
_weightsBuffer.SetData(main.worldData[chunkID].chunkData);
_materialBuffer.SetData(main.worldData[chunkID].materials);
_trianglesBuffer.SetCounterValue(0);
MarchingShader.Dispatch(0, GridMetrics.ThreadGroups(LOD), GridMetrics.ThreadGroups(LOD), GridMetrics.ThreadGroups(LOD));
Triangle[] triangles = new Triangle[ReadTriangleCount()];
_trianglesBuffer.GetData(triangles);
return CreateMeshFromTriangles(triangles);
}
//gets count of triangles
int ReadTriangleCount() {
int[] triCount = { 0 };
ComputeBuffer.CopyCount(_trianglesBuffer, _trianglesCountBuffer, 0);
_trianglesCountBuffer.GetData(triCount);
return triCount[0];
}
//creates mesh from provided info
Mesh CreateMeshFromTriangles(Triangle[] triangles) {
List<Vector3> verts = new List<Vector3>();
List<List<int>> submeshTriangles = new List<List<int>>();
for (int submeshIndex = 0; submeshIndex < 5; submeshIndex++)
{
submeshTriangles.Add(new List<int>());
}
for (int i = 0; i < triangles.Length; i++) {
int startIndex = i * 3;
verts.Add(triangles[i].a);
verts.Add(triangles[i].b);
verts.Add(triangles[i].c);
submeshTriangles[triangles[i].materialIndex].Add(startIndex);
submeshTriangles[triangles[i].materialIndex].Add(startIndex + 1);
submeshTriangles[triangles[i].materialIndex].Add(startIndex + 2);
}
Mesh mesh = new Mesh();
mesh.vertices = verts.ToArray();
mesh.subMeshCount = 5;
for(int i = 0; i < submeshTriangles.Count; i++)
{
mesh.SetTriangles(submeshTriangles[i].ToArray(), i);
//submeshTriangles[triangles[i].materialIndex].Clear();
}
mesh.RecalculateNormals();
return mesh;
}
Compute Shader (couldn’t find hlsl option in code):
#pragma kernel March
#include “Includes\MarchingTable.hlsl”
#include “Includes\MetricsCompute.compute”
RWStructuredBuffer _Weights;
float _IsoLevel;
int _LOD;
int _LODID;
RWStructuredBuffer _Materials;
struct Triangle {
float3 a, b, c;
int materialIndex;
};
AppendStructuredBuffer _Triangles;
float3 interp(float3 edgeVertex1, float valueAtVertex1, float3 edgeVertex2, float valueAtVertex2)
{
return (edgeVertex1 + (_IsoLevel - valueAtVertex1) * (edgeVertex2 - edgeVertex1) / (valueAtVertex2 - valueAtVertex1));
}
[numthreads(numThreads, numThreads, numThreads)]
void March(uint3 id : SV_DispatchThreadID)
{
if (id.x >= _LOD || id.y >= _LOD || id.z >= _LOD)
{
return;
}
int scale = (5 - _LODID);
float3 samplePos = id * scale;
float cubeValues[8] = {
_Weights[indexFromCoord(samplePos.x, samplePos.y, samplePos.z + scale)],
_Weights[indexFromCoord(samplePos.x + scale, samplePos.y, samplePos.z + scale)],
_Weights[indexFromCoord(samplePos.x + scale, samplePos.y, samplePos.z)],
_Weights[indexFromCoord(samplePos.x, samplePos.y, samplePos.z)],
_Weights[indexFromCoord(samplePos.x, samplePos.y + scale, samplePos.z + scale)],
_Weights[indexFromCoord(samplePos.x + scale, samplePos.y + scale, samplePos.z + scale)],
_Weights[indexFromCoord(samplePos.x + scale, samplePos.y + scale, samplePos.z)],
_Weights[indexFromCoord(samplePos.x, samplePos.y + scale, samplePos.z)]
};
int cubeIndex = 0;
if (cubeValues[0] < _IsoLevel) cubeIndex |= 1;
if (cubeValues[1] < _IsoLevel) cubeIndex |= 2;
if (cubeValues[2] < _IsoLevel) cubeIndex |= 4;
if (cubeValues[3] < _IsoLevel) cubeIndex |= 8;
if (cubeValues[4] < _IsoLevel) cubeIndex |= 16;
if (cubeValues[5] < _IsoLevel) cubeIndex |= 32;
if (cubeValues[6] < _IsoLevel) cubeIndex |= 64;
if (cubeValues[7] < _IsoLevel) cubeIndex |= 128;
int edges[ ] = triTable[cubeIndex];
for (int i = 0; edges != -1; i += 3)
{
// First edge lies between vertex e00 and vertex e01
int e00 = edgeConnections[edges*][0];*
int e01 = edgeConnections[edges*][1];*
// Second edge lies between vertex e10 and vertex e11
int e10 = edgeConnections[edges[i + 1]][0];
int e11 = edgeConnections[edges[i + 1]][1];
// Third edge lies between vertex e20 and vertex e21
int e20 = edgeConnections[edges[i + 2]][0];
int e21 = edgeConnections[edges[i + 2]][1];
Triangle tri;
tri.a = (interp(cornerOffsets[e00], cubeValues[e00], cornerOffsets[e01], cubeValues[e01]) + id) * scale;
tri.b = (interp(cornerOffsets[e10], cubeValues[e10], cornerOffsets[e11], cubeValues[e11]) + id) * scale;
tri.c = (interp(cornerOffsets[e20], cubeValues[e20], cornerOffsets[e21], cubeValues[e21]) + id) * scale;
tri.materialIndex = _Materials[indexFromCoord(id.x, id.y, id.z)];
_Triangles.Append(tri);
}
}
