예제 #1
0
        /// <summary>
        /// Batch update. Reconstruct all meshes needed by running GPU based Marching Cubes
        /// </summary>
        public void BatchUpdate()
        {
            for (int x = 0; x < width / blockSize; x++)
            {
                for (int y = 0; y < height / blockSize; y++)
                {
                    for (int z = 0; z < length / blockSize; z++)
                    {
                        if (_blocks[x, y, z] == null)
                        {
                            continue;
                        }
                        if (_blocks[x, y, z].GetComponent <MeshFilter>().mesh != null)
                        {
                            _blocks[x, y, z].GetComponent <MeshFilter>().mesh.Clear();
                        }
                        //if (_blocks[x, y, z].GetComponent<MeshCollider>().sharedMesh != null)
                        //    _blocks[x, y, z].GetComponent<MeshCollider>().sharedMesh.Clear();
                    }
                }
            }

            shaderSample.SetBuffer(_kernelCollectSurfaceBlock, "_Particles", sphSolver._bufferParticles);
            _bufferSufaceBlocks.SetData(_surfaceBlocksInit);
            shaderSample.SetBuffer(_kernelCollectSurfaceBlock, "_SurfaceMCBlocks", _bufferSufaceBlocks);
            shaderSample.Dispatch(_kernelCollectSurfaceBlock, sphSolver._sphthreadGroupNum, 1, 1);
            _bufferSufaceBlocks.GetData(_surfaceBlocksContainer);
            _nextUpdateblocks.Clear();

            for (int i = 0; i < _surfaceBlocksContainer.Length; ++i)
            {
                if (_surfaceBlocksContainer[i] == 1)
                {
                    int x = i / (blockDimY * blockDimZ);
                    int y = (i - x * (blockDimY * blockDimZ)) / blockDimZ;
                    int z = i - x * (blockDimY * blockDimZ) - y * blockDimZ;
                    _nextUpdateblocks.Add(new Int3(x, y, z));
                }
            }

            //for (int x = 0; x < blockDimX; ++x)
            //    for (int y = 0; y < blockDimY; ++y)
            //        for (int z = 0; z < blockDimZ; ++z)
            //            _nextUpdateblocks.Add(new Int3(x, y, z));

            if (_nextUpdateblocks.Count == 0)
            {
                return;
            }

            //GPU sampling
            ComputeBuffer bufferBlocks = new ComputeBuffer(_nextUpdateblocks.Count, sizeof(int) * 3);

            bufferBlocks.SetData(_nextUpdateblocks.ToArray());


            //List<CSParticle> particlesCopy = new List<CSParticle>();

            //int[] particlesStartIdx = new int[sphSolver.gridCountXYZ + 1];

            //int startIdx = 0;
            //for (int x = 0; x < sphSolver.gridSize._x; ++x)
            //    for (int y = 0; y < sphSolver.gridSize._y; ++y)
            //        for (int z = 0; z < sphSolver.gridSize._z; ++z)
            //        {
            //            int idx = x * sphSolver.gridCountYZ + y * sphSolver.gridSize._z + z;
            //            foreach (var particle in sphSolver.grid[idx].particles)
            //            {
            //                particlesCopy.Add(new CSParticle((float)particle.mass, 1f / (float)particle.density,
            //                    new Vector3((float)particle.position.x, (float)particle.position.y, (float)particle.position.z)));
            //            }
            //            particlesStartIdx[idx] = startIdx;
            //            startIdx += sphSolver.grid[idx].particles.Count;
            //        }
            //particlesStartIdx[particlesStartIdx.Length - 1] = sphSolver.currParticleNum;

            //_bufferParticlesStartIndex.SetData(particlesStartIdx);
            //_bufferParticles.SetData(particlesCopy.ToArray());

            ComputeBuffer bufferSamples = new ComputeBuffer(_nextUpdateblocks.Count * (ag1BlockSize) * (ag1BlockSize) * (ag1BlockSize), sizeof(float));
            ComputeBuffer bufferNormals = new ComputeBuffer(_nextUpdateblocks.Count * (ag1BlockSize) * (ag1BlockSize) * (ag1BlockSize), sizeof(float) * 3);

            shaderSample.SetBuffer(sampleKernel, "_Blocks", bufferBlocks);
            shaderSample.SetBuffer(sampleKernel, "_ParticleCellNumPrefixSum", sphSolver._bufferParticleNumPerCell);
            shaderSample.SetBuffer(sampleKernel, "_Particles", sphSolver._bufferParticles);
            shaderSample.SetBuffer(sampleKernel, "_Samples", bufferSamples);
            shaderSample.SetBuffer(sampleKernel, "_Normals", bufferNormals);

            shaderSample.Dispatch(sampleKernel, _nextUpdateblocks.Count, 1, 1);

            bufferBlocks.Release();
            bufferBlocks = null;

            //marching-cube

            //STAGE I: collect triangle number
            ComputeBuffer bufferTriNum = new ComputeBuffer(1, sizeof(int));

            bufferTriNum.SetData(new int[] { 0 });
            ComputeBuffer bufferCornerFlags = new ComputeBuffer(_nextUpdateblocks.Count * blockSize * blockSize * blockSize, sizeof(int));

            shaderCollectTriNum.SetBuffer(ctnKernel, "_Samples", bufferSamples);
            shaderCollectTriNum.SetBuffer(ctnKernel, "_CornerToTriNumTable", _bufferCornerToTriNumTable);
            shaderCollectTriNum.SetBuffer(ctnKernel, "_TriNum", bufferTriNum);
            shaderCollectTriNum.SetBuffer(ctnKernel, "_CornerFlags", bufferCornerFlags);

            shaderCollectTriNum.Dispatch(ctnKernel, _nextUpdateblocks.Count, 1, 1);

            int[] triNum = new int[1];
            bufferTriNum.GetData(triNum);
            if (triNum[0] == 0)
            {
                //no triangles, early exit

                bufferNormals.Release();
                bufferSamples.Release();

                bufferTriNum.Release();
                bufferCornerFlags.Release();
                return;
            }
//#if UNITY_EDITOR
//            //Debug.Log("triangles count " + triNum[0]);
//#endif
            //STAGE II: do marching cube
            ComputeBuffer bufferMeshes      = new ComputeBuffer(triNum[0], CSTriangle.stride);
            ComputeBuffer bufferTriEndIndex = new ComputeBuffer(1, sizeof(int));

            bufferTriEndIndex.SetData(new int[] { 0 });
            ComputeBuffer bufferTriBlockNum = new ComputeBuffer(_nextUpdateblocks.Count, sizeof(int));

            int[] triBlockNum = new int[_nextUpdateblocks.Count];
            bufferTriBlockNum.SetData(triBlockNum);

            shaderMarchingCube.SetBuffer(mcKernel, "_Samples", bufferSamples);
            shaderMarchingCube.SetBuffer(mcKernel, "_Normals", bufferNormals);
            shaderMarchingCube.SetBuffer(mcKernel, "_CornerFlags", bufferCornerFlags);
            shaderMarchingCube.SetBuffer(mcKernel, "_CornerToEdgeTable", _bufferCornerToEdgeTable);
            shaderMarchingCube.SetBuffer(mcKernel, "_CornerToVertTable", _bufferCornerToVertTable);
            shaderMarchingCube.SetBuffer(mcKernel, "_Meshes", bufferMeshes);
            shaderMarchingCube.SetBuffer(mcKernel, "_TriEndIndex", bufferTriEndIndex);
            shaderMarchingCube.SetBuffer(mcKernel, "_TriBlockNum", bufferTriBlockNum);
            //dispatch compute shader
            shaderMarchingCube.Dispatch(mcKernel, _nextUpdateblocks.Count, 1, 1);

            //split bufferMeshes to meshes for individual blocks
            CSTriangle[] csTriangles = new CSTriangle[triNum[0]];//triNum[0] is the counter
            bufferMeshes.GetData(csTriangles);
            bufferTriBlockNum.GetData(triBlockNum);
            int[] triBlockCounter = new int[triBlockNum.Length];

            Vector3[][] vertices = new Vector3[_nextUpdateblocks.Count][];
            Vector3[][] normals  = new Vector3[_nextUpdateblocks.Count][];
            for (int i = 0; i < _nextUpdateblocks.Count; i++)
            {
                vertices[i] = new Vector3[3 * triBlockNum[i]];
                normals[i]  = new Vector3[3 * triBlockNum[i]];
            }
            foreach (var vt in csTriangles)
            {
                vertices[vt.block][triBlockCounter[vt.block]] = vt.position0 * engineScale;
                normals[vt.block][triBlockCounter[vt.block]]  = vt.normal0;
                triBlockCounter[vt.block]++;

                vertices[vt.block][triBlockCounter[vt.block]] = vt.position1 * engineScale;
                normals[vt.block][triBlockCounter[vt.block]]  = vt.normal1;
                triBlockCounter[vt.block]++;

                vertices[vt.block][triBlockCounter[vt.block]] = vt.position2 * engineScale;
                normals[vt.block][triBlockCounter[vt.block]]  = vt.normal2;
                triBlockCounter[vt.block]++;
            }

            for (int i = 0; i < _nextUpdateblocks.Count; i++)
            {
                var x = _nextUpdateblocks[i]._x;
                var y = _nextUpdateblocks[i]._y;
                var z = _nextUpdateblocks[i]._z;
                _blocks[x, y, z].GetComponent <MeshFilter>().mesh.Clear(false);
                var mesh = _blocks[x, y, z].GetComponent <MeshFilter>().mesh;

                mesh.vertices = vertices[i];
                int[] idx = new int[vertices[i].Length];
                Buffer.BlockCopy(_incSequence, 0, idx, 0, vertices[i].Length * sizeof(int));
                mesh.SetTriangles(idx, 0);
                mesh.normals = normals[i];
                mesh.Optimize();
                mesh.RecalculateBounds();
                // _blocks[x, y, z].GetComponent<MeshFilter>().mesh = mesh;
                _blocks[x, y, z].GetComponent <MeshRenderer>().material = material;
                //_blocks[x, y, z].GetComponent<MeshCollider>().sharedMesh = mesh;
            }

            //Debug.Log("Time taken: " + (Time.realtimeSinceStartup - startTime) * 1000.0f);
//#if UNITY_EDITOR
//            print("Time taken: " + (Time.realtimeSinceStartup - startTime) * 1000.0f);
//#endif
            bufferNormals.Release();
            bufferSamples.Release();

            bufferTriNum.Release();
            bufferCornerFlags.Release();

            bufferMeshes.Release();
            bufferTriEndIndex.Release();
            bufferTriBlockNum.Release();

            GC.Collect();
        }
