Exemple #1
0
        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();
            }
                              ));
        }
Exemple #2
0
        public VoxelChunk(VoxelWorld <TIndexer> world, ChunkPos pos, int chunkSize, IndexerFactory <TIndexer> indexerFactory)
        {
            this.world          = world;
            this.chunkSize      = chunkSize;
            this.chunkSizeSq    = chunkSize * chunkSize;
            this.Pos            = pos;
            this.indexerFactory = indexerFactory;

            voxels = new NativeArray3D <Voxel, TIndexer>(indexerFactory(chunkSize + 1, chunkSize + 1, chunkSize + 1), chunkSize + 1, chunkSize + 1, chunkSize + 1, Allocator.Persistent);
            //voxels = new Voxel[chunkSize * chunkSize * chunkSize];
            //voxels = new NativeArray<Voxel>(chunkSize * chunkSize * chunkSize, Allocator.Persistent); //TODO Dispose
        }
Exemple #3
0
        public Change ScheduleGrid <TGridIndexer>(int tx, int ty, int tz, int gx, int gy, int gz, NativeArray3D <Voxel, TGridIndexer> grid, bool propagatePadding, bool includePadding, bool writeUnsetVoxels)
            where TGridIndexer : struct, IIndexer
        {
            var gridJob = new ChunkGridJob <TGridIndexer, TIndexer>
            {
                source           = grid,
                chunkSize        = chunkSize + (includePadding ? 1 : 0),
                writeUnsetVoxels = writeUnsetVoxels,
                tx     = tx,
                ty     = ty,
                tz     = tz,
                gx     = gx,
                gy     = gy,
                gz     = gz,
                target = voxels
            };

            return(new Change(gridJob.Schedule(), () =>
            {
                NeedsRebuild = true;

                if (propagatePadding)
                {
                    //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();
                }
            }
        }
Exemple #5
0
        public static bool FillCell(NativeArray3D <Voxel, TIndexer> voxels, int x, int y, int z, int cellIndex, NativeArray <int> materials, NativeArray <float> intersections, NativeArray <float3> normals)
        {
            var v000 = voxels[x, y, z];
            var v100 = voxels[x + 1, y, z];
            var v101 = voxels[x + 1, y, z + 1];
            var v001 = voxels[x, y, z + 1];
            var v010 = voxels[x, y + 1, z];
            var v110 = voxels[x + 1, y + 1, z];
            var v111 = voxels[x + 1, y + 1, z + 1];
            var v011 = voxels[x, y + 1, z + 1];

            var d000 = (float4x3)v000.Data;
            var d100 = (float4x3)v100.Data;
            var d101 = (float4x3)v101.Data;
            var d001 = (float4x3)v001.Data;
            var d010 = (float4x3)v010.Data;
            var d110 = (float4x3)v110.Data;
            var d111 = (float4x3)v111.Data;
            var d011 = (float4x3)v011.Data;

            int solids = 0;

            if ((materials[cellIndex * 8 + 0] = v000.Material) != 0)
            {
                solids++;
            }
            if ((materials[cellIndex * 8 + 1] = v100.Material) != 0)
            {
                solids++;
            }
            if ((materials[cellIndex * 8 + 2] = v101.Material) != 0)
            {
                solids++;
            }
            if ((materials[cellIndex * 8 + 3] = v001.Material) != 0)
            {
                solids++;
            }
            if ((materials[cellIndex * 8 + 4] = v010.Material) != 0)
            {
                solids++;
            }
            if ((materials[cellIndex * 8 + 5] = v110.Material) != 0)
            {
                solids++;
            }
            if ((materials[cellIndex * 8 + 6] = v111.Material) != 0)
            {
                solids++;
            }
            if ((materials[cellIndex * 8 + 7] = v011.Material) != 0)
            {
                solids++;
            }

            if (solids == 0 || solids == 8)
            {
                //No surface in cell
                return(false);
            }

            intersections[cellIndex * 12 + 0]  = d000[0].w;
            intersections[cellIndex * 12 + 1]  = d100[2].w;
            intersections[cellIndex * 12 + 2]  = d001[0].w;
            intersections[cellIndex * 12 + 3]  = d000[2].w;
            intersections[cellIndex * 12 + 4]  = d010[0].w;
            intersections[cellIndex * 12 + 5]  = d110[2].w;
            intersections[cellIndex * 12 + 6]  = d011[0].w;
            intersections[cellIndex * 12 + 7]  = d010[2].w;
            intersections[cellIndex * 12 + 8]  = d000[1].w;
            intersections[cellIndex * 12 + 9]  = d100[1].w;
            intersections[cellIndex * 12 + 10] = d101[1].w;
            intersections[cellIndex * 12 + 11] = d001[1].w;

            normals[cellIndex * 12 + 0]  = d000[0].xyz;
            normals[cellIndex * 12 + 1]  = d100[2].xyz;
            normals[cellIndex * 12 + 2]  = d001[0].xyz;
            normals[cellIndex * 12 + 3]  = d000[2].xyz;
            normals[cellIndex * 12 + 4]  = d010[0].xyz;
            normals[cellIndex * 12 + 5]  = d110[2].xyz;
            normals[cellIndex * 12 + 6]  = d011[0].xyz;
            normals[cellIndex * 12 + 7]  = d010[2].xyz;
            normals[cellIndex * 12 + 8]  = d000[1].xyz;
            normals[cellIndex * 12 + 9]  = d100[1].xyz;
            normals[cellIndex * 12 + 10] = d101[1].xyz;
            normals[cellIndex * 12 + 11] = d001[1].xyz;

            return(true);
        }
Exemple #6
0
 public void CopyFrom(NativeArray3D <T, TIndexer> array)
 {
     data.CopyFrom(array.data);
 }
        private static void ApplySdfIntersection(NativeArray3D <Voxel, TIndexer> snapshot, float3 origin, int x, int y, int z, int chunkSize, int edge, int xo, int yo, int zo, TSdf sdf, NativeArray3D <float, LinearIndexer> evaluatedSdf, int material, bool replace, NativeArray3D <Voxel, TIndexer> outVoxels)
        {
            if (x < 0 || y < 0 || z < 0 || x >= chunkSize || y >= chunkSize || z >= chunkSize)
            {
                return;
            }

            //Remove intersections and normals from edges that do not have
            //a material change

            /*if (voxels[x, y, z].material == voxels[x + xo, y + yo, z + zo].material)
             * {
             *  intersections[x][y][z][edge] = 0;
             *  normals[x][y][z][edge] = Vector3.zero;
             *  return;
             * }*/

            bool isIgnoredReplacement = replace && (outVoxels[x, y, z].Material == 0 || outVoxels[x + xo, y + yo, z + zo].Material == 0);

            float d1 = evaluatedSdf[x, y, z];
            float d2 = evaluatedSdf[x + xo, y + yo, z + zo];

            float       normalFacing = material == 0 ? -1.0f : 1.0f;
            const float epsilon      = 0.001F;

            if (!isIgnoredReplacement)
            {
                if ((d1 < 0) != (d2 < 0))
                {
                    float3 edgeStart            = new float3(x, y, z) - origin;
                    float3 newIntersectionPoint = FindIntersection(edgeStart, d1, new float3(x + xo, y + yo, z + zo) - origin, d2, sdf, 0.001f, 4);

                    float newIntersection = math.length(newIntersectionPoint - edgeStart);

                    if (snapshot[x, y, z].Material == snapshot[x + xo, y + yo, z + zo].Material)
                    {
                        //Currently no existing intersection, can just set
                        outVoxels[x, y, z] = outVoxels[x, y, z].ModifyEdge(true, edge, newIntersection, normalFacing * SdfDerivative.FirstOrderCentralFiniteDifferenceNormalized(newIntersectionPoint, epsilon, sdf));
                    }
                    else
                    {
                        //An intersection already exists, need to check where the already existing intersection is and compare to the new one
                        float intersection = outVoxels[x, y, z].Data[edge].w;

                        bool overwrite = false;

                        bool s1 = snapshot[x, y, z].Material != 0;
                        bool s2 = snapshot[x + xo, y + yo, z + zo].Material != 0;

                        if (material != 0)
                        {
                            if (d1 < 0 && s1 && newIntersection > intersection)
                            {
                                overwrite = true;
                            }
                            else if (d2 < 0 && s2 && newIntersection < intersection)
                            {
                                overwrite = true;
                            }
                        }
                        else
                        {
                            if (d1 < 0 && s2 && newIntersection > intersection)
                            {
                                overwrite = true;
                            }
                            else if (d2 < 0 && s1 && newIntersection < intersection)
                            {
                                overwrite = true;
                            }
                        }

                        if (overwrite)
                        {
                            outVoxels[x, y, z] = outVoxels[x, y, z].ModifyEdge(true, edge, newIntersection, normalFacing * SdfDerivative.FirstOrderCentralFiniteDifferenceNormalized(newIntersectionPoint, epsilon, sdf));
                        }
                    }
                }
                else if (d1 < 0 && d2 < 0)
                {
                    outVoxels[x, y, z] = outVoxels[x, y, z].ModifyEdge(true, edge, 0, 0);
                }
            }
            else if ((d1 < 0) != (d2 < 0))
            {
                float3 intersection = FindIntersection(new float3(x, y, z) - origin, d1, new float3(x + xo, y + yo, z + zo) - origin, d2, sdf, 0.001F, 4);

                float intersectionDist = math.length(intersection - new float3(x, y, z) + origin);

                //TODO Use inVoxels for comparison?
                if (outVoxels[x, y, z].Material == outVoxels[x + xo, y + yo, z + zo].Material)
                {
                    outVoxels[x, y, z] = outVoxels[x, y, z].ModifyEdge(true, edge, math.length(intersection - new float3(x, y, z) + origin), normalFacing * SdfDerivative.FirstOrderCentralFiniteDifferenceNormalized(intersection, epsilon, sdf));
                }
            }
        }
        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);
        }