Hey thx for reply Kurt, right after I post for help I figure it out. God I hate programming.
The problem was with my triangles. I needed to add an “index” like so.
public struct _Mesh
{
public int index;
public UnsafeList<Vector3> v;
public UnsafeList<int> t;
public UnsafeList<Vector3> u;
}
And then when I add a new face to the list I increase the index for however many vertices I just added.
if (_.map.GetBlock(data.x, data.y+1, data.z) == null) {
m.o.v.Add(new(x - 0.5f, y + 0.25f, z - 0.5f));
m.o.v.Add(new(x - 0.5f, y + 0.25f, z + 0.5f));
m.o.v.Add(new(x + 0.5f, y + 0.25f, z + 0.5f));
m.o.v.Add(new(x + 0.5f, y + 0.25f, z - 0.5f));
m.o.t.Add(m.o.index + 0); m.o.t.Add(m.o.index + 1); m.o.t.Add(m.o.index + 2);
m.o.t.Add(m.o.index + 0); m.o.t.Add(m.o.index + 2); m.o.t.Add(m.o.index + 3);
m.o.u.Add(new(0,0,mat));
m.o.u.Add(new(0,1,mat));
m.o.u.Add(new(1,1,mat));
m.o.u.Add(new(1,0,mat));
m.o.index += 4;
}
Man… I’ve been messing around with this for about 12 hours now… about to passout. If anyone else is trying to get mesh generation working with the unity jobs system then here is my full code.
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using Unity.Collections;
using Unity.Collections.LowLevel.Unsafe;
using Unity.Jobs;
using Unity.VisualScripting;
using UnityEngine;
public struct _Mesh
{
public int index;
public UnsafeList<Vector3> v;
public UnsafeList<int> t;
public UnsafeList<Vector3> u;
}
public struct _SectionMeshData
{
public _Mesh o;
public _Mesh c;
}
public struct Refresh : IJobParallelFor
{
public NativeArray<MeshBuilder> sections;
public void Execute(int index)
{
var section = sections[index];
section.Refresh();
sections[index] = section;
}
public static void Schedule(List<Section> list)
{
// set all of the sections to busy status
foreach(Section s in list) { s.busy = true; }
// build our refresher array
var _sections = new NativeArray<MeshBuilder>(list.Count, Allocator.Persistent);
for(var i = 0; i < list.Count; i++) { _sections[i] = new MeshBuilder(list[i].data.x, list[i].data.y, list[i].data.z); }
// schedule the job
var job = new Refresh() { sections = _sections };
var handle = job.Schedule(list.Count, 1);
handle.Complete();
// update each mesh on each section
for(var i = 0; i < list.Count; i++) {
if (_sections[i].m.o.v.Length > 0) {
GameObject.Destroy(list[i].omf.mesh);
Mesh m = new Mesh();
Vector3[] verts = new Vector3[_sections[i].m.o.v.Length];
for(int v1 = 0; v1 < _sections[i].m.o.v.Length; v1++) { verts[v1] = _sections[i].m.o.v[v1]; }
int[] tris = new int[_sections[i].m.o.t.Length];
for(int v2 = 0; v2 < _sections[i].m.o.t.Length; v2++) { tris[v2] = _sections[i].m.o.t[v2]; }
Vector3[] uvs = new Vector3[_sections[i].m.o.u.Length];
for(int v3 = 0; v3 < _sections[i].m.o.u.Length; v3++) { uvs[v3] = _sections[i].m.o.u[v3]; }
m.SetVertices(verts);
m.SetTriangles(tris, 0);
m.SetUVs(0, uvs);
list[i].omf.mesh = m;
list[i].omf.mesh.RecalculateNormals();
}
if (_sections[i].m.c.v.Length > 0) {
GameObject.Destroy(list[i].ocol.sharedMesh);
Mesh m1 = new Mesh();
Vector3[] verts1 = new Vector3[_sections[i].m.c.v.Length];
for(int v1 = 0; v1 < _sections[i].m.c.v.Length; v1++) { verts1[v1] = _sections[i].m.c.v[v1]; }
int[] tris1 = new int[_sections[i].m.o.t.Length];
for(int v2 = 0; v2 < _sections[i].m.c.t.Length; v2++) { tris1[v2] = _sections[i].m.c.t[v2]; }
Vector3[] uvs1 = new Vector3[_sections[i].m.o.u.Length];
for(int v3 = 0; v3 < _sections[i].m.c.u.Length; v3++) { uvs1[v3] = _sections[i].m.c.u[v3]; }
m1.vertices = verts1;
m1.triangles = tris1;
m1.SetUVs(0, uvs1);
list[i].ocol.sharedMesh = m1;
list[i].ocol.sharedMesh.RecalculateNormals();
}
}
// cleanup
foreach(Section s in list) { s.busy = false; }
foreach(MeshBuilder mb in _sections) {
mb.m.o.v.Dispose(); mb.m.o.t.Dispose(); mb.m.o.u.Dispose();
mb.m.c.v.Dispose(); mb.m.c.t.Dispose(); mb.m.c.u.Dispose();
}
_sections.Dispose();
}
}
public struct MeshBuilder
{
public int x, y, z;
public _SectionMeshData m;
public MeshBuilder(int x, int y, int z)
{
this.x = x; this.y = y; this.z = z;
this.m = new _SectionMeshData();
m.o = new _Mesh(); m.o.index = 0;
m.c = new _Mesh(); m.c.index = 0;
this.m.o.v = new UnsafeList<Vector3>(0, Allocator.Persistent);
this.m.o.t = new UnsafeList<int>(0, Allocator.Persistent);
this.m.o.u = new UnsafeList<Vector3>(0, Allocator.Persistent);
this.m.c.v = new UnsafeList<Vector3>(0, Allocator.Persistent);
this.m.c.t = new UnsafeList<int>(0, Allocator.Persistent);
this.m.c.u = new UnsafeList<Vector3>(0, Allocator.Persistent);
}
public void Refresh()
{
int x2 = 0; int y2 = 0; int z2 = 0;
int max = _.map.data.chunkSize * _.map.data.chunkSize * _.map.data.chunkSize;
for(int i = 0; i < max; i++) {
if (_.map.GetBlock(x + x2, y + y2, z + z2) != null) {
_.map.GetBlock(x + x2, y + y2, z + z2).Build(ref m);
}
x2++; if (x2 == _.map.data.chunkSize) { x2 = 0; z2++; } if (z2 == _.map.data.chunkSize) { z2 = 0; y2++; }
}
}
}
One area that can be improved is this part.
Vector3[] verts = new Vector3[_sections[i].m.o.v.Length];
for(int v1 = 0; v1 < _sections[i].m.o.v.Length; v1++) { verts[v1] = _sections[i].m.o.v[v1]; }
int[] tris = new int[_sections[i].m.o.t.Length];
for(int v2 = 0; v2 < _sections[i].m.o.t.Length; v2++) { tris[v2] = _sections[i].m.o.t[v2]; }
Vector3[] uvs = new Vector3[_sections[i].m.o.u.Length];
for(int v3 = 0; v3 < _sections[i].m.o.u.Length; v3++) { uvs[v3] = _sections[i].m.o.u[v3]; }
Unity meshes need a Vector3 array for their verts but for unity job system I could only get it working with UnsafeList so after I populate the mesh data I have to convert it to a Vector3 array to assign to the mesh. It’s kinda hacky and stupid, wish there was a way for Mesh to take different data.