修改水
This commit is contained in:
@@ -80,7 +80,7 @@ namespace Obi
|
||||
};
|
||||
|
||||
public readonly static Vector3Int[] faceNeighborhood =
|
||||
{
|
||||
{
|
||||
new Vector3Int(-1,0,0),
|
||||
new Vector3Int(1,0,0),
|
||||
new Vector3Int(0,-1,0),
|
||||
@@ -226,15 +226,15 @@ namespace Obi
|
||||
}
|
||||
|
||||
|
||||
public IEnumerator Voxelize(Matrix4x4 transform, Vector3Int axisMask, bool generateTriangleIndices = false)
|
||||
public IEnumerator Voxelize(Matrix4x4 transform, bool generateTriangleIndices = false)
|
||||
{
|
||||
voxelSize = Mathf.Max(0.0001f, voxelSize);
|
||||
|
||||
var xfBounds = input.bounds.Transform(transform);
|
||||
|
||||
// Calculate min and max voxels, adding a 1-voxel margin.
|
||||
origin = GetPointVoxel(Vector3.Scale(xfBounds.min, axisMask)) - axisMask;
|
||||
Vector3Int max = GetPointVoxel(Vector3.Scale(xfBounds.max, axisMask)) + axisMask;
|
||||
origin = GetPointVoxel(xfBounds.min) - new Vector3Int(1, 1, 1);
|
||||
Vector3Int max = GetPointVoxel(xfBounds.max) + new Vector3Int(1, 1, 1);
|
||||
|
||||
resolution = new Vector3Int(max.x - origin.x + 1, max.y - origin.y + 1, max.z - origin.z + 1);
|
||||
|
||||
@@ -263,9 +263,9 @@ namespace Obi
|
||||
// Generate surface voxels:
|
||||
for (int i = 0; i < triIndices.Length; i += 3)
|
||||
{
|
||||
Vector3 v1 = Vector3.Scale(transform.MultiplyPoint3x4(vertices[triIndices[i]]), axisMask);
|
||||
Vector3 v2 = Vector3.Scale(transform.MultiplyPoint3x4(vertices[triIndices[i + 1]]), axisMask);
|
||||
Vector3 v3 = Vector3.Scale(transform.MultiplyPoint3x4(vertices[triIndices[i + 2]]), axisMask);
|
||||
Vector3 v1 = transform.MultiplyPoint3x4(vertices[triIndices[i]]);
|
||||
Vector3 v2 = transform.MultiplyPoint3x4(vertices[triIndices[i + 1]]);
|
||||
Vector3 v3 = transform.MultiplyPoint3x4(vertices[triIndices[i + 2]]);
|
||||
|
||||
Bounds triBounds = GetTriangleBounds(v1, v2, v3);
|
||||
|
||||
@@ -281,7 +281,6 @@ namespace Obi
|
||||
yield return fillCoroutine.Current;
|
||||
}
|
||||
|
||||
// Ensures boundary is only one voxel thick.
|
||||
public void BoundaryThinning()
|
||||
{
|
||||
for (int x = 0; x < resolution.x; ++x)
|
||||
@@ -309,212 +308,6 @@ namespace Obi
|
||||
}
|
||||
}
|
||||
|
||||
// Ensures boundary voxels are 2D.
|
||||
public void MakeBoundary2D()
|
||||
{
|
||||
for (int x = 0; x < resolution.x; ++x)
|
||||
for (int y = 0; y < resolution.y; ++y)
|
||||
for (int z = 0; z < resolution.z; ++z)
|
||||
if (this[x, y, z] == Voxel.Boundary)
|
||||
this[x, y, z] = Voxel.Inside;
|
||||
|
||||
for (int x = 0; x < resolution.x; ++x)
|
||||
for (int y = 0; y < resolution.y; ++y)
|
||||
for (int z = 0; z < resolution.z; ++z)
|
||||
{
|
||||
int sum = 0;
|
||||
for (int j = 0; j < faceNeighborhood.Length; ++j)
|
||||
{
|
||||
var index = faceNeighborhood[j];
|
||||
if (VoxelExists(index.x + x, index.y + y, index.z + z) && this[index.x + x, index.y + y, index.z + z] != Voxel.Outside)
|
||||
{
|
||||
sum++;
|
||||
}
|
||||
}
|
||||
|
||||
if (sum <= 3 && this[x, y, z] == Voxel.Inside)
|
||||
this[x, y, z] = Voxel.Boundary;
|
||||
}
|
||||
}
|
||||
|
||||
public void CreateMesh(ref Mesh mesh, int smoothingIterations)
|
||||
{
|
||||
if (mesh == null)
|
||||
mesh = new Mesh();
|
||||
|
||||
mesh.indexFormat = UnityEngine.Rendering.IndexFormat.UInt32;
|
||||
mesh.Clear();
|
||||
List<Vector3> vertices = new List<Vector3>();
|
||||
List<Vector3> vertices2 = new List<Vector3>();
|
||||
List<int> tris = new List<int>();
|
||||
vertices.Clear();
|
||||
vertices2.Clear();
|
||||
tris.Clear();
|
||||
|
||||
int[] vtxIndex = new int[voxelCount];
|
||||
for (int i = 0; i < vtxIndex.Length; ++i)
|
||||
vtxIndex[i] = -1;
|
||||
|
||||
// create vertices:
|
||||
for (int x = 0; x < resolution.x; ++x)
|
||||
for (int y = 0; y < resolution.y; ++y)
|
||||
for (int z = 0; z < resolution.z; ++z)
|
||||
if (this[x, y, z] == Voxel.Boundary)
|
||||
{
|
||||
vtxIndex[GetVoxelIndex(x, y, z)] = vertices.Count;
|
||||
var vtx = new Vector3(Origin.x + x + 0.5f, Origin.y + y + 0.5f, Origin.z + z + 0.5f) * voxelSize;
|
||||
vertices.Add(vtx);
|
||||
vertices2.Add(vtx);
|
||||
}
|
||||
|
||||
List<Vector3> inputVertices = vertices;
|
||||
List<Vector3> outputVertices = vertices2;
|
||||
for (int i = 0; i < smoothingIterations; ++i)
|
||||
{
|
||||
for (int x = 0; x < resolution.x; ++x)
|
||||
for (int y = 0; y < resolution.y; ++y)
|
||||
for (int z = 0; z < resolution.z; ++z)
|
||||
if (this[x, y, z] == Voxel.Boundary)
|
||||
{
|
||||
Vector3 avg = Vector3.zero;
|
||||
|
||||
int count = 0;
|
||||
for (int j = 0; j < faceNeighborhood.Length; ++j)
|
||||
{
|
||||
var index = faceNeighborhood[j];
|
||||
if (VoxelExists(index.x + x, index.y + y, index.z + z) && this[index.x + x, index.y + y, index.z + z] == Voxel.Boundary)
|
||||
{
|
||||
avg += inputVertices[vtxIndex[GetVoxelIndex(index.x + x, index.y + y, index.z + z)]];
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
if (count > 0)
|
||||
outputVertices[vtxIndex[GetVoxelIndex(x, y, z)]] = avg / count;
|
||||
}
|
||||
|
||||
var aux = inputVertices;
|
||||
inputVertices = outputVertices;
|
||||
outputVertices = aux;
|
||||
}
|
||||
|
||||
// triangulate
|
||||
for (int x = 0; x < resolution.x; ++x)
|
||||
for (int y = 0; y < resolution.y; ++y)
|
||||
for (int z = 0; z < resolution.z; ++z)
|
||||
if (this[x, y, z] == Voxel.Boundary)
|
||||
{
|
||||
int x0y0z0 = GetVoxelIndex(x, y, z);
|
||||
|
||||
int x1y0z0 = VoxelExists(x + 1, y, z) ? GetVoxelIndex(x+1, y, z) : -1;
|
||||
int x1y1z0 = VoxelExists(x + 1, y + 1, z) ? GetVoxelIndex(x+1, y+1, z) : -1;
|
||||
int x0y1z0 = VoxelExists(x, y + 1, z) ? GetVoxelIndex(x, y+1, z) : -1;
|
||||
|
||||
int x0y0z1 = VoxelExists(x, y, z + 1) ? GetVoxelIndex(x, y , z + 1) : -1;
|
||||
int x0y1z1 = VoxelExists(x, y + 1, z + 1) ? GetVoxelIndex(x, y + 1, z + 1) : -1;
|
||||
int x1y0z1 = VoxelExists(x + 1, y, z + 1) ? GetVoxelIndex(x+1, y, z + 1) : -1;
|
||||
|
||||
int x1y1z1 = VoxelExists(x + 1, y + 1, z + 1) ? GetVoxelIndex(x + 1, y + 1, z + 1) : -1;
|
||||
|
||||
// XY plane
|
||||
if (x1y0z0 >= 0 && x1y1z0 >= 0 && x0y1z0 >= 0 &&
|
||||
voxels[x1y0z0] == Voxel.Boundary &&
|
||||
voxels[x1y1z0] == Voxel.Boundary &&
|
||||
voxels[x0y1z0] == Voxel.Boundary)
|
||||
{
|
||||
if (x0y1z1 < 0 || voxels[x0y1z1] == Voxel.Outside ||
|
||||
x0y0z1 < 0 || voxels[x0y0z1] == Voxel.Outside ||
|
||||
x1y0z1 < 0 || voxels[x1y0z1] == Voxel.Outside ||
|
||||
x1y1z1 < 0 || voxels[x1y1z1] == Voxel.Outside)
|
||||
{
|
||||
tris.Add(vtxIndex[x0y0z0]);
|
||||
tris.Add(vtxIndex[x1y0z0]);
|
||||
tris.Add(vtxIndex[x0y1z0]);
|
||||
|
||||
tris.Add(vtxIndex[x0y1z0]);
|
||||
tris.Add(vtxIndex[x1y0z0]);
|
||||
tris.Add(vtxIndex[x1y1z0]);
|
||||
}
|
||||
else
|
||||
{
|
||||
tris.Add(vtxIndex[x1y0z0]);
|
||||
tris.Add(vtxIndex[x0y0z0]);
|
||||
tris.Add(vtxIndex[x0y1z0]);
|
||||
|
||||
tris.Add(vtxIndex[x1y0z0]);
|
||||
tris.Add(vtxIndex[x0y1z0]);
|
||||
tris.Add(vtxIndex[x1y1z0]);
|
||||
}
|
||||
}
|
||||
|
||||
// XZ plane
|
||||
if (x1y0z0 >= 0 && x1y0z1 >= 0 && x0y0z1 >= 0 &&
|
||||
voxels[x1y0z0] == Voxel.Boundary &&
|
||||
voxels[x1y0z1] == Voxel.Boundary &&
|
||||
voxels[x0y0z1] == Voxel.Boundary)
|
||||
{
|
||||
if (x0y1z0 < 0 || voxels[x0y1z0] == Voxel.Outside ||
|
||||
x0y1z1 < 0 || voxels[x0y1z1] == Voxel.Outside ||
|
||||
x1y1z0 < 0 || voxels[x1y1z0] == Voxel.Outside ||
|
||||
x1y1z1 < 0 || voxels[x1y1z1] == Voxel.Outside)
|
||||
{
|
||||
tris.Add(vtxIndex[x1y0z0]);
|
||||
tris.Add(vtxIndex[x0y0z0]);
|
||||
tris.Add(vtxIndex[x0y0z1]);
|
||||
|
||||
tris.Add(vtxIndex[x1y0z0]);
|
||||
tris.Add(vtxIndex[x0y0z1]);
|
||||
tris.Add(vtxIndex[x1y0z1]);
|
||||
}
|
||||
else
|
||||
{
|
||||
tris.Add(vtxIndex[x0y0z0]);
|
||||
tris.Add(vtxIndex[x1y0z0]);
|
||||
tris.Add(vtxIndex[x0y0z1]);
|
||||
|
||||
tris.Add(vtxIndex[x0y0z1]);
|
||||
tris.Add(vtxIndex[x1y0z0]);
|
||||
tris.Add(vtxIndex[x1y0z1]);
|
||||
}
|
||||
}
|
||||
|
||||
// XY plane
|
||||
if (x0y0z1 >= 0 && x0y1z1 >= 0 && x0y1z0 >= 0 &&
|
||||
voxels[x0y0z1] == Voxel.Boundary &&
|
||||
voxels[x0y1z1] == Voxel.Boundary &&
|
||||
voxels[x0y1z0] == Voxel.Boundary)
|
||||
{
|
||||
if (x1y0z0 < 0 || voxels[x1y0z0] == Voxel.Outside ||
|
||||
x1y0z1 < 0 || voxels[x1y0z1] == Voxel.Outside ||
|
||||
x1y1z0 < 0 || voxels[x1y1z0] == Voxel.Outside ||
|
||||
x1y1z1 < 0 || voxels[x1y1z1] == Voxel.Outside)
|
||||
{
|
||||
tris.Add(vtxIndex[x0y0z1]);
|
||||
tris.Add(vtxIndex[x0y0z0]);
|
||||
tris.Add(vtxIndex[x0y1z0]);
|
||||
|
||||
tris.Add(vtxIndex[x0y0z1]);
|
||||
tris.Add(vtxIndex[x0y1z0]);
|
||||
tris.Add(vtxIndex[x0y1z1]);
|
||||
}
|
||||
else
|
||||
{
|
||||
tris.Add(vtxIndex[x0y0z0]);
|
||||
tris.Add(vtxIndex[x0y0z1]);
|
||||
tris.Add(vtxIndex[x0y1z0]);
|
||||
|
||||
tris.Add(vtxIndex[x0y1z0]);
|
||||
tris.Add(vtxIndex[x0y0z1]);
|
||||
tris.Add(vtxIndex[x0y1z1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mesh.SetVertices(outputVertices);
|
||||
mesh.SetIndices(tris, MeshTopology.Triangles, 0);
|
||||
mesh.RecalculateNormals();
|
||||
}
|
||||
|
||||
private IEnumerator FloodFill()
|
||||
{
|
||||
Queue<Vector3Int> queue = new Queue<Vector3Int>();
|
||||
@@ -631,5 +424,6 @@ namespace Obi
|
||||
|
||||
return !(Mathf.Max(-maxP, minP) > r);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,4 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Collections;
|
||||
using System.Collections;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Obi
|
||||
@@ -10,7 +9,7 @@ namespace Obi
|
||||
*/
|
||||
public class VoxelDistanceField
|
||||
{
|
||||
public Vector3[,,] distanceField; // for each coordinate, stores coordinates of closest surface voxel.
|
||||
public Vector3Int[,,] distanceField; // for each coordinate, stores coordinates of closest surface voxel.
|
||||
|
||||
private MeshVoxelizer voxelizer;
|
||||
|
||||
@@ -19,159 +18,115 @@ namespace Obi
|
||||
this.voxelizer = voxelizer;
|
||||
}
|
||||
|
||||
public Vector4 SampleUnfiltered(int x, int y, int z)
|
||||
public float SampleUnfiltered(int x, int y, int z)
|
||||
{
|
||||
x = Mathf.Clamp(x, 0, voxelizer.resolution.x - 1);
|
||||
y = Mathf.Clamp(y, 0, voxelizer.resolution.y - 1);
|
||||
z = Mathf.Clamp(z, 0, voxelizer.resolution.z - 1);
|
||||
if (!voxelizer.VoxelExists(x, y, z)) return float.PositiveInfinity;
|
||||
|
||||
var grad = distanceField[x, y, z];
|
||||
float dist = grad.magnitude;
|
||||
grad.Normalize();
|
||||
float dist = Vector3.Distance(voxelizer.GetVoxelCenter(distanceField[x, y, z]),
|
||||
voxelizer.GetVoxelCenter(new Vector3Int(x, y, z)));
|
||||
|
||||
return new Vector4(grad.x, grad.y, grad.z, -dist);
|
||||
if (voxelizer[x, y, z] == MeshVoxelizer.Voxel.Inside)
|
||||
return -dist;
|
||||
return dist;
|
||||
}
|
||||
|
||||
public Vector4 SampleFiltered(float x, float y, float z, Vector3Int axisMask)
|
||||
public Vector4 SampleFiltered(float x, float y, float z)
|
||||
{
|
||||
var pos = new Vector3(x, y, z);
|
||||
|
||||
// clamp position inside the distance field:
|
||||
var min = voxelizer.GetVoxelCenter(new Vector3Int(0, 0, 0));
|
||||
var min = voxelizer.GetVoxelCenter(new Vector3Int(0, 0, 0));
|
||||
var max = voxelizer.GetVoxelCenter(new Vector3Int(voxelizer.resolution.x - 1, voxelizer.resolution.y - 1, voxelizer.resolution.z - 1));
|
||||
pos.x = Mathf.Clamp(pos.x, min.x, max.x);
|
||||
pos.y = Mathf.Clamp(pos.y, min.y, max.y);
|
||||
pos.z = Mathf.Clamp(pos.z, min.z, max.z);
|
||||
pos.x = Mathf.Clamp(pos.x, min.x, max.x - voxelizer.voxelSize * 0.05f);
|
||||
pos.y = Mathf.Clamp(pos.y, min.y, max.y - voxelizer.voxelSize * 0.05f);
|
||||
pos.z = Mathf.Clamp(pos.z, min.z, max.z - voxelizer.voxelSize * 0.05f);
|
||||
|
||||
var voxel = voxelizer.GetPointVoxel(pos - Vector3.one * voxelizer.voxelSize * 0.5f) - voxelizer.Origin;
|
||||
|
||||
var voxel = voxelizer.GetPointVoxel(pos - (Vector3)axisMask * voxelizer.voxelSize * 0.5f) - voxelizer.Origin;
|
||||
var voxelCenter = voxelizer.GetVoxelCenter(voxel);
|
||||
var norm = Vector3.Scale((pos - voxelCenter) / voxelizer.voxelSize, axisMask);
|
||||
var norm = (pos - voxelCenter) / voxelizer.voxelSize;
|
||||
|
||||
var xz00 = SampleUnfiltered(voxel.x, voxel.y, voxel.z);
|
||||
var xz01 = SampleUnfiltered(voxel.x, voxel.y, voxel.z + 1);
|
||||
var xz10 = SampleUnfiltered(voxel.x + 1, voxel.y, voxel.z);
|
||||
var xz11 = SampleUnfiltered(voxel.x + 1, voxel.y, voxel.z + 1);
|
||||
float xz00 = SampleUnfiltered(voxel.x, voxel.y, voxel.z);
|
||||
float xz01 = SampleUnfiltered(voxel.x, voxel.y, voxel.z + 1);
|
||||
float xz10 = SampleUnfiltered(voxel.x + 1, voxel.y, voxel.z);
|
||||
float xz11 = SampleUnfiltered(voxel.x + 1, voxel.y, voxel.z + 1);
|
||||
|
||||
var yz00 = SampleUnfiltered(voxel.x, voxel.y + 1, voxel.z);
|
||||
var yz01 = SampleUnfiltered(voxel.x, voxel.y + 1, voxel.z + 1);
|
||||
var yz10 = SampleUnfiltered(voxel.x + 1, voxel.y + 1, voxel.z);
|
||||
var yz11 = SampleUnfiltered(voxel.x + 1, voxel.y + 1, voxel.z + 1);
|
||||
float yz00 = SampleUnfiltered(voxel.x, voxel.y + 1, voxel.z);
|
||||
float yz01 = SampleUnfiltered(voxel.x, voxel.y + 1, voxel.z + 1);
|
||||
float yz10 = SampleUnfiltered(voxel.x + 1, voxel.y + 1, voxel.z);
|
||||
float yz11 = SampleUnfiltered(voxel.x + 1, voxel.y + 1, voxel.z + 1);
|
||||
|
||||
var X1 = Vector4.Lerp(xz00, xz10, norm.x);
|
||||
var X2 = Vector4.Lerp(xz01, xz11, norm.x);
|
||||
var X3 = Vector4.Lerp(yz00, yz10, norm.x);
|
||||
var X4 = Vector4.Lerp(yz01, yz11, norm.x);
|
||||
float X1 = Mathf.Lerp(xz00, xz10, norm.x);
|
||||
float X2 = Mathf.Lerp(xz01, xz11, norm.x);
|
||||
float X3 = Mathf.Lerp(yz00, yz10, norm.x);
|
||||
float X4 = Mathf.Lerp(yz01, yz11, norm.x);
|
||||
|
||||
var Y1 = Vector4.Lerp(X1, X2, norm.z);
|
||||
var Y2 = Vector4.Lerp(X3, X4, norm.z);
|
||||
float Y1 = Mathf.Lerp(X1, X2, norm.z);
|
||||
float Y2 = Mathf.Lerp(X3, X4, norm.z);
|
||||
|
||||
return Vector4.Lerp(Y1, Y2, norm.y);
|
||||
}
|
||||
float R = Mathf.Lerp(Mathf.Lerp(xz10, xz11, norm.z), Mathf.Lerp(yz10, yz11, norm.z), norm.y);
|
||||
float L = Mathf.Lerp(Mathf.Lerp(xz00, xz01, norm.z), Mathf.Lerp(yz00, yz01, norm.z), norm.y);
|
||||
|
||||
public void Smooth()
|
||||
{
|
||||
// create output buffer for ping-pong.
|
||||
Vector3[,,] smoothed = new Vector3[voxelizer.resolution.x,
|
||||
voxelizer.resolution.y,
|
||||
voxelizer.resolution.z];
|
||||
float F = Mathf.Lerp(X2, X4, norm.y);
|
||||
float B = Mathf.Lerp(X1, X3, norm.y);
|
||||
|
||||
for (int x = 0; x < distanceField.GetLength(0); ++x)
|
||||
for (int y = 0; y < distanceField.GetLength(1); ++y)
|
||||
for (int z = 0; z < distanceField.GetLength(2); ++z)
|
||||
{
|
||||
if (voxelizer[x, y, z] != MeshVoxelizer.Voxel.Outside)
|
||||
{
|
||||
var p = new Vector3Int(x, y, z);
|
||||
Vector3 df = distanceField[x, y, z];
|
||||
int count = 1;
|
||||
foreach (var o in MeshVoxelizer.faceNeighborhood)
|
||||
{
|
||||
// offset voxel to get neighbor:
|
||||
var n = p + o;
|
||||
if (voxelizer.VoxelExists(n.x, n.y, n.z) && voxelizer[n.x, n.y, n.z] != MeshVoxelizer.Voxel.Outside)
|
||||
{
|
||||
df += distanceField[n.x, n.y, n.z];
|
||||
count++;
|
||||
}
|
||||
}
|
||||
df /= count;
|
||||
smoothed[x, y, z] = df;
|
||||
}
|
||||
}
|
||||
|
||||
distanceField = smoothed;
|
||||
}
|
||||
|
||||
private void CalculateGradientsAndDistances(Vector3Int[,,] buffer1)
|
||||
{
|
||||
distanceField = new Vector3[voxelizer.resolution.x,
|
||||
voxelizer.resolution.y,
|
||||
voxelizer.resolution.z];
|
||||
|
||||
for (int x = 0; x < buffer1.GetLength(0); ++x)
|
||||
for (int y = 0; y < buffer1.GetLength(1); ++y)
|
||||
for (int z = 0; z < buffer1.GetLength(2); ++z)
|
||||
{
|
||||
if (voxelizer[x, y, z] != MeshVoxelizer.Voxel.Outside)
|
||||
{
|
||||
distanceField[x, y, z] = voxelizer.GetVoxelCenter(buffer1[x, y, z]) -
|
||||
voxelizer.GetVoxelCenter(new Vector3Int(x, y, z));
|
||||
}
|
||||
else
|
||||
distanceField[x, y, z] = Vector3.zero;
|
||||
}
|
||||
return new Vector4((R - L) / voxelizer.voxelSize,
|
||||
(Y2 - Y1) / voxelizer.voxelSize,
|
||||
(F - B) / voxelizer.voxelSize,
|
||||
Mathf.Lerp(Y1, Y2, norm.y));
|
||||
}
|
||||
|
||||
public IEnumerator JumpFlood()
|
||||
{
|
||||
// create two buffers for ping-ponging:
|
||||
Vector3Int[,,] buffer1 = new Vector3Int[voxelizer.resolution.x,
|
||||
voxelizer.resolution.y,
|
||||
voxelizer.resolution.z];
|
||||
|
||||
Vector3Int[,,] buffer2 = new Vector3Int[voxelizer.resolution.x,
|
||||
// create and initialize distance field:
|
||||
distanceField = new Vector3Int[voxelizer.resolution.x,
|
||||
voxelizer.resolution.y,
|
||||
voxelizer.resolution.z];
|
||||
|
||||
// create auxiliar buffer for ping-pong.
|
||||
Vector3Int[,,] auxBuffer = new Vector3Int[voxelizer.resolution.x,
|
||||
voxelizer.resolution.y,
|
||||
voxelizer.resolution.z];
|
||||
|
||||
// initialize distance field:
|
||||
for (int x = 0; x < buffer1.GetLength(0); ++x)
|
||||
for (int y = 0; y < buffer1.GetLength(1); ++y)
|
||||
for (int z = 0; z < buffer1.GetLength(2); ++z)
|
||||
for (int x = 0; x < distanceField.GetLength(0); ++x)
|
||||
for (int y = 0; y < distanceField.GetLength(1); ++y)
|
||||
for (int z = 0; z < distanceField.GetLength(2); ++z)
|
||||
{
|
||||
if (voxelizer[x, y, z] == MeshVoxelizer.Voxel.Outside)
|
||||
buffer1[x, y, z] = new Vector3Int(x, y, z);
|
||||
if (voxelizer[x, y, z] == MeshVoxelizer.Voxel.Boundary)
|
||||
distanceField[x, y, z] = new Vector3Int(x, y, z);
|
||||
else
|
||||
buffer1[x, y, z] = new Vector3Int(-1, -1, -1);
|
||||
distanceField[x, y, z] = new Vector3Int(-1, -1, -1);
|
||||
}
|
||||
|
||||
// calculate the maximum size of the buffer:
|
||||
int size = Mathf.Max(buffer1.GetLength(0),
|
||||
buffer1.GetLength(1),
|
||||
buffer1.GetLength(2));
|
||||
int size = Mathf.Max(distanceField.GetLength(0),
|
||||
distanceField.GetLength(1),
|
||||
distanceField.GetLength(2));
|
||||
int step = (int)(size / 2.0f);
|
||||
|
||||
yield return new CoroutineJob.ProgressInfo("Generating voxel distance field...", 0);
|
||||
yield return new CoroutineJob.ProgressInfo("Generating voxel distance field...",0);
|
||||
|
||||
float numPasses = (int)Mathf.Log(size, 2);
|
||||
float numPasses = (int) Mathf.Log(size, 2);
|
||||
int i = 0;
|
||||
|
||||
// jump flood passes:
|
||||
while (step >= 1)
|
||||
{
|
||||
JumpFloodPass(step, buffer1, buffer2);
|
||||
JumpFloodPass(step, distanceField, auxBuffer);
|
||||
|
||||
// halve step:
|
||||
step /= 2;
|
||||
|
||||
// swap buffers:
|
||||
Vector3Int[,,] temp = buffer1;
|
||||
buffer1 = buffer2;
|
||||
buffer2 = temp;
|
||||
Vector3Int[,,] temp = distanceField;
|
||||
distanceField = auxBuffer;
|
||||
auxBuffer = temp;
|
||||
|
||||
yield return new CoroutineJob.ProgressInfo("Generating voxel distance field...", ++i / numPasses);
|
||||
}
|
||||
|
||||
CalculateGradientsAndDistances(buffer1);
|
||||
}
|
||||
|
||||
private void JumpFloodPass(int stride, Vector3Int[,,] input, Vector3Int[,,] output)
|
||||
@@ -200,30 +155,34 @@ namespace Obi
|
||||
dist = (s - p).sqrMagnitude;
|
||||
|
||||
// for each neighbor voxel:
|
||||
foreach (var o in MeshVoxelizer.fullNeighborhood)
|
||||
{
|
||||
// offset voxel to get neighbor:
|
||||
var n = p + o * stride;
|
||||
|
||||
if (voxelizer.VoxelExists(n.x, n.y, n.z))
|
||||
{
|
||||
// neighbors' closest seed.
|
||||
Vector3Int nc = input[n.x, n.y, n.z];
|
||||
|
||||
if (nc.x >= 0)
|
||||
for (int nx = -1; nx <= 1; ++nx)
|
||||
for (int ny = -1; ny <= 1; ++ny)
|
||||
for (int nz = -1; nz <= 1; ++nz)
|
||||
{
|
||||
// distance to neighbor's closest seed:
|
||||
float newDist = (nc - p).sqrMagnitude;
|
||||
// neighbor's position:
|
||||
int px = x + nx * stride;
|
||||
int py = y + ny * stride;
|
||||
int pz = z + nz * stride;
|
||||
|
||||
// if the distance to the neighbor's closest seed is smaller than the distance to ours:
|
||||
if (newDist < dist)
|
||||
if (voxelizer.VoxelExists(px,py,pz))
|
||||
{
|
||||
output[x, y, z] = nc;
|
||||
dist = newDist;
|
||||
// neighbors' closest seed.
|
||||
Vector3Int n = input[px,py,pz];
|
||||
|
||||
if (n.x >= 0)
|
||||
{
|
||||
// distance to neighbor's closest seed:
|
||||
float newDist = (n - p).sqrMagnitude;
|
||||
|
||||
// if the distance to the neighbor's closest seed is smaller than the distance to ours:
|
||||
if (newDist < dist)
|
||||
{
|
||||
output[x, y, z] = n;
|
||||
dist = newDist;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user