static void SmearDirection(VoxelSet <float> voxels, float transference, Vec3i dir) { Vec3i dx = new Vec3i(Math.Abs(dir.y), Math.Abs(dir.z), Math.Abs(dir.x)); Vec3i dy = new Vec3i(Math.Abs(dir.z), Math.Abs(dir.x), Math.Abs(dir.y)); Vec3i start = new Vec3i(0); if (Vec3i.Dot(dir, new Vec3i(1)) < 0) { start = voxels.Size.Dot(dir) * dir + dir; } int y = 0; while (voxels.IsValid(start + y * dy)) { int x = 0; while (voxels.IsValid(start + y * dy + x * dx)) { SmearLine(voxels, transference, dir, start + y * dy + x * dx); x++; } y++; } }
public static List <Box> MakeBoxes(VoxelSet <bool> shape) { List <Box> boxes = new List <Box>(); // Directions to explore Vec3i[] dirs = new[] { new Vec3i(1, 0, 0), new Vec3i(0, 1, 0), new Vec3i(0, 0, 1) }; // TODO: Iteration order may need to be reversed for (int z = 0; z < shape.Size.z; z++) { for (int y = 0; y < shape.Size.y; y++) { for (int x = 0; x < shape.Size.x; x++) { if (!shape[x, y, z]) { continue; } Vec3i idx = new Vec3i(x, y, z); Vec3i endIdx = new Vec3i(x, y, z); // Expand box in each cardinal direction as much as possible foreach (var dir in dirs) { Vec3i checkFromIdx = idx; // Expand as much as possible in the current direction while (shape.IsValid(endIdx + dir)) { checkFromIdx += dir; // Create a slice for the next layer in the current dir and make sure it's solid var slice = shape.Slice(checkFromIdx, endIdx + dir); if (!slice.IsAllSolid(b => b)) { break; } slice.Set(false); endIdx += dir; } } Box box = new Box(); box.origin = new Vec3i(x, y, z); box.extents = new Vec3i(endIdx.x + 1 - idx.x, endIdx.y + 1 - idx.y, endIdx.z + 1 - idx.z); boxes.Add(box); } } } return(boxes); }
static void SmearLine(VoxelSet <float> voxels, float transference, Vec3i dir, Vec3i start) { Vec3i idx = start + dir; while (voxels.IsValid(idx)) { voxels[idx] += voxels[idx - dir] * transference; idx += dir; } }
bool LayerMarch(Vector3 startPoint, Vector3 dir, out Vec3i hitIdx, out Vec3i lastIdx, ref float t) { dir = Vector3.Normalize(dir); Vector3 voxelGridSize = new Vector3(voxels.Size.x, voxels.Size.y, voxels.Size.z); Vector3 p0 = startPoint; float endT = VecUtil.MinComp(Vector3.Max( VecUtil.Div(voxelGridSize - p0, dir), VecUtil.Div(-p0, dir) )); Vector3 dirAbs = VecUtil.Abs(dir); // TODO: This is making invalid assumptions about p0 //Vector3 p0abs = VecUtil.Mul(Vector3.one - VecUtil.Step(0, dir), voxelGridSize) // + VecUtil.Mul(VecUtil.Sign(dir), p0); //Vector3 negativeDimensions = Vector3.one - VecUtil.Step(0, dir); //Vector3 p0abs = VecUtil.Mul(negativeDimensions, voxelGridSize) - VecUtil.Mul(negativeDimensions, p0) //+ VecUtil.Mul(VecUtil.Step(0, dir), p0); Vector3 p0abs = p0; for (int i = 0; i < 3; ++i) { if (dir[i] < 0) { p0abs[i] = voxelGridSize[i] - p0[i]; } } //float t = 0; //t = 0; lastIdx = ToIndex(p0 + dir * (t - kEps)); int iterationCount = 0; List <Vector3> debugPos = new List <Vector3>(); List <Vector3> debugPosAbs = new List <Vector3>(); t += kEps; while (t <= endT) { Vec3i idx = ToIndex(p0 + dir * (t + kEps)); debugPos.Add(p0 + dir * (t + kEps)); //Vec3i idx = ToIndex(p0 + dir * t); debugPosAbs.Add(p0abs + dirAbs * (t + kEps)); Vector3 pAbs = p0abs + dirAbs * (t + kEps); //////////////// // DEBUG CODE Vec3i delta = idx - lastIdx; if (Vec3i.Dot(delta, delta) > 1) { Debug.LogWarning("Skipped a voxel"); } if (!voxels.IsValid(idx)) { break; } Color32 c = voxels[idx]; if (c.a > 0) { hitIdx = idx; return(true); } lastIdx = idx; // Pretend we came in from a positive direction //Vector3 pAbs = p0abs + dirAbs * (t); Vector3 deltas = VecUtil.Div(Vector3.one - VecUtil.Fract(pAbs), dirAbs); //t += Mathf.Max(VecUtil.MinComp(deltas), float.Epsilon); //t += Mathf.Max(VecUtil.MinComp(deltas), 0.0005f); t += Mathf.Max(VecUtil.MinComp(deltas), kEps) + kEps; //Vector3 pAbs = p0abs + dirAbs * t; //Vector3 deltas = VecUtil.Div(Vector3.one - VecUtil.Fract(pAbs), dirAbs); //t += Mathf.Max(VecUtil.MinComp(deltas), float.Epsilon); //Vector3 pAbs = p0abs + dirAbs * t; //Vector3 p = p0 + dir * t; //Vector3 deltas = VecUtil.Div(VecUtil.Step(0, dir) - VecUtil.Fract(p), dir); //t += Mathf.Max(VecUtil.MinComp(deltas), 0.0005f); //t += Mathf.Max(VecUtil.MinComp(deltas), float.Epsilon); iterationCount++; } hitIdx = new Vec3i(-1); return(false); }
public static List <Quad> VoxelsToQuads(VoxelSet <Vec4b> voxels) { List <Quad> quads = new List <Quad>(); Vec3f[] normals = { new Vec3f(1, 0, 0), new Vec3f(-1, 0, 0), new Vec3f(0, 1, 0), new Vec3f(0, -1, 0), new Vec3f(0, 0, 1), new Vec3f(0, 0, -1) }; Vec3f[] dxs = { new Vec3f(0, 1, 0), new Vec3f(0, 0, 1), new Vec3f(0, 0, 1), new Vec3f(1, 0, 0), new Vec3f(1, 0, 0), new Vec3f(0, 1, 0) }; Vec3f[] dys = { new Vec3f(0, 0, 1), new Vec3f(0, 1, 0), new Vec3f(1, 0, 0), new Vec3f(0, 0, 1), new Vec3f(0, 1, 0), new Vec3f(1, 0, 0) }; voxels.Apply((Vec4b c, Vec3i idx) => { if (c.w == 0) { // Voxel is empty //return; } // Check each face for (int i = 0; i < 6; ++i) { Quad quad = new Quad(); quad.normal = normals[i]; quad.dx = dxs[i]; quad.dy = dys[i]; quad.offset = new Vec3f(idx.x, idx.y, idx.z); quad.color = c; Vec3i neighbor = idx + new Vec3i(new Vec3f(quad.normal.x, quad.normal.y, quad.normal.z)); if (c.w == 0 || voxels.IsValid(neighbor) && voxels[neighbor].w > 0) { // Voxel face is covered continue; } if (quad.normal.x > 0 || quad.normal.y > 0 || quad.normal.z > 0) { quad.offset += quad.normal; } quads.Add(quad); } }); return(quads); }
//////////////////////////////////////////////////////////////////////////// // Adds all faces for the given index of the given voxels to the list of quads. static void AddFaces(VoxelSet <Vec4b> voxels, List <Quad> quads, Vec3i idx) { Vec3i[] normals = { new Vec3i(1, 0, 0), new Vec3i(-1, 0, 0), new Vec3i(0, 1, 0), new Vec3i(0, -1, 0), new Vec3i(0, 0, 1), new Vec3i(0, 0, -1) }; bool transparent = IsTransparent(voxels, idx); for (int i = 0; i < normals.Length; ++i) { Vec3i normal = normals[i]; Vec3i neighbor = idx + normal; if (voxels.IsValid(neighbor) && (voxels[neighbor].w > 0)) { if (transparent && IsTransparent(voxels, neighbor)) { // Two transparent voxels - face is hidden. continue; } if (transparent && voxels[neighbor].w == 255) { // Transparent self and opaque neighbor - hidden to avoid z-fighting. continue; } if (!transparent && voxels[neighbor].w == 255) { // Two opaque voxels - face is hidden. continue; } } var c = voxels[idx]; Quad q = new Quad(); q.color = new Color32(c.x, c.y, c.z, c.w); Vec3i pos = idx; if (Vec3i.Dot(normal, new Vec3i(1)) > 0) { pos += normal; } q.position = new Vector3(pos.x, pos.y, pos.z); q.uv = new Vector2(i, 0); quads.Add(q); if (transparent) { // Add back facing as well for transparent quads //q.uv = new Vector2((i - (i % 2)) + ((i + 1) % 2), 0); q.uv = new Vector2(i ^ 1, 0); //q.position += new Vector3(normal.x, normal.y, normal.z); quads.Add(q); } } }