添加插件
This commit is contained in:
187
Assets/Obi/Scripts/Common/DataStructures/ASDF/ASDF.cs
Normal file
187
Assets/Obi/Scripts/Common/DataStructures/ASDF/ASDF.cs
Normal file
@@ -0,0 +1,187 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Obi
|
||||
{
|
||||
public class ASDF
|
||||
{
|
||||
static readonly Vector4[] corners =
|
||||
{
|
||||
new Vector4(-1,-1,-1,-1),
|
||||
new Vector4(-1,-1,1,-1),
|
||||
new Vector4(-1,1,-1,-1),
|
||||
new Vector4(-1,1,1,-1),
|
||||
|
||||
new Vector4(1,-1,-1,-1),
|
||||
new Vector4(1,-1,1,-1),
|
||||
new Vector4(1,1,-1,-1),
|
||||
new Vector4(1,1,1,-1)
|
||||
};
|
||||
|
||||
static readonly Vector4[] samples =
|
||||
{
|
||||
new Vector4(0,0,0,0),
|
||||
new Vector4(1,0,0,0),
|
||||
new Vector4(-1,0,0,0),
|
||||
new Vector4(0,1,0,0),
|
||||
new Vector4(0,-1,0,0),
|
||||
new Vector4(0,0,1,0),
|
||||
new Vector4(0,0,-1,0),
|
||||
|
||||
new Vector4(0,-1,-1,0),
|
||||
new Vector4(0,-1,1,0),
|
||||
new Vector4(0,1,-1,0),
|
||||
new Vector4(0,1,1,0),
|
||||
|
||||
new Vector4(-1,0,-1,0),
|
||||
new Vector4(-1,0,1,0),
|
||||
new Vector4(1,0,-1,0),
|
||||
new Vector4(1,0,1,0),
|
||||
|
||||
new Vector4(-1,-1,0,0),
|
||||
new Vector4(-1,1,0,0),
|
||||
new Vector4(1,-1,0,0),
|
||||
new Vector4(1,1,0,0)
|
||||
};
|
||||
|
||||
const float sqrt3 = 1.73205f;
|
||||
|
||||
public static IEnumerator Build(float maxError, int maxDepth, Vector3[] vertexPositions, int[] triangleIndices, List<DFNode> nodes, int yieldAfterNodeCount = 32)
|
||||
{
|
||||
// Empty vertex or triangle lists, return.
|
||||
if (maxDepth <= 0 ||
|
||||
nodes == null ||
|
||||
vertexPositions == null || vertexPositions.Length == 0 ||
|
||||
triangleIndices == null || triangleIndices.Length == 0)
|
||||
yield break;
|
||||
|
||||
// Build a bounding interval hierarchy from the triangles, to speed up distance queries:
|
||||
IBounded[] t = new IBounded[triangleIndices.Length / 3];
|
||||
for (int i = 0; i < t.Length; ++i)
|
||||
{
|
||||
int t1 = triangleIndices[i * 3];
|
||||
int t2 = triangleIndices[i * 3 + 1];
|
||||
int t3 = triangleIndices[i * 3 + 2];
|
||||
t[i] = new Triangle(t1, t2, t3, vertexPositions[t1], vertexPositions[t2], vertexPositions[t3]);
|
||||
}
|
||||
var bih = BIH.Build(ref t);
|
||||
|
||||
// Copy reordered triangles over to a new array:
|
||||
Triangle[] tris = Array.ConvertAll(t, x => (Triangle)x);
|
||||
|
||||
// Build angle weighted normals, used to determine the sign of the distance field.
|
||||
Vector3[] angleNormals = ObiUtils.CalculateAngleWeightedNormals(vertexPositions,triangleIndices);
|
||||
|
||||
// Calculate bounding box of the mesh:
|
||||
Bounds bounds = new Bounds(vertexPositions[0], Vector3.zero);
|
||||
for (int i = 1; i < vertexPositions.Length; ++i)
|
||||
bounds.Encapsulate(vertexPositions[i]);
|
||||
|
||||
bounds.Expand(0.2f);
|
||||
|
||||
// Auxiliar variables to keep track of current tree depth:
|
||||
int depth = 0;
|
||||
int nodesToNextLevel = 1;
|
||||
|
||||
// Initialize node list:
|
||||
Vector4 center = bounds.center;
|
||||
Vector3 boundsExtents = bounds.extents;
|
||||
center[3] = Mathf.Max(boundsExtents[0], Math.Max(boundsExtents[1], boundsExtents[2]));
|
||||
nodes.Clear();
|
||||
nodes.Add(new DFNode(center));
|
||||
|
||||
|
||||
var queue = new Queue<int>();
|
||||
queue.Enqueue(0);
|
||||
|
||||
int processedNodeCount = 0;
|
||||
while (queue.Count > 0)
|
||||
{
|
||||
// get current node:
|
||||
int index = queue.Dequeue();
|
||||
var node = nodes[index];
|
||||
|
||||
// measure distance at the 8 node corners:
|
||||
for (int i = 0; i < 8; ++i)
|
||||
{
|
||||
Vector4 point = node.center + corners[i] * node.center[3];
|
||||
point[3] = 0;
|
||||
float distance = BIH.DistanceToSurface(bih, tris, vertexPositions,angleNormals,point);
|
||||
|
||||
if (i < 4)
|
||||
node.distancesA[i] = distance;
|
||||
else
|
||||
node.distancesB[i - 4] = distance;
|
||||
}
|
||||
|
||||
// only subdivide those nodes intersecting the surface:
|
||||
if (depth < maxDepth && Mathf.Abs(BIH.DistanceToSurface(bih, tris, vertexPositions, angleNormals, node.center)) < node.center[3] * sqrt3)
|
||||
{
|
||||
|
||||
// calculate mean squared error between measured distances and interpolated ones:
|
||||
float mse = 0;
|
||||
for (int i = 0; i < samples.Length; ++i)
|
||||
{
|
||||
Vector4 point = node.center + samples[i] * node.center[3];
|
||||
float groundTruth = BIH.DistanceToSurface(bih, tris, vertexPositions, angleNormals, point);
|
||||
float estimation = node.Sample(point);
|
||||
float d = groundTruth - estimation;
|
||||
mse += d * d;
|
||||
}
|
||||
mse /= (float)samples.Length;
|
||||
|
||||
// if error > threshold, subdivide the node:
|
||||
if (mse > maxError)
|
||||
{
|
||||
node.firstChild = nodes.Count;
|
||||
for (int i = 0; i < 8; ++i)
|
||||
{
|
||||
queue.Enqueue(nodes.Count);
|
||||
nodes.Add(new DFNode(node.center + corners[i] * node.center[3] * 0.5f));
|
||||
}
|
||||
}
|
||||
|
||||
// keep track of current depth:
|
||||
if (--nodesToNextLevel == 0)
|
||||
{
|
||||
depth++;
|
||||
nodesToNextLevel = queue.Count;
|
||||
}
|
||||
}
|
||||
|
||||
// feed the modified node back:
|
||||
nodes[index] = node;
|
||||
|
||||
// if we've processed enough nodes, yield.
|
||||
if (nodes.Count - processedNodeCount >= yieldAfterNodeCount)
|
||||
{
|
||||
processedNodeCount = nodes.Count;
|
||||
yield return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static float Sample(List<DFNode> nodes, Vector3 position)
|
||||
{
|
||||
if (nodes != null && nodes.Count > 0)
|
||||
{
|
||||
var queue = new Queue<int>();
|
||||
queue.Enqueue(0);
|
||||
|
||||
while (queue.Count > 0)
|
||||
{
|
||||
// get current node:
|
||||
var node = nodes[queue.Dequeue()];
|
||||
|
||||
if (node.firstChild > -1)
|
||||
queue.Enqueue(node.firstChild + node.GetOctant(position));
|
||||
else
|
||||
return node.Sample(position);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user