static unsafe void GetVoxelsInternal(ref GetVoxelsContext context, int indexStart) { int i0 = context.indices[indexStart]; int i1 = context.indices[indexStart + 1]; int i2 = context.indices[indexStart + 2]; SimpleMesh.Vertex v0 = context.verts[i0]; SimpleMesh.Vertex v1 = context.verts[i1]; SimpleMesh.Vertex v2 = context.verts[i2]; float3 a = v0.Position; float3 b = v1.Position; float3 c = v2.Position; float3 normalTri; { float3 normalCross = cross(b - a, c - a); float normalCrossLengthSqrd = dot(normalCross, normalCross); if (normalCrossLengthSqrd == 0f) { return; } normalTri = normalCross * rcp(sqrt(normalCrossLengthSqrd)); } // extend every tri by half a voxel by just extending it along the corner-middle dir. // it's a naive attempt to get a conservative rasterizer - works good enough in general float3 middle = (a + b + c) / 3f; a += normalize(a - middle) * 0.5f; b += normalize(b - middle) * 0.5f; c += normalize(c - middle) * 0.5f; // get the AABB float3 minf = min(a, min(b, c)); float3 maxf = max(a, max(b, c)); int3 maxDimensions = context.maxDimensions; int3 mini = clamp(int3(floor(minf)), 0, maxDimensions); int3 maxi = clamp(int3(ceil(maxf)), 0, maxDimensions); int written = 0; VoxelizedPosition *positions = context.positions; int positionsLength = context.positionLength; Color color0 = v0.Color; Color color1 = v1.Color; Color color2 = v2.Color; for (int x = mini.x; x <= maxi.x; x++) { for (int z = mini.z; z <= maxi.z; z++) { for (int y = mini.y; y <= maxi.y; y++) { float3 voxel = float3(x, y, z) + 0.5f; float normalDistToTriangle = dot(voxel - a, normalTri); if (abs(normalDistToTriangle) > 0.5f) { continue; // distance to the triangle plane is over half a voxel -> the other side will have a voxel instead if we're at 0.5-1.0 dist } // set up barycentric coordinates float3 p = voxel - normalTri * normalDistToTriangle; float3 p0 = b - a; float3 p1 = c - a; float3 p2 = p - a; float d00 = dot(p0, p0); float d01 = dot(p0, p1); float d11 = dot(p1, p1); float d20 = dot(p2, p0); float d21 = dot(p2, p1); float denom = 1f / (d00 * d11 - d01 * d01); float3 barry; barry.y = (d11 * d20 - d01 * d21) * denom; // v1 barry.z = (d00 * d21 - d01 * d20) * denom; // v2 barry.x = 1.0f - barry.y - barry.z; // v0 if (any(barry < 0 | barry > 1)) { continue; // we're on the triangle plane, but outside the triangle } // interpolate vertex colors with the barycentric coordinates Color color; color.r = (color0.r * barry.x + color1.r * barry.y + color2.r * barry.z); color.g = (color0.g * barry.x + color1.g * barry.y + color2.g * barry.z); color.b = (color0.b * barry.x + color1.b * barry.y + color2.b * barry.z); color.a = 1f; float2 uv; uv.x = (v0.UV.x * barry.x + v1.UV.x * barry.y + v2.UV.x * barry.z); uv.y = (v0.UV.y * barry.x + v1.UV.y * barry.y + v2.UV.y * barry.z); int idx = x * (maxDimensions.z + 1) + z; positions[written++] = new VoxelizedPosition { XZIndex = idx, Y = (short)y, Color = color, MaterialIndex = (sbyte)v0.MaterialIndex, UV = uv }; if (written == positionsLength) { goto END; // buffer full, our triangle must've been huge } } } } END: context.writtenVoxelCount = written; }
public unsafe static void GetVoxels(ref GetVoxelsContext context, int indexStart) { GetVoxelsInvoker(ref context, indexStart); }