Beispiel #1
0
        public Voxel_t[] GetData()
        {
            var voxels = new Voxel_t[Buffer.count];

            Buffer.GetData(voxels);
            return(voxels);
        }
Beispiel #2
0
/*
 *      public static int GetNearPow2(float n)
 *      {
 *          if(n <= 0) {
 *              return 0;
 *          }
 *          Debug.LogFormat("GetNearPow2 n:{0}", n);
 *          var k = Mathf.CeilToInt(Mathf.Log(n, 2));
 *          Debug.LogFormat("GetNearPow2 2^k:{0}", k);
 *          return (int)Mathf.Pow(2, k);
 *      }
 */


        public void InitVoxelization(
            Mesh mesh,
            Bounds bounds,
            int resolution = 32,
            bool pow2      = true
            )
        {
            //
            // Bounding & resolusion settings
            //
            var maxLength = Mathf.Max(bounds.size.x, Mathf.Max(bounds.size.y, bounds.size.z));

            this.unit     = maxLength / resolution;
            this.halfUnit = this.unit * 0.5f;

            // Extend (min & max) to voxelize boundary surface correctly.
            this.voxelBoundsStart = bounds.min - new Vector3(this.halfUnit, this.halfUnit, this.halfUnit);
            this.voxelBoundsEnd   = bounds.max + new Vector3(this.halfUnit, this.halfUnit, this.halfUnit);
            this.voxelBoundsSize  = voxelBoundsEnd - voxelBoundsStart;

            if (!pow2)
            {
                this.resolutionWidth  = Mathf.CeilToInt(this.voxelBoundsSize.x / this.unit);
                this.resolutionHeight = Mathf.CeilToInt(this.voxelBoundsSize.y / this.unit);
                this.resolutionDepth  = Mathf.CeilToInt(this.voxelBoundsSize.z / this.unit);
            }
            else
            {
                this.resolutionWidth  = Mathf.ClosestPowerOfTwo((int)(this.voxelBoundsSize.x / this.unit));
                this.resolutionHeight = Mathf.ClosestPowerOfTwo((int)(this.voxelBoundsSize.y / this.unit));
                this.resolutionDepth  = Mathf.ClosestPowerOfTwo((int)(this.voxelBoundsSize.z / this.unit));
            }
            //Debug.LogFormat("w: {0}, h: {1}, d: {2}", this.resolutionWidth, this.resolutionHeight, this.resolutionDepth);
            //Debug.LogFormat("resolution: {0}, this.unit: {1}", resolution, this.unit);

            this.voxelBuffer = new ComputeBuffer(this.resolutionWidth * this.resolutionHeight * this.resolutionDepth,
                                                 Marshal.SizeOf(typeof(Voxel_t)));
            var voxels = new Voxel_t[this.voxelBuffer.count];

            //Debug.LogFormat("voxels count: {0}", this.voxelBuffer.count);
            this.voxelBuffer.SetData(voxels); // initialize voxels explicitly. Takes a lot of times

            //
            // Compute buffers for a mesh
            //
            this.vertBuffer = new ComputeBuffer(mesh.vertices.Length, Marshal.SizeOf(typeof(Vector3)));
            this.vertBuffer.SetData(mesh.vertices);

            this.uvBuffer = new ComputeBuffer(vertBuffer.count, Marshal.SizeOf(typeof(Vector2)));
            if (mesh.uv.Length > 0)
            {
                uvBuffer.SetData(mesh.uv);
            }
            this.triBuffer = new ComputeBuffer(mesh.triangles.Length, Marshal.SizeOf(typeof(int)));
            this.triBuffer.SetData(mesh.triangles);
        }
