public void Execute() { var width = source.Length(0); var height = source.Length(1); var depth = source.Length(2); for (int z = 0; z < chunkSize; z++) { for (int y = 0; y < chunkSize; y++) { for (int x = 0; x < chunkSize; x++) { var cvx = x + tx; var cvy = y + ty; var cvz = z + tz; var gvx = x + gx; var gvy = y + gy; var gvz = z + gz; if (cvx >= 0 && cvx < chunkSize && cvy >= 0 && cvy < chunkSize && cvz >= 0 && cvz < chunkSize && gvx >= 0 && gvx < width && gvy >= 0 && gvy < height && gvz >= 0 && gvz < depth) { Voxel sourceVoxel = source[gvx, gvy, gvz]; if (writeUnsetVoxels || sourceVoxel.Data.IsVoxelSet) { target[cvx, cvy, cvz] = sourceVoxel; } } } } } }
public void Execute() { int nVoxels = Voxels.Length(0) * Voxels.Length(1) * Voxels.Length(2); int nCells = (Voxels.Length(0) - 1) * (Voxels.Length(1) - 1) * (Voxels.Length(2) - 1); var MemoryCache = new NativeMemoryCache(Allocator.Temp); var DedupeCache = new VoxelMeshTessellation.NativeDeduplicationCache(Allocator.Temp); var Components = new NativeList <VoxelMeshComponent>(Allocator.Temp); var Indices = new NativeList <PackedIndex>(Allocator.Temp); var Vertices = new NativeList <VoxelMeshComponentVertex>(Allocator.Temp); var Materials = new NativeArray <int>(8, Allocator.Temp, NativeArrayOptions.UninitializedMemory); var Intersections = new NativeArray <float>(12, Allocator.Temp, NativeArrayOptions.UninitializedMemory); var Normals = new NativeArray <float3>(12, Allocator.Temp, NativeArrayOptions.UninitializedMemory); var solver = new SvdQefSolver <RawArrayVoxelCell> { Clamp = false }; var polygonizer = new CMSVoxelPolygonizer <RawArrayVoxelCell, CMSProperties.DataStruct, SvdQefSolver <RawArrayVoxelCell>, IntersectionSharpFeatureSolver <RawArrayVoxelCell> >(PolygonizationProperties, solver, new IntersectionSharpFeatureSolver <RawArrayVoxelCell>(), MemoryCache); int xSize = Voxels.Length(0); int ySize = Voxels.Length(1); int zSize = Voxels.Length(2); TIndexer indexer = Voxels.Indexer; for (int index = 0; index < nVoxels; ++index) { int x = 0, y = 0, z = 0; indexer.FromIndex(index, ref x, ref y, ref z); if (x < xSize - 1 && y < ySize - 1 && z < zSize - 1 && FillCell(Voxels, x, y, z, 0, Materials, Intersections, Normals)) { //TODO Directly operate on voxel array RawArrayVoxelCell cell = new RawArrayVoxelCell(0, new float3(x, y, z), Materials, Intersections, Normals); polygonizer.Polygonize(cell, Components, Indices, Vertices); } } VoxelMeshTessellation.Tessellate(Components, Indices, Vertices, Matrix4x4.identity, MeshVertices, MeshTriangles, MeshNormals, MeshMaterials, new MaterialColors(), MeshColors, DedupeCache); MemoryCache.Dispose(); DedupeCache.Dispose(); Materials.Dispose(); Intersections.Dispose(); Normals.Dispose(); Components.Dispose(); Indices.Dispose(); Vertices.Dispose(); //Cells.Dispose(); }
public Change ScheduleSdf <TSdf>(float ox, float oy, float oz, TSdf sdf, int material, bool replace) where TSdf : struct, ISdf { var changed = new NativeArray <bool>(1, Allocator.TempJob); var outVoxels = new NativeArray3D <Voxel, TIndexer>(indexerFactory(voxels.Length(0), voxels.Length(1), voxels.Length(2)), voxels.Length(0), voxels.Length(1), voxels.Length(2), Allocator.Persistent, NativeArrayOptions.UninitializedMemory); var sdfJob = new ChunkSdfJob <TSdf, TIndexer> { origin = new float3(ox, oy, oz), sdf = sdf, material = material, replace = replace, snapshot = voxels, changed = changed, outVoxels = outVoxels }; return(new Change(sdfJob.Schedule(), () => { voxels.Dispose(); voxels = outVoxels; if (sdfJob.changed[0]) { NeedsRebuild = true; } changed.Dispose(); //Update the padding of all -X/-Y/-Z adjacent chunks //TODO Only propagate those sides that have changed PropagatePadding(); } )); }
public void ApplyGrid <TGridIndexer>(int x, int y, int z, NativeArray3D <Voxel, TGridIndexer> grid, bool propagatePadding, bool includePadding, VoxelEditConsumer <TIndexer> edits, bool writeToChunks = true, bool writeUnsetVoxels = false) where TGridIndexer : struct, IIndexer { int minX = Mathf.FloorToInt((float)x / ChunkSize); int minY = Mathf.FloorToInt((float)y / ChunkSize); int minZ = Mathf.FloorToInt((float)z / ChunkSize); int maxX = Mathf.FloorToInt((float)(x + grid.Length(0)) / ChunkSize); int maxY = Mathf.FloorToInt((float)(y + grid.Length(1)) / ChunkSize); int maxZ = Mathf.FloorToInt((float)(z + grid.Length(2)) / ChunkSize); var handles = new List <VoxelChunk <TIndexer> .FinalizeChange>(); var watch = System.Diagnostics.Stopwatch.StartNew(); if (edits != null) { var snapshots = new List <VoxelChunk <TIndexer> .Snapshot>(); //Include padding int minX2 = Mathf.FloorToInt((float)(x - 1) / ChunkSize); int minY2 = Mathf.FloorToInt((float)(y - 1) / ChunkSize); int minZ2 = Mathf.FloorToInt((float)(z - 1) / ChunkSize); int maxX2 = Mathf.FloorToInt((float)(x + grid.Length(0) + 1) / ChunkSize); int maxY2 = Mathf.FloorToInt((float)(y + grid.Length(1) + 1) / ChunkSize); int maxZ2 = Mathf.FloorToInt((float)(z + grid.Length(2) + 1) / ChunkSize); var snapshotChunks = new List <VoxelChunk <TIndexer> >(); for (int cx = minX2; cx <= maxX2; cx++) { for (int cy = minY2; cy <= maxY2; cy++) { for (int cz = minZ2; cz <= maxZ2; cz++) { ChunkPos chunkPos = ChunkPos.FromChunk(cx, cy, cz); chunks.TryGetValue(chunkPos, out VoxelChunk <TIndexer> chunk); if (chunk != null) { snapshots.Add(chunk.ScheduleSnapshot()); } else { snapshotChunks.Add(new VoxelChunk <TIndexer>(this, chunkPos, ChunkSize, IndexerFactory)); } } } } //Finalize clone jobs foreach (VoxelChunk <TIndexer> .Snapshot snapshot in snapshots) { snapshot.handle.Complete(); snapshotChunks.Add(snapshot.chunk); } //Produce edit edits(new VoxelEdit <TIndexer>(this, snapshotChunks)); } if (writeToChunks) { var changes = new List <VoxelChunk <TIndexer> .Change>(); //Schedule all jobs for (int cx = minX; cx <= maxX; cx++) { for (int cy = minY; cy <= maxY; cy++) { for (int cz = minZ; cz <= maxZ; cz++) { ChunkPos chunkPos = ChunkPos.FromChunk(cx, cy, cz); chunks.TryGetValue(chunkPos, out VoxelChunk <TIndexer> chunk); if (chunk == null) { chunks[chunkPos] = chunk = new VoxelChunk <TIndexer>(this, chunkPos, ChunkSize, IndexerFactory); } var gx = (cx - minX) * ChunkSize; var gy = (cy - minY) * ChunkSize; var gz = (cz - minZ) * ChunkSize; changes.Add(chunk.ScheduleGrid(0, 0, 0, gx, gy, gz, grid, propagatePadding, includePadding, writeUnsetVoxels)); } } } //Wait and finalize jobs foreach (var change in changes) { change.handle.Complete(); } //Finalize foreach (var change in changes) { change.finalize(); } } }
public static bool ApplySdf(NativeArray3D <Voxel, TIndexer> snapshot, float3 origin, TSdf sdf, int material, bool replace, NativeArray3D <Voxel, TIndexer> outVoxels, Allocator allocator) { int chunkSize = snapshot.Length(0) - 1; float3 minBound = math.floor(origin + sdf.Min()); float3 maxBound = math.ceil(origin + sdf.Max()); snapshot.CopyTo(outVoxels); var evaluatedSdf = new NativeArray3D <float, LinearIndexer>(new LinearIndexer(chunkSize + 1, chunkSize + 1, chunkSize + 1), chunkSize + 1, chunkSize + 1, chunkSize + 1, allocator); bool changed = false; //Apply materials for (int z = (int)minBound.z; z <= maxBound.z + 1; z++) { for (int y = (int)minBound.y; y <= maxBound.y + 1; y++) { for (int x = (int)minBound.x; x <= maxBound.x + 1; x++) { if (x >= 0 && x < chunkSize + 1 && y >= 0 && y < chunkSize + 1 && z >= 0 && z < chunkSize + 1) { bool isInside = (evaluatedSdf[x, y, z] = sdf.Eval(new float3(x, y, z) - origin)) < 0; if (isInside) { if (replace && outVoxels[x, y, z].Material != 0) { //TODO Does this need intersection value checks? outVoxels[x, y, z] = outVoxels[x, y, z].ModifyMaterial(true, material); changed = true; } else if (!replace && outVoxels[x, y, z].Material != material) { outVoxels[x, y, z] = outVoxels[x, y, z].ModifyMaterial(true, material); changed = true; } } } } } } //Apply intersections and normals in a second pass, such that they aren't unnecessarily //asigned to edges with no material change for (int z = (int)minBound.z; z <= maxBound.z; z++) { for (int y = (int)minBound.y; y <= maxBound.y; y++) { for (int x = (int)minBound.x; x <= maxBound.x; x++) { if (x >= 0 && x < chunkSize && y >= 0 && y < chunkSize && z >= 0 && z < chunkSize) { ApplySdfIntersection(snapshot, origin, x, y, z, chunkSize, 0, 1, 0, 0, sdf, evaluatedSdf, material, replace, outVoxels); ApplySdfIntersection(snapshot, origin, x, y, z, chunkSize, 1, 0, 1, 0, sdf, evaluatedSdf, material, replace, outVoxels); ApplySdfIntersection(snapshot, origin, x, y, z, chunkSize, 2, 0, 0, 1, sdf, evaluatedSdf, material, replace, outVoxels); } } } } evaluatedSdf.Dispose(); return(changed); }