public Voxel_t[] GetData() { var voxels = new Voxel_t[Buffer.count]; Buffer.GetData(voxels); return(voxels); }
/* * 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); }
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); } } } }
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)); }
// 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)); }
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)); }