예제 #2
0
        /// <summary>
        /// Batch update. Reconstruct all meshes needed by running GPU based Marching Cubes
        /// </summary>
        private void BatchUpdate()
        {
            if (_nextUpdateblocks.Count == 0)
            {
                return;
            }

            //In order to also recompute the normals of vertices, we need to also sample "one more layer" in adjacent cells
            //"argumented block size"
            int ag1BlockSize = blockSize + 1;
            int ag2BlockSize = blockSize + 2;

            //the array that hold samples in order to send them to GPU
            float[] samples = new float[_nextUpdateblocks.Count * (ag2BlockSize) * (ag2BlockSize) * (ag2BlockSize)];
            for (int blockNum = 0; blockNum < _nextUpdateblocks.Count; blockNum++)
            {
                var blockIdx = _nextUpdateblocks[blockNum];
                int x = blockIdx._x; int y = blockIdx._y; int z = blockIdx._z;
                for (int ix = 0; ix < ag2BlockSize; ix++)
                {
                    for (int iy = 0; iy < ag2BlockSize; iy++)
                    {
                        for (int iz = 0; iz < ag2BlockSize; iz++)
                        {
                            var queryX = x * blockSize + ix;
                            var queryY = y * blockSize + iy;
                            var queryZ = z * blockSize + iz;

                            //store value
                            samples[ix +
                                    iy * (ag2BlockSize) +
                                    iz * (ag2BlockSize) * (ag2BlockSize) +
                                    blockNum * (ag2BlockSize) * (ag2BlockSize) * (ag2BlockSize)]
                                = _voxelSamples[queryX, queryY, queryZ];
                        }
                    }
                }
            }

            //float startTime = Time.realtimeSinceStartup;
            ////rebuild normals
            int nrmKernel = _shaderNormal.FindKernel("SampleNormal");

            if (nrmKernel < 0)
            {
                throw new UnityException("Fail to find kernel of shader: " + _shaderNormal.name);
            }
            ComputeBuffer bufferSamples = new ComputeBuffer(_nextUpdateblocks.Count * (ag2BlockSize) * (ag2BlockSize) * (ag2BlockSize), sizeof(float));

            bufferSamples.SetData(samples);
            _shaderNormal.SetBuffer(nrmKernel, "_Samples", bufferSamples);

            ComputeBuffer bufferNormals = new ComputeBuffer(_nextUpdateblocks.Count * (ag1BlockSize) * (ag1BlockSize) * (ag1BlockSize), sizeof(float) * 3);

            _shaderNormal.SetBuffer(nrmKernel, "_Normals", bufferNormals);
            //dispatch compute shader
            _shaderNormal.Dispatch(nrmKernel, _nextUpdateblocks.Count, 1, 1);

            //marching-cube

            //STAGE I: collect triangle number
            int ctnKernel = _shaderCollectTriNum.FindKernel("CollectTriNum");

            if (ctnKernel < 0)
            {
                throw new UnityException("Fail to find kernel of shader: " + _shaderCollectTriNum.name);
            }
            ComputeBuffer bufferTriNum = new ComputeBuffer(1, sizeof(int));

            bufferTriNum.SetData(new int[] { 0 });
            ComputeBuffer bufferCornerFlags = new ComputeBuffer(_nextUpdateblocks.Count * blockSize * blockSize * blockSize, sizeof(int));

            _shaderCollectTriNum.SetBuffer(ctnKernel, "_Samples", bufferSamples);
            _shaderCollectTriNum.SetBuffer(ctnKernel, "_CornerToTriNumTable", _bufferCornerToTriNumTable);
            _shaderCollectTriNum.SetBuffer(ctnKernel, "_TriNum", bufferTriNum);
            _shaderCollectTriNum.SetBuffer(ctnKernel, "_CornerFlags", bufferCornerFlags);

            _shaderCollectTriNum.Dispatch(ctnKernel, _nextUpdateblocks.Count, 1, 1);

            int[] triNum = new int[1];
            bufferTriNum.GetData(triNum);
            if (triNum[0] == 0)
            {
                //no triangles, early exit
                bufferNormals.Release();
                bufferSamples.Release();

                bufferTriNum.Release();
                bufferCornerFlags.Release();
                return;
            }
            //Debug.Log("triangles count " + triNum[0]);

            //STAGE II: do marching cube
            int mcKernel = _shaderMarchingCube.FindKernel("MarchingCube");

            if (mcKernel < 0)
            {
                throw new UnityException("Fail to find kernel of shader: " + _shaderMarchingCube.name);
            }
            ComputeBuffer bufferMeshes      = new ComputeBuffer(triNum[0], CSTriangle.stride);
            ComputeBuffer bufferTriEndIndex = new ComputeBuffer(1, sizeof(int));

            bufferTriEndIndex.SetData(new int[] { 0 });
            _shaderMarchingCube.SetBuffer(mcKernel, "_Samples", bufferSamples);
            _shaderMarchingCube.SetBuffer(mcKernel, "_Normals", bufferNormals);
            _shaderMarchingCube.SetBuffer(mcKernel, "_CornerFlags", bufferCornerFlags);
            _shaderMarchingCube.SetBuffer(mcKernel, "_CornerToEdgeTable", _bufferCornerToEdgeTable);
            _shaderMarchingCube.SetBuffer(mcKernel, "_CornerToVertTable", _bufferCornerToVertTable);
            _shaderMarchingCube.SetBuffer(mcKernel, "_Meshes", bufferMeshes);
            _shaderMarchingCube.SetBuffer(mcKernel, "_TriEndIndex", bufferTriEndIndex);
            //dispatch compute shader
            _shaderMarchingCube.Dispatch(mcKernel, _nextUpdateblocks.Count, 1, 1);

            //split bufferMeshes to meshes for individual blocks
            CSTriangle[] csTriangles = new CSTriangle[triNum[0]];//triNum[0] is the counter
            bufferMeshes.GetData(csTriangles);


            List <Vector3>[] vertices = new List <Vector3> [_nextUpdateblocks.Count];
            List <Vector3>[] normals  = new List <Vector3> [_nextUpdateblocks.Count];
            for (int i = 0; i < _nextUpdateblocks.Count; i++)
            {
                vertices[i] = new List <Vector3>();
                normals[i]  = new List <Vector3>();
            }
            foreach (var vt in csTriangles)
            {
                vertices[vt._block].Add(vt._position0 * _voxelScale);
                vertices[vt._block].Add(vt._position1 * _voxelScale);
                vertices[vt._block].Add(vt._position2 * _voxelScale);

                normals[vt._block].Add(vt._normal0);
                normals[vt._block].Add(vt._normal1);
                normals[vt._block].Add(vt._normal2);
            }

            for (int i = 0; i < _nextUpdateblocks.Count; i++)
            {
                var x = _nextUpdateblocks[i]._x;
                var y = _nextUpdateblocks[i]._y;
                var z = _nextUpdateblocks[i]._z;
                _blocks[x, y, z].GetComponent <MeshFilter>().mesh.Clear();
                var mesh = new Mesh();

                mesh.vertices = vertices[i].ToArray();
                var idx = Enumerable.Range(0, vertices[i].Count).ToArray();
                mesh.SetTriangles(idx, 0);
                mesh.normals = normals[i].ToArray();
                mesh.Optimize();
                mesh.RecalculateBounds();
                _blocks[x, y, z].GetComponent <MeshFilter>().mesh         = mesh;
                _blocks[x, y, z].GetComponent <MeshRenderer>().material   = _material;
                _blocks[x, y, z].GetComponent <MeshCollider>().sharedMesh = mesh;
            }

            //Debug.Log("Time taken: " + (Time.realtimeSinceStartup - startTime) * 1000.0f);

            bufferNormals.Release();
            bufferSamples.Release();

            bufferTriNum.Release();
            bufferCornerFlags.Release();

            bufferMeshes.Release();
            bufferTriEndIndex.Release();
        }