Exemple #1
0
        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();
        }
    private void Update()
    {
        if (undo)
        {
            undo = false;

            var editManager = GetComponent <VoxelEditManagerContainer>().Instance;
            if (editManager != null)
            {
                editManager.Undo();
            }
        }

        if (redo)
        {
            redo = false;

            var editManager = GetComponent <VoxelEditManagerContainer>().Instance;
            if (editManager != null)
            {
                editManager.Redo();
            }
        }

        if (!lockSelection)
        {
            Camera camera = Camera.current;
            if (camera != null)
            {
                Vector3 relPos = camera.transform.position - transform.position;
                Vector3 relDir = Quaternion.Inverse(transform.rotation) * camera.transform.forward.normalized;

                //if (field.RayCast(relPos, relDir, 16, out TestVoxelField.RayCastResult result))
                if (gameObject.GetComponent <VoxelWorldContainer>().Instance.RayCast(relPos, relDir, 64, out VoxelWorld <MortonIndexer> .RayCastResult result))
                {
                    selectedCell = new Vector3Int(Mathf.FloorToInt(result.pos.x), Mathf.FloorToInt(result.pos.y), Mathf.FloorToInt(result.pos.z));
                }
                else
                {
                    selectedCell = null;
                }

                if (selectedCell != null)
                {
                    lockedSelection = selectedCell.Value;
                }
                else
                {
                    lockedSelection = Vector3Int.zero;
                }
            }
            else
            {
                selectedCell = null;
            }
        }
        else
        {
            selectedCell = lockedSelection;
        }

        if (selectedCell != null && prevSelectedCell != selectedCell)
        {
            //field.FillCell(selectedCell.Value.x, selectedCell.Value.y, selectedCell.Value.z, 0, gizmoCellMaterials, gizmoCellIntersections, gizmoCellNormals);
            var sculpture = gameObject.GetComponent <VoxelWorldContainer>().Instance;
            VoxelChunk <MortonIndexer> chunk = sculpture.GetChunk(ChunkPos.FromVoxel(selectedCell.Value, sculpture.ChunkSize));
            if (chunk != null)
            {
                chunk.FillCell(
                    ((selectedCell.Value.x % sculpture.ChunkSize) + sculpture.ChunkSize) % sculpture.ChunkSize,
                    ((selectedCell.Value.y % sculpture.ChunkSize) + sculpture.ChunkSize) % sculpture.ChunkSize,
                    ((selectedCell.Value.z % sculpture.ChunkSize) + sculpture.ChunkSize) % sculpture.ChunkSize,
                    0, gizmoCellMaterials, gizmoCellIntersections, gizmoCellNormals);

                gizmoCell = new RawArrayVoxelCell(0, (Vector3)selectedCell.Value, gizmoCellMaterials, gizmoCellIntersections, gizmoCellNormals);

                NativeMemoryCache memoryCache = new NativeMemoryCache(Allocator.Persistent);

                var polygonizer = new CMSVoxelPolygonizer <RawArrayVoxelCell, CMSStandardProperties, SvdQefSolver <RawArrayVoxelCell>, IntersectionSharpFeatureSolver <RawArrayVoxelCell> >(new CMSStandardProperties(), new SvdQefSolver <RawArrayVoxelCell>(), new IntersectionSharpFeatureSolver <RawArrayVoxelCell>(), memoryCache);

                var components        = new NativeList <VoxelMeshComponent>(Allocator.Persistent);
                var componentIndices  = new NativeList <PackedIndex>(Allocator.Persistent);
                var componentVertices = new NativeList <VoxelMeshComponentVertex>(Allocator.Persistent);

                polygonizer.Polygonize(gizmoCell, components, componentIndices, componentVertices);

                gizmoComponents = new List <VoxelMeshComponent>(components.Length);
                for (int i = 0; i < components.Length; i++)
                {
                    gizmoComponents.Add(components[i]);
                }

                gizmoComponentIndices = new List <PackedIndex>(componentIndices.Length);
                for (int i = 0; i < componentIndices.Length; i++)
                {
                    gizmoComponentIndices.Add(componentIndices[i]);
                }

                gizmoComponentVertices = new List <VoxelMeshComponentVertex>(componentVertices.Length);
                for (int i = 0; i < componentVertices.Length; i++)
                {
                    gizmoComponentVertices.Add(componentVertices[i]);
                }

                memoryCache.Dispose();
                components.Dispose();
                componentIndices.Dispose();
                componentVertices.Dispose();

                gizmoPosition  = selectedCell.Value;
                gizmoTransform = Matrix4x4.TRS(transform.position, transform.rotation, transform.lossyScale);
            }
        }

        prevSelectedCell = selectedCell;

        float brushSize = 2.1f + 8;

        if (placeSdf)
        {
            placeSdf   = false;
            regenerate = true;

            var editManager = GetComponent <VoxelEditManagerContainer>().Instance;

            switch (brushType)
            {
            case BrushType.Sphere:
                gameObject.GetComponent <VoxelWorldContainer>().Instance.ApplySdf(new Vector3(gizmoPosition.x, gizmoPosition.y, gizmoPosition.z), Quaternion.Euler(sdfRotation), new SphereSDF(brushSize), MaterialColors.ToInteger(materialRed, materialGreen, materialBlue, materialTexture), replaceSdfMaterial, editManager.Consumer());
                break;

            case BrushType.Box:
                gameObject.GetComponent <VoxelWorldContainer>().Instance.ApplySdf(new Vector3(gizmoPosition.x, gizmoPosition.y, gizmoPosition.z), Quaternion.Euler(sdfRotation), new BoxSDF(brushSize), MaterialColors.ToInteger(materialRed, materialGreen, materialBlue, materialTexture), replaceSdfMaterial, editManager.Consumer());
                break;

            case BrushType.Cylinder:
                gameObject.GetComponent <VoxelWorldContainer>().Instance.ApplySdf(new Vector3(gizmoPosition.x, gizmoPosition.y, gizmoPosition.z), Quaternion.Euler(sdfRotation), new CylinderSDF(brushSize, brushSize), MaterialColors.ToInteger(materialRed, materialGreen, materialBlue, materialTexture), replaceSdfMaterial, editManager.Consumer());
                break;

            case BrushType.Pyramid:
                gameObject.GetComponent <VoxelWorldContainer>().Instance.ApplySdf(new Vector3(gizmoPosition.x, gizmoPosition.y - brushSize / 2, gizmoPosition.z), Quaternion.Euler(sdfRotation), new PyramidSDF(brushSize * 2, brushSize * 2), MaterialColors.ToInteger(materialRed, materialGreen, materialBlue, materialTexture), replaceSdfMaterial, editManager.Consumer());
                break;

            case BrushType.Mesh:
                var mesh      = voxelizeMesh.mesh;
                var triangles = mesh.triangles;
                var vertices  = mesh.vertices;
                var normals   = mesh.normals;

                var inVertices = new NativeArray <float3>(triangles.Length, Allocator.TempJob);
                var inNormals  = new NativeArray <float3>(triangles.Length, Allocator.TempJob);

                for (int l = triangles.Length, i = 0; i < l; i += 3)
                {
                    inVertices[i]     = vertices[triangles[i]];
                    inVertices[i + 1] = vertices[triangles[i + 1]];
                    inVertices[i + 2] = vertices[triangles[i + 2]];

                    inNormals[i]     = normals[triangles[i]];
                    inNormals[i + 1] = normals[triangles[i + 1]];
                    inNormals[i + 2] = normals[triangles[i + 2]];
                }

                int voxelizerSize = 64;
                var outVoxels     = new NativeArray3D <Voxel.Voxel, MortonIndexer>(new MortonIndexer(voxelizerSize, voxelizerSize, voxelizerSize), voxelizerSize, voxelizerSize, voxelizerSize, Allocator.TempJob);

                var voxelizationProperties = smoothVoxelizerNormals ? Voxelizer.VoxelizationProperties.SMOOTH : Voxelizer.VoxelizationProperties.FLAT;

                var watch = new System.Diagnostics.Stopwatch();
                watch.Start();

                using (var job = Voxelizer.Voxelize(inVertices, inNormals, outVoxels, MaterialColors.ToInteger(materialRed, materialGreen, materialBlue, materialTexture), voxelizationProperties))
                {
                    job.Handle.Complete();
                }

                watch.Stop();
                Debug.Log("Voxelized mesh: " + watch.ElapsedMilliseconds + "ms");
                watch.Reset();
                watch.Start();

                //TODO Make voxelizer also undoable?
                gameObject.GetComponent <VoxelWorldContainer>().Instance.ApplyGrid((int)gizmoPosition.x, (int)gizmoPosition.y, (int)gizmoPosition.z, outVoxels, true, false, null);

                watch.Stop();
                Debug.Log("Applied to grid: " + watch.ElapsedMilliseconds + "ms");

                inVertices.Dispose();
                inNormals.Dispose();
                outVoxels.Dispose();

                break;

            case BrushType.Custom:
                using (var sdf = customBrush.Instance.CreateSdf(Allocator.TempJob))
                {
                    gameObject.GetComponent <VoxelWorldContainer>().Instance.ApplySdf(new Vector3(gizmoPosition.x, gizmoPosition.y, gizmoPosition.z), Quaternion.Euler(sdfRotation), sdf, MaterialColors.ToInteger(materialRed, materialGreen, materialBlue, materialTexture), replaceSdfMaterial, editManager.Consumer());
                }
                break;
            }
        }

        if (gizmoPosition != null)
        {
            switch (brushType)
            {
            case BrushType.Sphere:
                gameObject.GetComponent <SdfShapeRenderHandler>().Render(new Vector3(gizmoPosition.x, gizmoPosition.y, gizmoPosition.z), Quaternion.Euler(sdfRotation), new SphereSDF(brushSize));
                break;

            case BrushType.Box:
                gameObject.GetComponent <SdfShapeRenderHandler>().Render(new Vector3(gizmoPosition.x, gizmoPosition.y, gizmoPosition.z), Quaternion.Euler(sdfRotation), new BoxSDF(brushSize));
                break;

            case BrushType.Cylinder:
                gameObject.GetComponent <SdfShapeRenderHandler>().Render(new Vector3(gizmoPosition.x, gizmoPosition.y, gizmoPosition.z), Quaternion.Euler(sdfRotation), new CylinderSDF(brushSize, brushSize));
                break;

            case BrushType.Pyramid:
                gameObject.GetComponent <SdfShapeRenderHandler>().Render(new Vector3(gizmoPosition.x, gizmoPosition.y - brushSize / 2, gizmoPosition.z), Quaternion.Euler(sdfRotation), new PyramidSDF(brushSize * 2, brushSize * 2));
                break;

            case BrushType.Custom:
                Matrix4x4 brushTransform = Matrix4x4.TRS(new Vector3(gizmoPosition.x, gizmoPosition.y, gizmoPosition.z), Quaternion.Euler(sdfRotation), new Vector3(1, 1, 1));
                using (var sdf = customBrush.Instance.CreateSdf(Allocator.TempJob))
                {
                    gameObject.GetComponent <SdfShapeRenderHandler>().Render(brushTransform, sdf);
                }

                Camera camera = Camera.current;
                if (camera != null)
                {
                    selectedPrimitive = -1;

                    var   ray    = camera.transform.forward.normalized;
                    float maxDst = 60.0f;
                    int   steps  = Mathf.CeilToInt(maxDst * 2);
                    for (int i = 0; i < steps && selectedPrimitive < 0; i++)
                    {
                        var pos = camera.transform.position + ray * maxDst / steps * i;

                        int j = 0;
                        foreach (var primitive in customBrush.Instance.Primitives)
                        {
                            var renderSdf = customBrush.Instance.Evaluator.GetRenderSdf(primitive);
                            if (renderSdf != null && renderSdf.Eval(math.mul(math.mul(brushTransform, primitive.invTransform), new float4(pos, 1.0f)).xyz) < 0)
                            {
                                selectedPrimitive = j;
                                break;
                            }
                            j++;
                        }
                    }
                }
                if (selectedPrimitive >= 0 && selectedPrimitive < customBrush.Instance.Primitives.Count)
                {
                    var primitive = customBrush.Instance.Primitives[selectedPrimitive];
                    var renderSdf = customBrush.Instance.Evaluator.GetRenderSdf(primitive);
                    if (renderSdf != null)
                    {
                        gameObject.GetComponent <SdfShapeRenderHandler>().Render(brushTransform * (Matrix4x4)primitive.transform, renderSdf);
                    }
                }
                break;
            }
        }

        if (generateEachFrame || regenerate)
        {
            regenerate = false;
            //GenerateMesh();
        }
    }
    private void GenerateMesh()
    {
        int size = (int)Mathf.Ceil(fieldSize * scale);

        /*field = new TestVoxelField(size, size, size);
         * GenerateScene(field);*/

        var dedupedTable = new Dictionary <int, List <VoxelMeshTessellation.DedupedVertex> >();

        var components        = new NativeList <VoxelMeshComponent>(Allocator.Persistent);
        var componentIndices  = new NativeList <PackedIndex>(Allocator.Persistent);
        var componentVertices = new NativeList <VoxelMeshComponentVertex>(Allocator.Persistent);

        int voxels = /*1;//*/ (size - 1) * (size - 1) * (size - 1);

        var cellMaterials     = new NativeArray <int>(voxels * 8, Allocator.Persistent);
        var cellIntersections = new NativeArray <float>(voxels * 12, Allocator.Persistent);
        var cellNormals       = new NativeArray <float3>(voxels * 12, Allocator.Persistent);

        var cells = new NativeArray <float3>(voxels, Allocator.Persistent);

        int voxelIndex = 0;

        for (int z = 0; z < size - 1; z++)
        {
            for (int y = 0; y < size - 1; y++)
            {
                for (int x = 0; x < size - 1; x++)
                {
                    if (renderLockedSelectionOnly && !(x == lockedSelection.x && y == lockedSelection.y && z == lockedSelection.z))
                    {
                        continue;
                    }

                    //field.FillCell(x, y, z, voxelIndex, cellMaterials, cellIntersections, cellNormals);

                    cells[voxelIndex] = new float3(x, y, z);

                    voxelIndex++;
                }
            }
        }

        NativeMemoryCache memoryCache = new NativeMemoryCache(Allocator.Persistent);

        VoxelMeshTessellation.NativeDeduplicationCache dedupeCache = new VoxelMeshTessellation.NativeDeduplicationCache(Allocator.Persistent);

        var meshVertices  = new NativeList <float3>(Allocator.Persistent);
        var meshNormals   = new NativeList <float3>(Allocator.Persistent);
        var meshTriangles = new NativeList <int>(Allocator.Persistent);
        var meshColors    = new NativeList <Color32>(Allocator.Persistent);
        var meshMaterials = new NativeList <int>(Allocator.Persistent);

        var polygonizerJob = new PolygonizeJob
        {
            Cells         = cells,
            MemoryCache   = memoryCache,
            Materials     = cellMaterials,
            Intersections = cellIntersections,
            Normals       = cellNormals,
            Components    = components,
            Indices       = componentIndices,
            Vertices      = componentVertices,
            MeshVertices  = meshVertices,
            MeshNormals   = meshNormals,
            MeshTriangles = meshTriangles,
            MeshColors    = meshColors,
            MeshMaterials = meshMaterials,
            DedupeCache   = dedupeCache
        };

        var watch = System.Diagnostics.Stopwatch.StartNew();

        polygonizerJob.Schedule().Complete();

        watch.Stop();

        string text = "Polygonized voxel field in " + watch.ElapsedMilliseconds + "ms. Vertices: " + meshVertices.Length + ". Run: " + run;

        Debug.Log(text);

        var cam = FindObjectOfType <Camera>();

        if (cam != null)
        {
            var display = cam.GetComponent <FPSDisplay>();
            if (display != null)
            {
                display.SetInfo(text);
            }
        }

        var vertices  = new List <Vector3>(meshVertices.Length);
        var indices   = new List <int>(meshTriangles.Length);
        var materials = new List <int>(meshMaterials.Length);
        var colors    = new List <Color32>(meshColors.Length);
        var normals   = new List <Vector3>(meshNormals.Length);

        for (int i = 0; i < meshVertices.Length; i++)
        {
            vertices.Add(meshVertices[i]);
        }
        for (int i = 0; i < meshTriangles.Length; i++)
        {
            indices.Add(meshTriangles[i]);
        }
        for (int i = 0; i < meshMaterials.Length; i++)
        {
            materials.Add(meshMaterials[i]);
        }
        for (int i = 0; i < meshColors.Length; i++)
        {
            colors.Add(meshColors[i]);
        }
        for (int i = 0; i < meshNormals.Length; i++)
        {
            normals.Add(meshNormals[i]);
        }

        dedupeCache.Dispose();

        meshVertices.Dispose();
        meshNormals.Dispose();
        meshTriangles.Dispose();
        meshColors.Dispose();
        meshMaterials.Dispose();

        memoryCache.Dispose();

        cells.Dispose();

        cellMaterials.Dispose();
        cellIntersections.Dispose();
        cellNormals.Dispose();

        components.Dispose();
        componentIndices.Dispose();
        componentVertices.Dispose();


        run++;

        voxelMesh.Clear(false);
        voxelMesh.SetVertices(vertices);
        voxelMesh.SetNormals(normals);
        voxelMesh.SetTriangles(indices, 0);
        if (colors.Count > 0)
        {
            voxelMesh.SetColors(colors);
        }

        if (meshCollider != null)
        {
            meshCollider.sharedMesh = voxelMesh;
        }
    }