Beispiel #3
0
        static void CalculatePlane(
            List <Vector3> vertices, List <Vector3> normals, List <Vector4> centers, List <Vector2> uvs, List <int> triangles,
            Voxel_t voxel, bool useUV, Vector3 offset, Vector3 right, Vector3 up, Vector3 normal, int rSegments = 2, int uSegments = 2
            )
        {
            float rInv = 1f / (rSegments - 1);
            float uInv = 1f / (uSegments - 1);

            int triangleOffset = vertices.Count;
            var center         = voxel.position;

            var transformed = center + offset;

            for (int y = 0; y < uSegments; y++)
            {
                float ru = y * uInv;
                for (int x = 0; x < rSegments; x++)
                {
                    float rr = x * rInv;
                    vertices.Add(transformed + right * (rr - 0.5f) + up * (ru - 0.5f));
                    normals.Add(normal);
                    centers.Add(center);
                    if (useUV)
                    {
                        uvs.Add(voxel.uv);
                    }
                    else
                    {
                        uvs.Add(new Vector2(rr, ru));
                    }
                }

                if (y < uSegments - 1)
                {
                    var ioffset = y * rSegments + triangleOffset;
                    for (int x = 0, n = rSegments - 1; x < n; x++)
                    {
                        triangles.Add(ioffset + x);
                        triangles.Add(ioffset + x + rSegments);
                        triangles.Add(ioffset + x + 1);

                        triangles.Add(ioffset + x + 1);
                        triangles.Add(ioffset + x + rSegments);
                        triangles.Add(ioffset + x + 1 + rSegments);
                    }
                }
            }
        }
Beispiel #4
0
        public static GPUVoxelData Voxelize(ComputeShader voxelizer, Mesh mesh, Bounds bounds, int resolution = 32, bool volume = true, bool pow2 = false)
        {
            var vertices   = mesh.vertices;
            var vertBuffer = new ComputeBuffer(vertices.Length, Marshal.SizeOf(typeof(Vector3)));

            vertBuffer.SetData(vertices);

            var uvBuffer = new ComputeBuffer(vertBuffer.count, Marshal.SizeOf(typeof(Vector2)));

            if (mesh.uv.Length > 0)
            {
                var uv = mesh.uv;
                uvBuffer.SetData(uv);
            }

            var triangles = mesh.triangles;
            var triBuffer = new ComputeBuffer(triangles.Length, Marshal.SizeOf(typeof(int)));

            triBuffer.SetData(triangles);

            var maxLength = Mathf.Max(bounds.size.x, Mathf.Max(bounds.size.y, bounds.size.z));
            var unit      = maxLength / resolution;
            var hunit     = unit * 0.5f;

            // Extend (min & max) to voxelize boundary surface correctly.
            var start = bounds.min - new Vector3(hunit, hunit, hunit);
            var end   = bounds.max + new Vector3(hunit, hunit, hunit);
            var size  = end - start;

            int w, h, d;

            if (!pow2)
            {
                w = Mathf.CeilToInt(size.x / unit);
                h = Mathf.CeilToInt(size.y / unit);
                d = Mathf.CeilToInt(size.z / unit);
            }
            else
            {
                w = GetNearPow2(size.x / unit);
                h = GetNearPow2(size.y / unit);
                d = GetNearPow2(size.z / unit);
            }

            var voxelBuffer = new ComputeBuffer(w * h * d, Marshal.SizeOf(typeof(Voxel_t)));
            var voxels      = new Voxel_t[voxelBuffer.count];

            voxelBuffer.SetData(voxels); // initialize voxels explicitly

            // send bounds
            voxelizer.SetVector(kStartKey, start);
            voxelizer.SetVector(kEndKey, end);
            voxelizer.SetVector(kSizeKey, size);

            voxelizer.SetFloat(kUnitKey, unit);
            voxelizer.SetFloat(kInvUnitKey, 1f / unit);
            voxelizer.SetFloat(kHalfUnitKey, hunit);
            voxelizer.SetInt(kWidthKey, w);
            voxelizer.SetInt(kHeightKey, h);
            voxelizer.SetInt(kDepthKey, d);

            // send mesh data
            voxelizer.SetInt(kTriCountKey, triBuffer.count);
            var indexes = triBuffer.count / 3;

            voxelizer.SetInt(kTriIndexesKey, indexes);

            // surface front
            var surfaceFrontKer = new Kernel(voxelizer, kSurfaceFrontKernelKey);

            voxelizer.SetBuffer(surfaceFrontKer.Index, kVertBufferKey, vertBuffer);
            voxelizer.SetBuffer(surfaceFrontKer.Index, kUVBufferKey, uvBuffer);
            voxelizer.SetBuffer(surfaceFrontKer.Index, kTriBufferKey, triBuffer);
            voxelizer.SetBuffer(surfaceFrontKer.Index, kVoxelBufferKey, voxelBuffer);
            voxelizer.Dispatch(surfaceFrontKer.Index, indexes / (int)surfaceFrontKer.ThreadX + 1, (int)surfaceFrontKer.ThreadY, (int)surfaceFrontKer.ThreadZ);

            // surface back
            var surfaceBackKer = new Kernel(voxelizer, kSurfaceBackKernelKey);

            voxelizer.SetBuffer(surfaceBackKer.Index, kVertBufferKey, vertBuffer);
            voxelizer.SetBuffer(surfaceBackKer.Index, kUVBufferKey, uvBuffer);
            voxelizer.SetBuffer(surfaceBackKer.Index, kTriBufferKey, triBuffer);
            voxelizer.SetBuffer(surfaceBackKer.Index, kVoxelBufferKey, voxelBuffer);
            voxelizer.Dispatch(surfaceBackKer.Index, indexes / (int)surfaceBackKer.ThreadX + 1, (int)surfaceBackKer.ThreadY, (int)surfaceBackKer.ThreadZ);

            if (volume)
            {
                var volumeKer = new Kernel(voxelizer, kVolumeKernelKey);
                voxelizer.SetBuffer(volumeKer.Index, kVoxelBufferKey, voxelBuffer);
                voxelizer.Dispatch(volumeKer.Index, w / (int)volumeKer.ThreadX + 1, h / (int)volumeKer.ThreadY + 1, (int)surfaceFrontKer.ThreadZ);
            }

            // dispose
            vertBuffer.Release();
            uvBuffer.Release();
            triBuffer.Release();

            return(new GPUVoxelData(voxelBuffer, w, h, d, unit));
        }
Beispiel #5
0
        // http://blog.wolfire.com/2009/11/Triangle-mesh-voxelization
        public static void Voxelize(Mesh mesh, int resolution, out List <Voxel_t> voxels, out float unit)
        {
            mesh.RecalculateBounds();

            var   bounds    = mesh.bounds;
            float maxLength = Mathf.Max(bounds.size.x, Mathf.Max(bounds.size.y, bounds.size.z));

            unit = maxLength / resolution;
            var hunit = unit * 0.5f;

            var start = bounds.min - new Vector3(hunit, hunit, hunit);
            var end   = bounds.max + new Vector3(hunit, hunit, hunit);
            var size  = end - start;

            var width  = Mathf.CeilToInt(size.x / unit);
            var height = Mathf.CeilToInt(size.y / unit);
            var depth  = Mathf.CeilToInt(size.z / unit);

            var volume    = new Voxel_t[width, height, depth];
            var boxes     = new Bounds[width, height, depth];
            var voxelSize = Vector3.one * unit;

            for (int x = 0; x < width; x++)
            {
                for (int y = 0; y < height; y++)
                {
                    for (int z = 0; z < depth; z++)
                    {
                        var p    = new Vector3(x, y, z) * unit + start;
                        var aabb = new Bounds(p, voxelSize);
                        boxes[x, y, z] = aabb;
                    }
                }
            }

            // build triangles
            var vertices  = mesh.vertices;
            var uvs       = mesh.uv;
            var uv00      = Vector2.zero;
            var indices   = mesh.triangles;
            var direction = Vector3.forward;

            for (int i = 0, n = indices.Length; i < n; i += 3)
            {
                var tri = new Triangle(
                    vertices[indices[i]],
                    vertices[indices[i + 1]],
                    vertices[indices[i + 2]],
                    direction
                    );

                Vector2 uva, uvb, uvc;
                if (uvs.Length > 0)
                {
                    uva = uvs[indices[i]];
                    uvb = uvs[indices[i + 1]];
                    uvc = uvs[indices[i + 2]];
                }
                else
                {
                    uva = uvb = uvc = uv00;
                }

                var min = tri.bounds.min - start;
                var max = tri.bounds.max - start;
                int iminX = Mathf.RoundToInt(min.x / unit), iminY = Mathf.RoundToInt(min.y / unit), iminZ = Mathf.RoundToInt(min.z / unit);
                int imaxX = Mathf.RoundToInt(max.x / unit), imaxY = Mathf.RoundToInt(max.y / unit), imaxZ = Mathf.RoundToInt(max.z / unit);
                // int iminX = Mathf.FloorToInt(min.x / unit), iminY = Mathf.FloorToInt(min.y / unit), iminZ = Mathf.FloorToInt(min.z / unit);
                // int imaxX = Mathf.CeilToInt(max.x / unit), imaxY = Mathf.CeilToInt(max.y / unit), imaxZ = Mathf.CeilToInt(max.z / unit);

                iminX = Mathf.Clamp(iminX, 0, width - 1);
                iminY = Mathf.Clamp(iminY, 0, height - 1);
                iminZ = Mathf.Clamp(iminZ, 0, depth - 1);
                imaxX = Mathf.Clamp(imaxX, 0, width - 1);
                imaxY = Mathf.Clamp(imaxY, 0, height - 1);
                imaxZ = Mathf.Clamp(imaxZ, 0, depth - 1);

                // Debug.Log((iminX + "," + iminY + "," + iminZ) + " ~ " + (imaxX + "," + imaxY + "," + imaxZ));

                uint front = (uint)(tri.frontFacing ? 1 : 0);

                for (int x = iminX; x <= imaxX; x++)
                {
                    for (int y = iminY; y <= imaxY; y++)
                    {
                        for (int z = iminZ; z <= imaxZ; z++)
                        {
                            if (Intersects(tri, boxes[x, y, z]))
                            {
                                var voxel = volume[x, y, z];
                                voxel.position = boxes[x, y, z].center;
                                voxel.uv       = tri.GetUV(voxel.position, uva, uvb, uvc);
                                if ((voxel.fill & 1) == 0)
                                {
                                    voxel.front = front;
                                }
                                else
                                {
                                    voxel.front = voxel.front & front;
                                }
                                voxel.fill      = voxel.fill | 1;
                                volume[x, y, z] = voxel;
                            }
                        }
                    }
                }
            }

            for (int x = 0; x < width; x++)
            {
                for (int y = 0; y < height; y++)
                {
                    for (int z = 0; z < depth; z++)
                    {
                        if (volume[x, y, z].IsCavity())
                        {
                            continue;
                        }

                        int ifront = z;

                        Vector2 uv = Vector2.zero;
                        for (; ifront < depth; ifront++)
                        {
                            if (!volume[x, y, ifront].IsFrontFace())
                            {
                                break;
                            }
                            uv = volume[x, y, ifront].uv;
                        }

                        if (ifront >= depth)
                        {
                            break;
                        }

                        var iback = ifront;

                        // step forward to cavity
                        for (; iback < depth && volume[x, y, iback].IsCavity(); iback++)
                        {
                        }

                        if (iback >= depth)
                        {
                            break;
                        }

                        // check if iback is back voxel
                        if (volume[x, y, iback].IsBackFace())
                        {
                            // step forward to back face
                            for (; iback < depth && volume[x, y, iback].IsBackFace(); iback++)
                            {
                            }
                        }

                        // fill from ifront to iback
                        for (int z2 = ifront; z2 < iback; z2++)
                        {
                            var p     = boxes[x, y, z2].center;
                            var voxel = volume[x, y, z2];
                            voxel.position   = p;
                            voxel.uv         = uv;
                            voxel.fill       = 1;
                            volume[x, y, z2] = voxel;
                        }

                        z = iback;
                    }
                }
            }

            voxels = new List <Voxel_t>();
            for (int x = 0; x < width; x++)
            {
                for (int y = 0; y < height; y++)
                {
                    for (int z = 0; z < depth; z++)
                    {
                        if (!volume[x, y, z].IsCavity())
                        {
                            voxels.Add(volume[x, y, z]);
                        }
                    }
                }
            }
        }
        public static GPUVoxelData Voxelize(ComputeShader voxelizer, Mesh mesh, Bounds bounds, int count = 32, bool volume = true, bool pow2 = false)
        {
            var vertices   = mesh.vertices;
            var vertBuffer = new ComputeBuffer(vertices.Length, Marshal.SizeOf(typeof(Vector3)));

            vertBuffer.SetData(vertices);

            var uvBuffer = new ComputeBuffer(vertBuffer.count, Marshal.SizeOf(typeof(Vector2)));

            if (mesh.uv.Length > 0)
            {
                var uv = mesh.uv;
                uvBuffer.SetData(uv);
            }

            var triangles = mesh.triangles;
            var triBuffer = new ComputeBuffer(triangles.Length, Marshal.SizeOf(typeof(int)));

            triBuffer.SetData(triangles);

            var maxLength = Mathf.Max(bounds.size.x, Mathf.Max(bounds.size.y, bounds.size.z));
            var unit      = maxLength / count;
            var size      = bounds.size;

            int w, h, d;

            if (!pow2)
            {
                w = Mathf.CeilToInt(size.x / unit);
                h = Mathf.CeilToInt(size.y / unit);
                d = Mathf.CeilToInt(size.z / unit);
            }
            else
            {
                w = GetNearPow2(size.x / unit);
                h = GetNearPow2(size.y / unit);
                d = GetNearPow2(size.z / unit);
            }

            var voxelBuffer = new ComputeBuffer(w * h * d, Marshal.SizeOf(typeof(Voxel_t)));
            var voxels      = new Voxel_t[voxelBuffer.count];

            voxelBuffer.SetData(voxels); // initialize voxels explicitly
            var kernel = new Kernel(voxelizer, volume ? kVolumeKernelKey : kSurfaceKernelKey);

            // send bounds
            voxelizer.SetVector(kStartKey, bounds.min);
            voxelizer.SetVector(kEndKey, bounds.max);
            voxelizer.SetVector(kSizeKey, bounds.size);

            voxelizer.SetFloat(kUnitKey, unit);
            voxelizer.SetFloat(kInvUnitKey, 1f / unit);
            voxelizer.SetFloat(kHalfUnitKey, unit * 0.5f);
            voxelizer.SetInt(kWidthKey, w);
            voxelizer.SetInt(kHeightKey, h);
            voxelizer.SetInt(kDepthKey, d);

            // send mesh data
            voxelizer.SetBuffer(kernel.Index, kVertBufferKey, vertBuffer);
            voxelizer.SetBuffer(kernel.Index, kUVBufferKey, uvBuffer);
            voxelizer.SetInt(kTriCountKey, triBuffer.count);
            voxelizer.SetBuffer(kernel.Index, kTriBufferKey, triBuffer);
            voxelizer.SetBuffer(kernel.Index, kVoxelBufferKey, voxelBuffer);

            voxelizer.Dispatch(kernel.Index, w / (int)kernel.ThreadX + 1, h / (int)kernel.ThreadY + 1, (int)kernel.ThreadZ);

            // dispose
            vertBuffer.Release();
            uvBuffer.Release();
            triBuffer.Release();

            return(new GPUVoxelData(voxelBuffer, w, h, d, unit));
        }
Beispiel #7
0
        public static GPUVoxelData Voxelize(ComputeShader voxelizer, Mesh mesh, Matrix4x4 worldToObjMat, float worldUnit = 1.0f, bool volume = true, bool pow2 = false)
        {
            mesh.RecalculateBounds();
            var bounds     = mesh.bounds;
            var vertices   = mesh.vertices;
            var vertBuffer = new ComputeBuffer(vertices.Length, Marshal.SizeOf(typeof(Vector3)));

            vertBuffer.SetData(vertices);

            var uvBuffer = new ComputeBuffer(vertBuffer.count, Marshal.SizeOf(typeof(Vector2)));

            if (mesh.uv.Length > 0)
            {
                var uv = mesh.uv;
                uvBuffer.SetData(uv);
            }

            var triangles = mesh.triangles;
            var triBuffer = new ComputeBuffer(triangles.Length, Marshal.SizeOf(typeof(int)));

            triBuffer.SetData(triangles);
            Vector3 worldUnitVec = new Vector3(worldUnit, worldUnit, worldUnit);
            Vector3 unit         = worldToObjMat.MultiplyVector(worldUnitVec);
            var     hunit        = unit * 0.5f;

            // Extend (min & max) to voxelize boundary surface correctly.
            var start = bounds.min;

            start  = worldToObjMat.inverse.MultiplyPoint(start);
            start  = new Vector3(Mathf.RoundToInt(start.x), Mathf.RoundToInt(start.y), Mathf.RoundToInt(start.z));
            start -= worldUnitVec;
            start  = worldToObjMat.MultiplyPoint(start);
            var end = bounds.max;

            end  = worldToObjMat.inverse.MultiplyPoint(end);
            end  = new Vector3(Mathf.RoundToInt(end.x), Mathf.RoundToInt(end.y), Mathf.RoundToInt(end.z));
            end += worldUnitVec;
            end  = worldToObjMat.MultiplyPoint(end);
            var size = end - start;

            int w, h, d;

            if (!pow2)
            {
                w = Mathf.CeilToInt(size.x / unit.x);
                h = Mathf.CeilToInt(size.y / unit.y);
                d = Mathf.CeilToInt(size.z / unit.z);
            }
            else
            {
                w = GetNearPow2(size.x / unit.x);
                h = GetNearPow2(size.y / unit.y);
                d = GetNearPow2(size.z / unit.z);
            }

            var voxelBuffer = new ComputeBuffer(w * h * d, Marshal.SizeOf(typeof(Voxel_t)));
            var voxels      = new Voxel_t[voxelBuffer.count];

            voxelBuffer.SetData(voxels); // initialize voxels explicitly

            // send bounds
            voxelizer.SetVector(kStartKey, start);
            voxelizer.SetVector(kEndKey, end);
            voxelizer.SetVector(kSizeKey, size);

            voxelizer.SetVector(kUnitKey, unit);
            voxelizer.SetVector(kInvUnitKey, new Vector3(1f / unit.x, 1f / unit.y, 1f / unit.z));
            voxelizer.SetVector(kHalfUnitKey, hunit);
            voxelizer.SetInt(kWidthKey, w);
            voxelizer.SetInt(kHeightKey, h);
            voxelizer.SetInt(kDepthKey, d);

            // send mesh data
            voxelizer.SetInt(kTriCountKey, triBuffer.count);
            var indexes = triBuffer.count / 3;

            voxelizer.SetInt(kTriIndexesKey, indexes);

            // surface front
            var surfaceFrontKer = new Kernel(voxelizer, kSurfaceFrontKernelKey);

            voxelizer.SetBuffer(surfaceFrontKer.Index, kVertBufferKey, vertBuffer);
            voxelizer.SetBuffer(surfaceFrontKer.Index, kUVBufferKey, uvBuffer);
            voxelizer.SetBuffer(surfaceFrontKer.Index, kTriBufferKey, triBuffer);
            voxelizer.SetBuffer(surfaceFrontKer.Index, kVoxelBufferKey, voxelBuffer);
            voxelizer.Dispatch(surfaceFrontKer.Index, indexes / (int)surfaceFrontKer.ThreadX + 1, (int)surfaceFrontKer.ThreadY, (int)surfaceFrontKer.ThreadZ);

            // surface back
            var surfaceBackKer = new Kernel(voxelizer, kSurfaceBackKernelKey);

            voxelizer.SetBuffer(surfaceBackKer.Index, kVertBufferKey, vertBuffer);
            voxelizer.SetBuffer(surfaceBackKer.Index, kUVBufferKey, uvBuffer);
            voxelizer.SetBuffer(surfaceBackKer.Index, kTriBufferKey, triBuffer);
            voxelizer.SetBuffer(surfaceBackKer.Index, kVoxelBufferKey, voxelBuffer);
            voxelizer.Dispatch(surfaceBackKer.Index, indexes / (int)surfaceBackKer.ThreadX + 1, (int)surfaceBackKer.ThreadY, (int)surfaceBackKer.ThreadZ);

            if (volume)
            {
                var volumeKer = new Kernel(voxelizer, kVolumeKernelKey);
                voxelizer.SetBuffer(volumeKer.Index, kVoxelBufferKey, voxelBuffer);
                voxelizer.Dispatch(volumeKer.Index, w / (int)volumeKer.ThreadX + 1, h / (int)volumeKer.ThreadY + 1, (int)surfaceFrontKer.ThreadZ);
            }

            // dispose
            vertBuffer.Release();
            uvBuffer.Release();
            triBuffer.Release();

            return(new GPUVoxelData(voxelBuffer, w, h, d, unit));
        }