浏览代码

moving files

/main
Lasse Jon Fuglsang Pedersen 4 年前
当前提交
f2e367df
共有 72 个文件被更改,包括 2525 次插入2489 次删除
  1. 912
      Editor/Utility/MeshLaplacian.cs
  2. 107
      Runtime/Utility/ArrayUtils.cs
  3. 93
      Runtime/Utility/Barycentric.cs
  4. 185
      Runtime/Utility/KdTree3Utils.cs
  5. 169
      Runtime/Utility/LinkedIndexList.cs
  6. 187
      Runtime/Utility/LinkedIndexListArray.cs
  7. 381
      Runtime/Utility/MeshAdjacency.cs
  8. 501
      Runtime/Utility/MeshBuffers.cs
  9. 189
      Runtime/Utility/MeshEdges.cs
  10. 89
      Runtime/Utility/MeshEx.cs
  11. 183
      Runtime/Utility/MeshInstanceBehaviour.cs
  12. 120
      Runtime/Utility/MeshIslands.cs
  13. 33
      Runtime/Utility/NativeMesh.cs
  14. 759
      Runtime/Utility/NativeMeshObjLoader.cs
  15. 47
      Runtime/Utility/UnsafeArrayBool.cs
  16. 47
      Runtime/Utility/UnsafeArrayFloat.cs
  17. 47
      Runtime/Utility/UnsafeArrayInt.cs
  18. 47
      Runtime/Utility/UnsafeArrayULong.cs
  19. 47
      Runtime/Utility/UnsafeArrayVector3.cs
  20. 113
      Runtime/Utility/UnsafeBFS.cs
  21. 109
      Runtime/Utility/UnsafeDFS.cs
  22. 622
      Runtime/Utility/KdTree3.cs
  23. 8
      Runtime/MeshTools.meta
  24. 12
      TODO.txt
  25. 7
      TODO.txt.meta
  26. 0
      /Editor/Utility.meta
  27. 0
      /Editor/Utility
  28. 0
      /Runtime/Utility/EditorUtilityProxy.cs
  29. 0
      /Runtime/Utility/EditorUtilityProxy.cs.meta
  30. 0
      /Runtime/Utility/ArrayUtils.cs
  31. 0
      /Runtime/Utility/ArrayUtils.cs.meta
  32. 0
      /Runtime/Utility/Barycentric.cs
  33. 0
      /Runtime/Utility/Barycentric.cs.meta
  34. 0
      /Runtime/Utility/KdTree3.cs.meta
  35. 0
      /Runtime/Utility/KdTree3Utils.cs
  36. 0
      /Runtime/Utility/KdTree3Utils.cs.meta
  37. 0
      /Runtime/Utility/LinkedIndexList.cs
  38. 0
      /Runtime/Utility/LinkedIndexList.cs.meta
  39. 0
      /Runtime/Utility/LinkedIndexListArray.cs
  40. 0
      /Runtime/Utility/LinkedIndexListArray.cs.meta
  41. 0
      /Runtime/Utility/MeshAdjacency.cs
  42. 0
      /Runtime/Utility/MeshAdjacency.cs.meta
  43. 0
      /Runtime/Utility/MeshBuffers.cs
  44. 0
      /Runtime/Utility/MeshBuffers.cs.meta
  45. 0
      /Runtime/Utility/MeshEdges.cs
  46. 0
      /Runtime/Utility/MeshEdges.cs.meta
  47. 0
      /Runtime/Utility/MeshEx.cs
  48. 0
      /Runtime/Utility/MeshEx.cs.meta
  49. 0
      /Runtime/Utility/MeshInstanceBehaviour.cs
  50. 0
      /Runtime/Utility/MeshInstanceBehaviour.cs.meta
  51. 0
      /Runtime/Utility/MeshIslands.cs
  52. 0
      /Runtime/Utility/MeshIslands.cs.meta
  53. 0
      /Runtime/Utility/NativeMesh.cs
  54. 0
      /Runtime/Utility/NativeMesh.cs.meta
  55. 0
      /Runtime/Utility/NativeMeshObjLoader.cs
  56. 0
      /Runtime/Utility/NativeMeshObjLoader.cs.meta
  57. 0
      /Runtime/Utility/UnsafeArrayBool.cs
  58. 0
      /Runtime/Utility/UnsafeArrayBool.cs.meta
  59. 0
      /Runtime/Utility/UnsafeArrayFloat.cs
  60. 0
      /Runtime/Utility/UnsafeArrayFloat.cs.meta
  61. 0
      /Runtime/Utility/UnsafeArrayInt.cs
  62. 0
      /Runtime/Utility/UnsafeArrayInt.cs.meta
  63. 0
      /Runtime/Utility/UnsafeArrayULong.cs
  64. 0
      /Runtime/Utility/UnsafeArrayULong.cs.meta
  65. 0
      /Runtime/Utility/UnsafeArrayVector3.cs
  66. 0
      /Runtime/Utility/UnsafeArrayVector3.cs.meta
  67. 0
      /Runtime/Utility/UnsafeBFS.cs
  68. 0
      /Runtime/Utility/UnsafeBFS.cs.meta
  69. 0
      /Runtime/Utility/UnsafeDFS.cs
  70. 0
      /Runtime/Utility/UnsafeDFS.cs.meta
  71. 0
      /Runtime/Utility/KdTree3.cs

912
Editor/Utility/MeshLaplacian.cs


using UnityEngine;
using UnityEngine.Profiling;
using Unity.Collections.LowLevel.Unsafe;
using Unity.DemoTeam.DigitalHuman;
public class MeshLaplacian
namespace Unity.DemoTeam.DigitalHuman
public int internalCount;
public double[] vertexDifferentialX;
public double[] vertexDifferentialY;
public double[] vertexDifferentialZ;
}
public class MeshLaplacian
{
public int internalCount;
public double[] vertexDifferentialX;
public double[] vertexDifferentialY;
public double[] vertexDifferentialZ;
}
public class MeshLaplacianTransform
{
public int vertexCount;
public class MeshLaplacianTransform
{
public int vertexCount;
public int[] constraintIndices;
public double constraintWeight;
public int[] constraintIndices;
public double constraintWeight;
public SparseMatrix Ls;
public SparseMatrix Lc;
public SparseMatrix LcT;
public SparseMatrix LcT_Lc;
public SparseCholesky LcT_Lc_chol;
public SparseMatrix Ls;
public SparseMatrix Lc;
public SparseMatrix LcT;
public SparseMatrix LcT_Lc;
public SparseCholesky LcT_Lc_chol;
public MeshLaplacianTransform(MeshAdjacency meshAdjacency, int[] constraintIndices)
{
BuildFrom(meshAdjacency, constraintIndices);
}
public MeshLaplacianTransform(MeshAdjacency meshAdjacency, int[] constraintIndices)
{
BuildFrom(meshAdjacency, constraintIndices);
}
public void BuildFrom(MeshAdjacency meshAdjacency, int[] constraintIndices)
{
vertexCount = meshAdjacency.vertexCount;
public void BuildFrom(MeshAdjacency meshAdjacency, int[] constraintIndices)
{
vertexCount = meshAdjacency.vertexCount;
this.constraintIndices = constraintIndices.Clone() as int[];
this.constraintWeight = 1.0;
this.constraintIndices = constraintIndices.Clone() as int[];
this.constraintWeight = 1.0;
// count unconstrained laplacian non-zero fields
int nzmax = vertexCount;
for (int i = 0; i != vertexCount; i++)
{
nzmax += meshAdjacency.vertexVertices.lists[i].size;
}
// count unconstrained laplacian non-zero fields
int nzmax = vertexCount;
for (int i = 0; i != vertexCount; i++)
{
nzmax += meshAdjacency.vertexVertices.lists[i].size;
}
// build Ls
EditorUtilityProxy.DisplayProgressBar("MeshLaplacian", "build Ls", 0.0f);
var Ls_storage = new CoordinateStorage<double>(vertexCount, vertexCount, nzmax);
for (int i = 0; i != vertexCount; i++)// D
{
//TODO proper fix
//Ls_storage.At(i, i, meshAdjacency.vertexVertices.lists[i].size);
Ls_storage.At(i, i, Mathf.Max(1, meshAdjacency.vertexVertices.lists[i].size));
}
for (int i = 0; i != vertexCount; i++)// A
{
foreach (var j in meshAdjacency.vertexVertices[i])
{
Ls_storage.At(i, j, -1.0);
}
}
Ls = Converter.ToCompressedColumnStorage(Ls_storage) as SparseMatrix;
// build Ls
EditorUtilityProxy.DisplayProgressBar("MeshLaplacian", "build Ls", 0.0f);
var Ls_storage = new CoordinateStorage<double>(vertexCount, vertexCount, nzmax);
for (int i = 0; i != vertexCount; i++)// D
{
//TODO proper fix
//Ls_storage.At(i, i, meshAdjacency.vertexVertices.lists[i].size);
Ls_storage.At(i, i, Mathf.Max(1, meshAdjacency.vertexVertices.lists[i].size));
}
for (int i = 0; i != vertexCount; i++)// A
{
foreach (var j in meshAdjacency.vertexVertices[i])
{
Ls_storage.At(i, j, -1.0);
}
}
Ls = Converter.ToCompressedColumnStorage(Ls_storage) as SparseMatrix;
// build Lc
EditorUtilityProxy.DisplayProgressBar("MeshLaplacian", "build Lc", 0.0f);
var Lc_storage = new CoordinateStorage<double>(vertexCount + constraintIndices.Length, vertexCount, nzmax + constraintIndices.Length);
for (int i = 0; i != vertexCount; i++)
{
//TODO proper fix
//Lc_storage.At(i, i, meshAdjacency.vertexVertices.lists[i].size);
Lc_storage.At(i, i, Mathf.Max(1, meshAdjacency.vertexVertices.lists[i].size));
}
for (int i = 0; i != vertexCount; i++)
{
foreach (var j in meshAdjacency.vertexVertices[i])
{
Lc_storage.At(i, j, -1.0);
}
}
for (int i = 0; i != constraintIndices.Length; i++)
{
Lc_storage.At(vertexCount + i, constraintIndices[i], constraintWeight);
}
Lc = Converter.ToCompressedColumnStorage(Lc_storage) as SparseMatrix;
// build Lc
EditorUtilityProxy.DisplayProgressBar("MeshLaplacian", "build Lc", 0.0f);
var Lc_storage = new CoordinateStorage<double>(vertexCount + constraintIndices.Length, vertexCount, nzmax + constraintIndices.Length);
for (int i = 0; i != vertexCount; i++)
{
//TODO proper fix
//Lc_storage.At(i, i, meshAdjacency.vertexVertices.lists[i].size);
Lc_storage.At(i, i, Mathf.Max(1, meshAdjacency.vertexVertices.lists[i].size));
}
for (int i = 0; i != vertexCount; i++)
{
foreach (var j in meshAdjacency.vertexVertices[i])
{
Lc_storage.At(i, j, -1.0);
}
}
for (int i = 0; i != constraintIndices.Length; i++)
{
Lc_storage.At(vertexCount + i, constraintIndices[i], constraintWeight);
}
Lc = Converter.ToCompressedColumnStorage(Lc_storage) as SparseMatrix;
// build LcT
EditorUtilityProxy.DisplayProgressBar("MeshLaplacian", "build LcT", 0.0f);
LcT = Lc.Transpose() as SparseMatrix;
// build LcT
EditorUtilityProxy.DisplayProgressBar("MeshLaplacian", "build LcT", 0.0f);
LcT = Lc.Transpose() as SparseMatrix;
// build LcT_Lc
EditorUtilityProxy.DisplayProgressBar("MeshLaplacian", "build LcT_Lc", 0.0f);
LcT_Lc = LcT.Multiply(Lc) as SparseMatrix;
// build LcT_Lc
EditorUtilityProxy.DisplayProgressBar("MeshLaplacian", "build LcT_Lc", 0.0f);
LcT_Lc = LcT.Multiply(Lc) as SparseMatrix;
// build LcT_Lc_chol
EditorUtilityProxy.DisplayProgressBar("MeshLaplacian", "build LcT_Lc_chol", 0.0f);
LcT_Lc_chol = SparseCholesky.Create(LcT_Lc, ColumnOrdering.MinimumDegreeAtPlusA);
// build LcT_Lc_chol
EditorUtilityProxy.DisplayProgressBar("MeshLaplacian", "build LcT_Lc_chol", 0.0f);
LcT_Lc_chol = SparseCholesky.Create(LcT_Lc, ColumnOrdering.MinimumDegreeAtPlusA);
// done
EditorUtilityProxy.ClearProgressBar();
}
// done
EditorUtilityProxy.ClearProgressBar();
}
public void ComputeMeshLaplacian(MeshLaplacian meshLaplacian, MeshBuffers meshBuffers)
{
Debug.Assert(vertexCount == meshBuffers.vertexCount);
public void ComputeMeshLaplacian(MeshLaplacian meshLaplacian, MeshBuffers meshBuffers)
{
Debug.Assert(vertexCount == meshBuffers.vertexCount);
// Ls x = diffcoords
unsafe
{
var vertexPositionX = new double[vertexCount];
var vertexPositionY = new double[vertexCount];
var vertexPositionZ = new double[vertexCount];
// Ls x = diffcoords
unsafe
{
var vertexPositionX = new double[vertexCount];
var vertexPositionY = new double[vertexCount];
var vertexPositionZ = new double[vertexCount];
fixed (Vector3* src = meshBuffers.vertexPositions)
fixed (double* dstX = vertexPositionX)
fixed (double* dstY = vertexPositionY)
fixed (double* dstZ = vertexPositionZ)
{
for (int i = 0; i != vertexCount; i++)
{
dstX[i] = src[i].x;
dstY[i] = src[i].y;
dstZ[i] = src[i].z;
}
}
fixed (Vector3* src = meshBuffers.vertexPositions)
fixed (double* dstX = vertexPositionX)
fixed (double* dstY = vertexPositionY)
fixed (double* dstZ = vertexPositionZ)
{
for (int i = 0; i != vertexCount; i++)
{
dstX[i] = src[i].x;
dstY[i] = src[i].y;
dstZ[i] = src[i].z;
}
}
ArrayUtils.ResizeCheckedIfLessThan(ref meshLaplacian.vertexDifferentialX, vertexCount);
ArrayUtils.ResizeCheckedIfLessThan(ref meshLaplacian.vertexDifferentialY, vertexCount);
ArrayUtils.ResizeCheckedIfLessThan(ref meshLaplacian.vertexDifferentialZ, vertexCount);
ArrayUtils.ResizeCheckedIfLessThan(ref meshLaplacian.vertexDifferentialX, vertexCount);
ArrayUtils.ResizeCheckedIfLessThan(ref meshLaplacian.vertexDifferentialY, vertexCount);
ArrayUtils.ResizeCheckedIfLessThan(ref meshLaplacian.vertexDifferentialZ, vertexCount);
Ls.Multiply(vertexPositionX, meshLaplacian.vertexDifferentialX);
Ls.Multiply(vertexPositionY, meshLaplacian.vertexDifferentialY);
Ls.Multiply(vertexPositionZ, meshLaplacian.vertexDifferentialZ);
Ls.Multiply(vertexPositionX, meshLaplacian.vertexDifferentialX);
Ls.Multiply(vertexPositionY, meshLaplacian.vertexDifferentialY);
Ls.Multiply(vertexPositionZ, meshLaplacian.vertexDifferentialZ);
meshLaplacian.internalCount = vertexCount;
}
}
meshLaplacian.internalCount = vertexCount;
}
}
public void ResolveMeshBuffers(MeshBuffers meshBuffers, MeshLaplacian meshLaplacian)
{
Debug.Assert(vertexCount == meshBuffers.vertexCount);
Debug.Assert(vertexCount == meshLaplacian.internalCount);
public void ResolveMeshBuffers(MeshBuffers meshBuffers, MeshLaplacian meshLaplacian)
{
Debug.Assert(vertexCount == meshBuffers.vertexCount);
Debug.Assert(vertexCount == meshLaplacian.internalCount);
int constraintCount = constraintIndices.Length;
int constraintCount = constraintIndices.Length;
// c = 'm' spatial constraints [c0 c1 ... cm]
// Lc = [Ls I|0] where dim(I) = m
// Lc x = [diffcoords c]
// x* = (Lc^T Lc)^-1 Lc^T [diffcoords c]
unsafe
{
var constrainedDifferentialX = new double[vertexCount + constraintCount];
var constrainedDifferentialY = new double[vertexCount + constraintCount];
var constrainedDifferentialZ = new double[vertexCount + constraintCount];
// c = 'm' spatial constraints [c0 c1 ... cm]
// Lc = [Ls I|0] where dim(I) = m
// Lc x = [diffcoords c]
// x* = (Lc^T Lc)^-1 Lc^T [diffcoords c]
unsafe
{
var constrainedDifferentialX = new double[vertexCount + constraintCount];
var constrainedDifferentialY = new double[vertexCount + constraintCount];
var constrainedDifferentialZ = new double[vertexCount + constraintCount];
fixed (double* srcX = meshLaplacian.vertexDifferentialX)
fixed (double* srcY = meshLaplacian.vertexDifferentialY)
fixed (double* srcZ = meshLaplacian.vertexDifferentialZ)
fixed (double* dstX = constrainedDifferentialX)
fixed (double* dstY = constrainedDifferentialY)
fixed (double* dstZ = constrainedDifferentialZ)
{
UnsafeUtility.MemCpy(dstX, srcX, sizeof(double) * vertexCount);
UnsafeUtility.MemCpy(dstY, srcY, sizeof(double) * vertexCount);
UnsafeUtility.MemCpy(dstZ, srcZ, sizeof(double) * vertexCount);
fixed (double* srcX = meshLaplacian.vertexDifferentialX)
fixed (double* srcY = meshLaplacian.vertexDifferentialY)
fixed (double* srcZ = meshLaplacian.vertexDifferentialZ)
fixed (double* dstX = constrainedDifferentialX)
fixed (double* dstY = constrainedDifferentialY)
fixed (double* dstZ = constrainedDifferentialZ)
{
UnsafeUtility.MemCpy(dstX, srcX, sizeof(double) * vertexCount);
UnsafeUtility.MemCpy(dstY, srcY, sizeof(double) * vertexCount);
UnsafeUtility.MemCpy(dstZ, srcZ, sizeof(double) * vertexCount);
for (int k = 0; k != constraintCount; k++)
{
int j = constraintIndices[k];
dstX[vertexCount + k] = constraintWeight * meshBuffers.vertexPositions[j].x;
dstY[vertexCount + k] = constraintWeight * meshBuffers.vertexPositions[j].y;
dstZ[vertexCount + k] = constraintWeight * meshBuffers.vertexPositions[j].z;
}
}
for (int k = 0; k != constraintCount; k++)
{
int j = constraintIndices[k];
dstX[vertexCount + k] = constraintWeight * meshBuffers.vertexPositions[j].x;
dstY[vertexCount + k] = constraintWeight * meshBuffers.vertexPositions[j].y;
dstZ[vertexCount + k] = constraintWeight * meshBuffers.vertexPositions[j].z;
}
}
var LcT_constrainedDifferentialX = new double[vertexCount + constraintCount];
var LcT_constrainedDifferentialY = new double[vertexCount + constraintCount];
var LcT_constrainedDifferentialZ = new double[vertexCount + constraintCount];
var LcT_constrainedDifferentialX = new double[vertexCount + constraintCount];
var LcT_constrainedDifferentialY = new double[vertexCount + constraintCount];
var LcT_constrainedDifferentialZ = new double[vertexCount + constraintCount];
LcT.Multiply(constrainedDifferentialX, LcT_constrainedDifferentialX);
LcT.Multiply(constrainedDifferentialY, LcT_constrainedDifferentialY);
LcT.Multiply(constrainedDifferentialZ, LcT_constrainedDifferentialZ);
LcT.Multiply(constrainedDifferentialX, LcT_constrainedDifferentialX);
LcT.Multiply(constrainedDifferentialY, LcT_constrainedDifferentialY);
LcT.Multiply(constrainedDifferentialZ, LcT_constrainedDifferentialZ);
var resultPositionX = new double[vertexCount + constraintCount];
var resultPositionY = new double[vertexCount + constraintCount];
var resultPositionZ = new double[vertexCount + constraintCount];
var resultPositionX = new double[vertexCount + constraintCount];
var resultPositionY = new double[vertexCount + constraintCount];
var resultPositionZ = new double[vertexCount + constraintCount];
Profiler.BeginSample("chol-solve");
LcT_Lc_chol.Solve(LcT_constrainedDifferentialX, resultPositionX);
LcT_Lc_chol.Solve(LcT_constrainedDifferentialY, resultPositionY);
LcT_Lc_chol.Solve(LcT_constrainedDifferentialZ, resultPositionZ);
Profiler.EndSample();
Profiler.BeginSample("chol-solve");
LcT_Lc_chol.Solve(LcT_constrainedDifferentialX, resultPositionX);
LcT_Lc_chol.Solve(LcT_constrainedDifferentialY, resultPositionY);
LcT_Lc_chol.Solve(LcT_constrainedDifferentialZ, resultPositionZ);
Profiler.EndSample();
fixed (double* srcX = resultPositionX)
fixed (double* srcY = resultPositionY)
fixed (double* srcZ = resultPositionZ)
fixed (float* dstX = &meshBuffers.vertexPositions[0].x)
fixed (float* dstY = &meshBuffers.vertexPositions[0].y)
fixed (float* dstZ = &meshBuffers.vertexPositions[0].z)
{
const int dstStride = 3;// sizeof(Vector3) / sizeof(float)
for (int i = 0; i != vertexCount; i++)
dstX[i * dstStride] = (float)srcX[i];
for (int i = 0; i != vertexCount; i++)
dstY[i * dstStride] = (float)srcY[i];
for (int i = 0; i != vertexCount; i++)
dstZ[i * dstStride] = (float)srcZ[i];
}
}
}
}
fixed (double* srcX = resultPositionX)
fixed (double* srcY = resultPositionY)
fixed (double* srcZ = resultPositionZ)
fixed (float* dstX = &meshBuffers.vertexPositions[0].x)
fixed (float* dstY = &meshBuffers.vertexPositions[0].y)
fixed (float* dstZ = &meshBuffers.vertexPositions[0].z)
{
const int dstStride = 3;// sizeof(Vector3) / sizeof(float)
for (int i = 0; i != vertexCount; i++)
dstX[i * dstStride] = (float)srcX[i];
for (int i = 0; i != vertexCount; i++)
dstY[i * dstStride] = (float)srcY[i];
for (int i = 0; i != vertexCount; i++)
dstZ[i * dstStride] = (float)srcZ[i];
}
}
}
}
public class MeshLaplacianTransformROI
{
public int internalCount;
public int externalCount;
public class MeshLaplacianTransformROI
{
public int internalCount;
public int externalCount;
public int[] internalFromExternal;// [0..mesh.vertexCount]
public int[] externalFromInternal;// [0..internalCount]
public int[] internalFromExternal;// [0..mesh.vertexCount]
public int[] externalFromInternal;// [0..internalCount]
public int[] constraintIndices;
public double constraintWeight;
public int[] constraintIndices;
public double constraintWeight;
public SparseMatrix Ls;
public SparseMatrix Lc;
public SparseMatrix LcT;
public SparseMatrix LcT_Lc;
public SparseCholesky LcT_Lc_chol;
public SparseMatrix Ls;
public SparseMatrix Lc;
public SparseMatrix LcT;
public SparseMatrix LcT_Lc;
public SparseCholesky LcT_Lc_chol;
private int InternalValence(MeshAdjacency meshAdjacency, int i)
{
int n = 0;
foreach (var k in meshAdjacency.vertexVertices[externalFromInternal[i]])
{
if (internalFromExternal[k] != -1)
n++;
}
return n;
}
private int InternalValence(MeshAdjacency meshAdjacency, int i)
{
int n = 0;
foreach (var k in meshAdjacency.vertexVertices[externalFromInternal[i]])
{
if (internalFromExternal[k] != -1)
n++;
}
return n;
}
public MeshLaplacianTransformROI(MeshAdjacency meshAdjacency, int[] roiIndices, int roiConstraintBoundary, int[] roiConstraintIndices = null)
{
BuildFrom(meshAdjacency, roiIndices, roiConstraintBoundary, roiConstraintIndices);
}
public MeshLaplacianTransformROI(MeshAdjacency meshAdjacency, int[] roiIndices, int roiConstraintBoundary, int[] roiConstraintIndices = null)
{
BuildFrom(meshAdjacency, roiIndices, roiConstraintBoundary, roiConstraintIndices);
}
public void BuildFrom(MeshAdjacency meshAdjacency, int[] roiIndices, int roiBoundaryLevels, int[] roiConstraintIndices = null)
{
unsafe
{
using (var visited = new UnsafeArrayBool(meshAdjacency.vertexCount))
using (var visitedBoundary = new UnsafeArrayBool(meshAdjacency.vertexCount))
using (var visitor = new UnsafeBFS(meshAdjacency.vertexCount))
{
// find boundary
visited.Clear(false);
visitedBoundary.Clear(false);
visitor.Clear();
public void BuildFrom(MeshAdjacency meshAdjacency, int[] roiIndices, int roiBoundaryLevels, int[] roiConstraintIndices = null)
{
unsafe
{
using (var visited = new UnsafeArrayBool(meshAdjacency.vertexCount))
using (var visitedBoundary = new UnsafeArrayBool(meshAdjacency.vertexCount))
using (var visitor = new UnsafeBFS(meshAdjacency.vertexCount))
{
// find boundary
visited.Clear(false);
visitedBoundary.Clear(false);
visitor.Clear();
int visitedCount = 0;
int visitedBoundaryCount = 0;
int visitedCount = 0;
int visitedBoundaryCount = 0;
foreach (int i in roiIndices)
{
visited.val[i] = true;
visitedCount++;
visitor.Ignore(i);
}
foreach (int i in roiIndices)
{
visited.val[i] = true;
visitedCount++;
visitor.Ignore(i);
}
foreach (int i in roiIndices)
{
foreach (var j in meshAdjacency.vertexVertices[i])
{
visitor.Insert(j);
}
}
foreach (int i in roiIndices)
{
foreach (var j in meshAdjacency.vertexVertices[i])
{
visitor.Insert(j);
}
}
// step boundary
while (visitor.MoveNext())
{
int i = visitor.position;
// step boundary
while (visitor.MoveNext())
{
int i = visitor.position;
visited.val[i] = true;
visitedCount++;
visitedBoundary.val[i] = true;
visitedBoundaryCount++;
visited.val[i] = true;
visitedCount++;
visitedBoundary.val[i] = true;
visitedBoundaryCount++;
if (visitor.depth < roiBoundaryLevels)
{
foreach (var j in meshAdjacency.vertexVertices[i])
{
visitor.Insert(j);
}
}
}
if (visitor.depth < roiBoundaryLevels)
{
foreach (var j in meshAdjacency.vertexVertices[i])
{
visitor.Insert(j);
}
}
}
// add constraints
if (roiConstraintIndices != null)
{
foreach (int i in roiConstraintIndices)
{
if (visited.val[i])
{
if (visitedBoundary.val[i] == false)
{
visitedBoundary.val[i] = true;
visitedBoundaryCount++;
}
}
else
{
Debug.LogWarning("ignoring user constraint outside ROI: vertex " + i);
}
}
}
// add constraints
if (roiConstraintIndices != null)
{
foreach (int i in roiConstraintIndices)
{
if (visited.val[i])
{
if (visitedBoundary.val[i] == false)
{
visitedBoundary.val[i] = true;
visitedBoundaryCount++;
}
}
else
{
Debug.LogWarning("ignoring user constraint outside ROI: vertex " + i);
}
}
}
// build translations
internalCount = 0;
externalCount = meshAdjacency.vertexCount;
// build translations
internalCount = 0;
externalCount = meshAdjacency.vertexCount;
internalFromExternal = new int[externalCount];
externalFromInternal = new int[visitedCount];
internalFromExternal = new int[externalCount];
externalFromInternal = new int[visitedCount];
for (int i = 0; i != meshAdjacency.vertexCount; i++)
{
if (visited.val[i])
{
int internalIndex = internalCount++;
externalFromInternal[internalIndex] = i;
internalFromExternal[i] = internalIndex;
}
else
{
internalFromExternal[i] = -1;
}
}
for (int i = 0; i != meshAdjacency.vertexCount; i++)
{
if (visited.val[i])
{
int internalIndex = internalCount++;
externalFromInternal[internalIndex] = i;
internalFromExternal[i] = internalIndex;
}
else
{
internalFromExternal[i] = -1;
}
}
// find constraint indices
constraintIndices = new int[visitedBoundaryCount];
constraintWeight = 1.0;
// find constraint indices
constraintIndices = new int[visitedBoundaryCount];
constraintWeight = 1.0;
int constraintCount = 0;
for (int i = 0; i != internalCount; i++)
{
if (visitedBoundary.val[externalFromInternal[i]])
{
constraintIndices[constraintCount++] = i;
}
}
int constraintCount = 0;
for (int i = 0; i != internalCount; i++)
{
if (visitedBoundary.val[externalFromInternal[i]])
{
constraintIndices[constraintCount++] = i;
}
}
// count unconstrained laplacian non-zero fields
int nzmax = internalCount;
for (int i = 0; i != internalCount; i++)
{
nzmax += InternalValence(meshAdjacency, i);
}
// count unconstrained laplacian non-zero fields
int nzmax = internalCount;
for (int i = 0; i != internalCount; i++)
{
nzmax += InternalValence(meshAdjacency, i);
}
// build Ls
EditorUtilityProxy.DisplayProgressBar("MeshLaplacian", "build Ls", 0.0f);
var Ls_storage = new CoordinateStorage<double>(internalCount, internalCount, nzmax);
for (int i = 0; i != internalCount; i++)// D
{
//TODO proper fix
//Ls_storage.At(i, i, InternalValence(meshAdjacency, i));
Ls_storage.At(i, i, Mathf.Max(1, InternalValence(meshAdjacency, i)));
}
for (int i = 0; i != internalCount; i++)// A
{
foreach (var k in meshAdjacency.vertexVertices[externalFromInternal[i]])
{
int j = internalFromExternal[k];
if (j != -1)
{
Ls_storage.At(i, j, -1.0);
}
}
}
Ls = Converter.ToCompressedColumnStorage(Ls_storage) as SparseMatrix;
// build Ls
EditorUtilityProxy.DisplayProgressBar("MeshLaplacian", "build Ls", 0.0f);
var Ls_storage = new CoordinateStorage<double>(internalCount, internalCount, nzmax);
for (int i = 0; i != internalCount; i++)// D
{
//TODO proper fix
//Ls_storage.At(i, i, InternalValence(meshAdjacency, i));
Ls_storage.At(i, i, Mathf.Max(1, InternalValence(meshAdjacency, i)));
}
for (int i = 0; i != internalCount; i++)// A
{
foreach (var k in meshAdjacency.vertexVertices[externalFromInternal[i]])
{
int j = internalFromExternal[k];
if (j != -1)
{
Ls_storage.At(i, j, -1.0);
}
}
}
Ls = Converter.ToCompressedColumnStorage(Ls_storage) as SparseMatrix;
// build Lc
EditorUtilityProxy.DisplayProgressBar("MeshLaplacian", "build Lc", 0.0f);
var Lc_storage = new CoordinateStorage<double>(internalCount + constraintCount, internalCount, nzmax + constraintCount);
for (int i = 0; i != internalCount; i++)
{
//TODO proper fix
//Lc_storage.At(i, i, InternalValence(meshAdjacency, i));
Lc_storage.At(i, i, Mathf.Max(1, InternalValence(meshAdjacency, i)));
}
for (int i = 0; i != internalCount; i++)
{
foreach (var k in meshAdjacency.vertexVertices[externalFromInternal[i]])
{
int j = internalFromExternal[k];
if (j != -1)
{
Lc_storage.At(i, j, -1.0);
}
}
}
for (int i = 0; i != constraintIndices.Length; i++)
{
Lc_storage.At(internalCount + i, constraintIndices[i], constraintWeight);
}
Lc = Converter.ToCompressedColumnStorage(Lc_storage) as SparseMatrix;
// build Lc
EditorUtilityProxy.DisplayProgressBar("MeshLaplacian", "build Lc", 0.0f);
var Lc_storage = new CoordinateStorage<double>(internalCount + constraintCount, internalCount, nzmax + constraintCount);
for (int i = 0; i != internalCount; i++)
{
//TODO proper fix
//Lc_storage.At(i, i, InternalValence(meshAdjacency, i));
Lc_storage.At(i, i, Mathf.Max(1, InternalValence(meshAdjacency, i)));
}
for (int i = 0; i != internalCount; i++)
{
foreach (var k in meshAdjacency.vertexVertices[externalFromInternal[i]])
{
int j = internalFromExternal[k];
if (j != -1)
{
Lc_storage.At(i, j, -1.0);
}
}
}
for (int i = 0; i != constraintIndices.Length; i++)
{
Lc_storage.At(internalCount + i, constraintIndices[i], constraintWeight);
}
Lc = Converter.ToCompressedColumnStorage(Lc_storage) as SparseMatrix;
// build LcT
EditorUtilityProxy.DisplayProgressBar("MeshLaplacian", "build LcT", 0.0f);
LcT = Lc.Transpose() as SparseMatrix;
// build LcT
EditorUtilityProxy.DisplayProgressBar("MeshLaplacian", "build LcT", 0.0f);
LcT = Lc.Transpose() as SparseMatrix;
// build LcT_Lc
EditorUtilityProxy.DisplayProgressBar("MeshLaplacian", "build LcT_Lc", 0.0f);
LcT_Lc = LcT.Multiply(Lc) as SparseMatrix;
// build LcT_Lc
EditorUtilityProxy.DisplayProgressBar("MeshLaplacian", "build LcT_Lc", 0.0f);
LcT_Lc = LcT.Multiply(Lc) as SparseMatrix;
// build LcT_Lc_chol
EditorUtilityProxy.DisplayProgressBar("MeshLaplacian", "build LcT_Lc_chol", 0.0f);
LcT_Lc_chol = SparseCholesky.Create(LcT_Lc, ColumnOrdering.MinimumDegreeAtPlusA);
// build LcT_Lc_chol
EditorUtilityProxy.DisplayProgressBar("MeshLaplacian", "build LcT_Lc_chol", 0.0f);
LcT_Lc_chol = SparseCholesky.Create(LcT_Lc, ColumnOrdering.MinimumDegreeAtPlusA);
// done
EditorUtilityProxy.ClearProgressBar();
}
}
}
// done
EditorUtilityProxy.ClearProgressBar();
}
}
}
public void ComputeMeshLaplacian(MeshLaplacian meshLaplacian, MeshBuffers meshBuffers)
{
Debug.Assert(externalCount == meshBuffers.vertexCount);
public void ComputeMeshLaplacian(MeshLaplacian meshLaplacian, MeshBuffers meshBuffers)
{
Debug.Assert(externalCount == meshBuffers.vertexCount);
// Ls x = diffcoords
unsafe
{
var vertexPositionX = new double[internalCount];
var vertexPositionY = new double[internalCount];
var vertexPositionZ = new double[internalCount];
// Ls x = diffcoords
unsafe
{
var vertexPositionX = new double[internalCount];
var vertexPositionY = new double[internalCount];
var vertexPositionZ = new double[internalCount];
fixed (Vector3* src = meshBuffers.vertexPositions)
fixed (double* dstX = vertexPositionX)
fixed (double* dstY = vertexPositionY)
fixed (double* dstZ = vertexPositionZ)
{
for (int i = 0; i != internalCount; i++)
{
int k = externalFromInternal[i];
dstX[i] = src[k].x;
dstY[i] = src[k].y;
dstZ[i] = src[k].z;
}
}
fixed (Vector3* src = meshBuffers.vertexPositions)
fixed (double* dstX = vertexPositionX)
fixed (double* dstY = vertexPositionY)
fixed (double* dstZ = vertexPositionZ)
{
for (int i = 0; i != internalCount; i++)
{
int k = externalFromInternal[i];
dstX[i] = src[k].x;
dstY[i] = src[k].y;
dstZ[i] = src[k].z;
}
}
ArrayUtils.ResizeCheckedIfLessThan(ref meshLaplacian.vertexDifferentialX, internalCount);
ArrayUtils.ResizeCheckedIfLessThan(ref meshLaplacian.vertexDifferentialY, internalCount);
ArrayUtils.ResizeCheckedIfLessThan(ref meshLaplacian.vertexDifferentialZ, internalCount);
ArrayUtils.ResizeCheckedIfLessThan(ref meshLaplacian.vertexDifferentialX, internalCount);
ArrayUtils.ResizeCheckedIfLessThan(ref meshLaplacian.vertexDifferentialY, internalCount);
ArrayUtils.ResizeCheckedIfLessThan(ref meshLaplacian.vertexDifferentialZ, internalCount);
Ls.Multiply(vertexPositionX, meshLaplacian.vertexDifferentialX);
Ls.Multiply(vertexPositionY, meshLaplacian.vertexDifferentialY);
Ls.Multiply(vertexPositionZ, meshLaplacian.vertexDifferentialZ);
Ls.Multiply(vertexPositionX, meshLaplacian.vertexDifferentialX);
Ls.Multiply(vertexPositionY, meshLaplacian.vertexDifferentialY);
Ls.Multiply(vertexPositionZ, meshLaplacian.vertexDifferentialZ);
meshLaplacian.internalCount = internalCount;
}
}
meshLaplacian.internalCount = internalCount;
}
}
public void ResolveMeshBuffers(MeshBuffers meshBuffers, MeshLaplacian meshLaplacian)
{
Debug.Assert(externalCount == meshBuffers.vertexCount);
Debug.Assert(internalCount == meshLaplacian.internalCount);
public void ResolveMeshBuffers(MeshBuffers meshBuffers, MeshLaplacian meshLaplacian)
{
Debug.Assert(externalCount == meshBuffers.vertexCount);
Debug.Assert(internalCount == meshLaplacian.internalCount);
int constraintCount = constraintIndices.Length;
int constraintCount = constraintIndices.Length;
// c = 'm' spatial constraints [c0 c1 ... cm]
// Lc = [Ls I|0] where dim(I) = m
// Lc x = [diffcoords c]
// x* = (Lc^T Lc)^-1 Lc^T [diffcoords c]
unsafe
{
var constrainedDifferentialX = new double[internalCount + constraintCount];
var constrainedDifferentialY = new double[internalCount + constraintCount];
var constrainedDifferentialZ = new double[internalCount + constraintCount];
// c = 'm' spatial constraints [c0 c1 ... cm]
// Lc = [Ls I|0] where dim(I) = m
// Lc x = [diffcoords c]
// x* = (Lc^T Lc)^-1 Lc^T [diffcoords c]
unsafe
{
var constrainedDifferentialX = new double[internalCount + constraintCount];
var constrainedDifferentialY = new double[internalCount + constraintCount];
var constrainedDifferentialZ = new double[internalCount + constraintCount];
fixed (double* srcX = meshLaplacian.vertexDifferentialX)
fixed (double* srcY = meshLaplacian.vertexDifferentialY)
fixed (double* srcZ = meshLaplacian.vertexDifferentialZ)
fixed (double* dstX = constrainedDifferentialX)
fixed (double* dstY = constrainedDifferentialY)
fixed (double* dstZ = constrainedDifferentialZ)
{
UnsafeUtility.MemCpy(dstX, srcX, sizeof(double) * internalCount);
UnsafeUtility.MemCpy(dstY, srcY, sizeof(double) * internalCount);
UnsafeUtility.MemCpy(dstZ, srcZ, sizeof(double) * internalCount);
fixed (double* srcX = meshLaplacian.vertexDifferentialX)
fixed (double* srcY = meshLaplacian.vertexDifferentialY)
fixed (double* srcZ = meshLaplacian.vertexDifferentialZ)
fixed (double* dstX = constrainedDifferentialX)
fixed (double* dstY = constrainedDifferentialY)
fixed (double* dstZ = constrainedDifferentialZ)
{
UnsafeUtility.MemCpy(dstX, srcX, sizeof(double) * internalCount);
UnsafeUtility.MemCpy(dstY, srcY, sizeof(double) * internalCount);
UnsafeUtility.MemCpy(dstZ, srcZ, sizeof(double) * internalCount);
for (int i = 0; i != constraintCount; i++)
{
int k = externalFromInternal[constraintIndices[i]];
dstX[internalCount + i] = constraintWeight * meshBuffers.vertexPositions[k].x;
dstY[internalCount + i] = constraintWeight * meshBuffers.vertexPositions[k].y;
dstZ[internalCount + i] = constraintWeight * meshBuffers.vertexPositions[k].z;
}
}
for (int i = 0; i != constraintCount; i++)
{
int k = externalFromInternal[constraintIndices[i]];
dstX[internalCount + i] = constraintWeight * meshBuffers.vertexPositions[k].x;
dstY[internalCount + i] = constraintWeight * meshBuffers.vertexPositions[k].y;
dstZ[internalCount + i] = constraintWeight * meshBuffers.vertexPositions[k].z;
}
}
var LcT_constrainedDifferentialX = new double[internalCount + constraintCount];
var LcT_constrainedDifferentialY = new double[internalCount + constraintCount];
var LcT_constrainedDifferentialZ = new double[internalCount + constraintCount];
var LcT_constrainedDifferentialX = new double[internalCount + constraintCount];
var LcT_constrainedDifferentialY = new double[internalCount + constraintCount];
var LcT_constrainedDifferentialZ = new double[internalCount + constraintCount];
LcT.Multiply(constrainedDifferentialX, LcT_constrainedDifferentialX);
LcT.Multiply(constrainedDifferentialY, LcT_constrainedDifferentialY);
LcT.Multiply(constrainedDifferentialZ, LcT_constrainedDifferentialZ);
LcT.Multiply(constrainedDifferentialX, LcT_constrainedDifferentialX);
LcT.Multiply(constrainedDifferentialY, LcT_constrainedDifferentialY);
LcT.Multiply(constrainedDifferentialZ, LcT_constrainedDifferentialZ);
var resultPositionX = new double[internalCount + constraintCount];
var resultPositionY = new double[internalCount + constraintCount];
var resultPositionZ = new double[internalCount + constraintCount];
var resultPositionX = new double[internalCount + constraintCount];
var resultPositionY = new double[internalCount + constraintCount];
var resultPositionZ = new double[internalCount + constraintCount];
Profiler.BeginSample("chol-solve");
LcT_Lc_chol.Solve(LcT_constrainedDifferentialX, resultPositionX);
LcT_Lc_chol.Solve(LcT_constrainedDifferentialY, resultPositionY);
LcT_Lc_chol.Solve(LcT_constrainedDifferentialZ, resultPositionZ);
Profiler.EndSample();
Profiler.BeginSample("chol-solve");
LcT_Lc_chol.Solve(LcT_constrainedDifferentialX, resultPositionX);
LcT_Lc_chol.Solve(LcT_constrainedDifferentialY, resultPositionY);
LcT_Lc_chol.Solve(LcT_constrainedDifferentialZ, resultPositionZ);
Profiler.EndSample();
fixed (double* srcX = resultPositionX)
fixed (double* srcY = resultPositionY)
fixed (double* srcZ = resultPositionZ)
fixed (float* dstX = &meshBuffers.vertexPositions[0].x)
fixed (float* dstY = &meshBuffers.vertexPositions[0].y)
fixed (float* dstZ = &meshBuffers.vertexPositions[0].z)
{
const int dstStride = 3;// sizeof(Vector3) / sizeof(float)
for (int i = 0; i != internalCount; i++)
{
int k = externalFromInternal[i];
dstX[k * dstStride] = (float)srcX[i];
dstY[k * dstStride] = (float)srcY[i];
dstZ[k * dstStride] = (float)srcZ[i];
}
}
}
}
fixed (double* srcX = resultPositionX)
fixed (double* srcY = resultPositionY)
fixed (double* srcZ = resultPositionZ)
fixed (float* dstX = &meshBuffers.vertexPositions[0].x)
fixed (float* dstY = &meshBuffers.vertexPositions[0].y)
fixed (float* dstZ = &meshBuffers.vertexPositions[0].z)
{
const int dstStride = 3;// sizeof(Vector3) / sizeof(float)
for (int i = 0; i != internalCount; i++)
{
int k = externalFromInternal[i];
dstX[k * dstStride] = (float)srcX[i];
dstY[k * dstStride] = (float)srcY[i];
dstZ[k * dstStride] = (float)srcZ[i];
}
}
}
}
}
}

107
Runtime/Utility/ArrayUtils.cs


using Unity.Collections;
using Unity.Mathematics;
public static class ArrayUtils
namespace Unity.DemoTeam.DigitalHuman
//PACKAGETODO remove begin
public static void ResizeChecked<T>(ref T[] array, int length)
{
if (array == null)
array = new T[length];
if (array.Length != length)
System.Array.Resize(ref array, length);
}
public static class ArrayUtils
{
public static void ResizeChecked<T>(ref T[] array, int length)
{
if (array == null)
array = new T[length];
if (array.Length != length)
System.Array.Resize(ref array, length);
}
public static void ResizeCheckedIfLessThan<T>(ref T[] array, int length)
{
if (array == null)
array = new T[length];
if (array.Length < length)
System.Array.Resize(ref array, length);
}
public static void ResizeCheckedIfLessThan<T>(ref T[] array, int length)
{
if (array == null)
array = new T[length];
if (array.Length < length)
System.Array.Resize(ref array, length);
}
public static void CopyChecked<T>(T[] arraySrc, ref T[] arrayDst, int length)
{
ResizeCheckedIfLessThan(ref arrayDst, length);
System.Array.Copy(arraySrc, arrayDst, length);
}
public static void CopyChecked<T>(T[] arraySrc, ref T[] arrayDst, int length)
{
ResizeCheckedIfLessThan(ref arrayDst, length);
System.Array.Copy(arraySrc, arrayDst, length);
}
public static void ClearChecked<T>(T[] array)
{
if (array != null)
System.Array.Clear(array, 0, array.Length);
}
//PACKAGETODO remove end
public static void ClearChecked<T>(T[] array)
{
if (array != null)
System.Array.Clear(array, 0, array.Length);
}
public static void Realloc<T>(ref NativeArray<T> array, int length, Allocator allocator = Allocator.Persistent) where T : struct
{
NativeArray<T> dst = new NativeArray<T>(length, allocator, NativeArrayOptions.UninitializedMemory);
NativeArray<T>.Copy(array, dst, math.min(array.Length, length));
array.Dispose();
array = dst;
}
public static void Realloc<T>(ref NativeArray<T> array, int length, Allocator allocator = Allocator.Persistent) where T : struct
{
NativeArray<T> dst = new NativeArray<T>(length, allocator, NativeArrayOptions.UninitializedMemory);
NativeArray<T>.Copy(array, dst, math.min(array.Length, length));
array.Dispose();
array = dst;
}
public static void ReallocChecked<T>(ref NativeArray<T> array, int length, Allocator allocator = Allocator.Persistent) where T : struct
{
if (array.IsCreated == false)
array = new NativeArray<T>(length, allocator, NativeArrayOptions.UninitializedMemory);
if (array.Length != length)
Realloc(ref array, length, allocator);
}
public static void ReallocChecked<T>(ref NativeArray<T> array, int length, Allocator allocator = Allocator.Persistent) where T : struct
{
if (array.IsCreated == false)
array = new NativeArray<T>(length, allocator, NativeArrayOptions.UninitializedMemory);
if (array.Length != length)
Realloc(ref array, length, allocator);
}
public static void ReallocCheckedIfLessThan<T>(ref NativeArray<T> array, int length, Allocator allocator = Allocator.Persistent) where T : struct
{
if (array.IsCreated == false)
array = new NativeArray<T>(length, allocator, NativeArrayOptions.UninitializedMemory);
if (array.Length < length)
Realloc(ref array, length, allocator);
}
public static void ReallocCheckedIfLessThan<T>(ref NativeArray<T> array, int length, Allocator allocator = Allocator.Persistent) where T : struct
{
if (array.IsCreated == false)
array = new NativeArray<T>(length, allocator, NativeArrayOptions.UninitializedMemory);
if (array.Length < length)
Realloc(ref array, length, allocator);
}
public static void CopyChecked<T>(in NativeArray<T> arraySrc, ref NativeArray<T> arrayDst, Allocator allocator = Allocator.Persistent) where T : struct
{
ReallocCheckedIfLessThan(ref arrayDst, arraySrc.Length, allocator);
NativeArray<T>.Copy(arraySrc, arrayDst);
}
public static void CopyChecked<T>(in NativeArray<T> arraySrc, ref NativeArray<T> arrayDst, Allocator allocator = Allocator.Persistent) where T : struct
{
ReallocCheckedIfLessThan(ref arrayDst, arraySrc.Length, allocator);
NativeArray<T>.Copy(arraySrc, arrayDst);
}
}
}

93
Runtime/Utility/Barycentric.cs


using System;
using UnityEngine;
[Serializable]
public struct Barycentric
namespace Unity.DemoTeam.DigitalHuman
public float u;
public float v;
public float w;
[Serializable]
public struct Barycentric
{
public float u;
public float v;
public float w;
public Barycentric(ref Vector3 q, ref Vector3 a, ref Vector3 b, ref Vector3 c)
{
// compute (u, v, w) for point q in plane spanned by triangle (a, b, c)
// https://gamedev.stackexchange.com/a/23745
//Vector3 v0 = b - a;
float x0 = b.x - a.x;
float y0 = b.y - a.y;
float z0 = b.z - a.z;
//Vector3 v1 = c - a;
float x1 = c.x - a.x;
float y1 = c.y - a.y;
float z1 = c.z - a.z;
//Vector3 v2 = q - a;
float x2 = q.x - a.x;
float y2 = q.y - a.y;
float z2 = q.z - a.z;
public Barycentric(ref Vector3 q, ref Vector3 a, ref Vector3 b, ref Vector3 c)
{
// compute (u, v, w) for point q in plane spanned by triangle (a, b, c)
// https://gamedev.stackexchange.com/a/23745
//Vector3 v0 = b - a;
float x0 = b.x - a.x;
float y0 = b.y - a.y;
float z0 = b.z - a.z;
//Vector3 v1 = c - a;
float x1 = c.x - a.x;
float y1 = c.y - a.y;
float z1 = c.z - a.z;
//Vector3 v2 = q - a;
float x2 = q.x - a.x;
float y2 = q.y - a.y;
float z2 = q.z - a.z;
float d00 = x0 * x0 + y0 * y0 + z0 * z0;//Vector3.Dot(v0, v0);
float d01 = x0 * x1 + y0 * y1 + z0 * z1;//Vector3.Dot(v0, v1);
float d11 = x1 * x1 + y1 * y1 + z1 * z1;//Vector3.Dot(v1, v1);
float d20 = x2 * x0 + y2 * y0 + z2 * z0;//Vector3.Dot(v2, v0);
float d21 = x2 * x1 + y2 * y1 + z2 * z1;//Vector3.Dot(v2, v1);
float d00 = x0 * x0 + y0 * y0 + z0 * z0;//Vector3.Dot(v0, v0);
float d01 = x0 * x1 + y0 * y1 + z0 * z1;//Vector3.Dot(v0, v1);
float d11 = x1 * x1 + y1 * y1 + z1 * z1;//Vector3.Dot(v1, v1);
float d20 = x2 * x0 + y2 * y0 + z2 * z0;//Vector3.Dot(v2, v0);
float d21 = x2 * x1 + y2 * y1 + z2 * z1;//Vector3.Dot(v2, v1);
float denom = d00 * d11 - d01 * d01;
v = (d11 * d20 - d01 * d21) / denom;
w = (d00 * d21 - d01 * d20) / denom;
u = 1.0f - v - w;
}
float denom = d00 * d11 - d01 * d01;
v = (d11 * d20 - d01 * d21) / denom;
w = (d00 * d21 - d01 * d20) / denom;
u = 1.0f - v - w;
}
public Vector3 Resolve(ref Vector3 a, ref Vector3 b, ref Vector3 c)
{
//return a * u + b * v + c * w;
Vector3 q;
q.x = a.x * u + b.x * v + c.x * w;
q.y = a.y * u + b.y * v + c.y * w;
q.z = a.z * u + b.z * v + c.z * w;
return q;
}
public Vector3 Resolve(ref Vector3 a, ref Vector3 b, ref Vector3 c)
{
//return a * u + b * v + c * w;
Vector3 q;
q.x = a.x * u + b.x * v + c.x * w;
q.y = a.y * u + b.y * v + c.y * w;
q.z = a.z * u + b.z * v + c.z * w;
return q;
}
public bool Within()
{
return (u >= 0.0f && u <= 1.0f) && (v >= 0.0f && v <= 1.0f) && (w >= 0.0f && w <= 1.0f);
}
public bool Within()
{
return (u >= 0.0f && u <= 1.0f) && (v >= 0.0f && v <= 1.0f) && (w >= 0.0f && w <= 1.0f);
}
}
}

185
Runtime/Utility/KdTree3Utils.cs


using System;
public static class KdTree3Utils
namespace Unity.DemoTeam.DigitalHuman
/*
This file implements derivate version of nth_element function in C#. Original Java source code is made by
Adam Horvath and you can find it from
http://blog.teamleadnet.com/2012/07/quick-select-algorithm-find-kth-element.html
public static class KdTree3Utils
{
/*
This file implements derivate version of nth_element function in C#. Original Java source code is made by
Adam Horvath and you can find it from
http://blog.teamleadnet.com/2012/07/quick-select-algorithm-find-kth-element.html
This is free and unencumbered software released into the public domain.
*/
This is free and unencumbered software released into the public domain.
*/
// Nth_element made with Quick select algorithm. Custom comparer. nthToSeek is zero base index
public static void nth_element<T>(T[] array, int startIndex, int nthToSeek, int endIndex, Comparison<T> comparison)
{
int from = startIndex;
int to = endIndex;
// Nth_element made with Quick select algorithm. Custom comparer. nthToSeek is zero base index
public static void nth_element<T>(T[] array, int startIndex, int nthToSeek, int endIndex, Comparison<T> comparison)
{
int from = startIndex;
int to = endIndex;
// if from == to we reached the kth element
while (from < to)
{
int r = from, w = to;
T mid = array[(r + w) / 2];
// if from == to we reached the kth element
while (from < to)
{
int r = from, w = to;
T mid = array[(r + w) / 2];
// stop if the reader and writer meets
while (r < w)
{
if (comparison(array[r], mid) > -1)
{ // put the large values at the end
T tmp = array[w];
array[w] = array[r];
array[r] = tmp;
w--;
}
else
{ // the value is smaller than the pivot, skip
r++;
}
}
// stop if the reader and writer meets
while (r < w)
{
if (comparison(array[r], mid) > -1)
{ // put the large values at the end
T tmp = array[w];
array[w] = array[r];
array[r] = tmp;
w--;
}
else
{ // the value is smaller than the pivot, skip
r++;
}
}
// if we stepped up (r++) we need to step one down
if (comparison(array[r], mid) > 0)
{
r--;
}
// if we stepped up (r++) we need to step one down
if (comparison(array[r], mid) > 0)
{
r--;
}
// the r pointer is on the end of the first k elements
if (nthToSeek <= r)
{
to = r;
}
else
{
from = r + 1;
}
}
// the r pointer is on the end of the first k elements
if (nthToSeek <= r)
{
to = r;
}
else
{
from = r + 1;
}
}
return;
}
return;
}
// Nth_element made with Quick select algorithm. Default comparer. nthSmallest is zero base index
public static void nth_element<T>(T[] array, int startIndex, int nthSmallest, int endIndex)
{
int from = startIndex;
int to = endIndex;
// Nth_element made with Quick select algorithm. Default comparer. nthSmallest is zero base index
public static void nth_element<T>(T[] array, int startIndex, int nthSmallest, int endIndex)
{
int from = startIndex;
int to = endIndex;
// if from == to we reached the kth element
while (from < to)
{
int r = from, w = to;
T mid = array[(r + w) / 2];
// if from == to we reached the kth element
while (from < to)
{
int r = from, w = to;
T mid = array[(r + w) / 2];
// stop if the reader and writer meets
while (r < w)
{
if (System.Collections.Generic.Comparer<T>.Default.Compare(array[r], mid) > -1)
{ // put the large values at the end
T tmp = array[w];
array[w] = array[r];
array[r] = tmp;
w--;
}
else
{ // the value is smaller than the pivot, skip
r++;
}
}
// stop if the reader and writer meets
while (r < w)
{
if (System.Collections.Generic.Comparer<T>.Default.Compare(array[r], mid) > -1)
{ // put the large values at the end
T tmp = array[w];
array[w] = array[r];
array[r] = tmp;
w--;
}
else
{ // the value is smaller than the pivot, skip
r++;
}
}
// if we stepped up (r++) we need to step one down
if (System.Collections.Generic.Comparer<T>.Default.Compare(array[r], mid) > 0)
{
r--;
}
// if we stepped up (r++) we need to step one down
if (System.Collections.Generic.Comparer<T>.Default.Compare(array[r], mid) > 0)
{
r--;
}
// the r pointer is on the end of the first k elements
if (nthSmallest <= r)
{
to = r;
}
else
{
from = r + 1;
}
}
// the r pointer is on the end of the first k elements
if (nthSmallest <= r)
{
to = r;
}
else
{
from = r + 1;
}
}
return;
}
return;
}
}
}

169
Runtime/Utility/LinkedIndexList.cs


using System.Collections;
using System.Collections.Generic;
[Serializable]
public struct LinkedIndexList
namespace Unity.DemoTeam.DigitalHuman
public int head;
public int size;
}
[Serializable]
public struct LinkedIndexList
{
public int head;
public int size;
}
[Serializable]
public struct LinkedIndexItem
{
public int next;
public int prev;
public int data;
}
[Serializable]
public struct LinkedIndexItem
{
public int next;
public int prev;
public int data;
}
[Serializable]
public struct LinkedIndexEnumerable : IEnumerable<int>
{
public LinkedIndexItem[] items;
public int headIndex;
[Serializable]
public struct LinkedIndexEnumerable : IEnumerable<int>
{
public LinkedIndexItem[] items;
public int headIndex;
public LinkedIndexEnumerable(LinkedIndexItem[] items, int headIndex)
{
this.items = items;
this.headIndex = headIndex;
}
public LinkedIndexEnumerable(LinkedIndexItem[] items, int headIndex)
{
this.items = items;
this.headIndex = headIndex;
}
public LinkedIndexEnumerator GetEnumerator()
{
return new LinkedIndexEnumerator(items, headIndex, -1);
}
public LinkedIndexEnumerator GetEnumerator()
{
return new LinkedIndexEnumerator(items, headIndex, -1);
}
IEnumerator<int> IEnumerable<int>.GetEnumerator()
{
return GetEnumerator();
}
IEnumerator<int> IEnumerable<int>.GetEnumerator()
{
return GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
[Serializable]
public struct LinkedIndexEnumerator : IEnumerator<int>
{
public LinkedIndexItem[] items;
public int headIndex;
public int itemIndex;
[Serializable]
public struct LinkedIndexEnumerator : IEnumerator<int>
{
public LinkedIndexItem[] items;
public int headIndex;
public int itemIndex;
public LinkedIndexEnumerator(LinkedIndexItem[] items, int headIndex, int itemIndex)
{
this.items = items;
this.headIndex = headIndex;
this.itemIndex = itemIndex;
}
public LinkedIndexEnumerator(LinkedIndexItem[] items, int headIndex, int itemIndex)
{
this.items = items;
this.headIndex = headIndex;
this.itemIndex = itemIndex;
}
public int Current
{
get { return items[itemIndex].data; }
}
public int Current
{
get { return items[itemIndex].data; }
}
object IEnumerator.Current
{
get { return Current; }
}
object IEnumerator.Current
{
get { return Current; }
}
public bool MoveNext()
{
if (itemIndex == -1)
{
itemIndex = headIndex;
return (itemIndex != -1);//return true;
}
else
{
itemIndex = items[itemIndex].next;
return (itemIndex != headIndex);
}
}
public bool MoveNext()
{
if (itemIndex == -1)
{
itemIndex = headIndex;
return (itemIndex != -1);//return true;
}
else
{
itemIndex = items[itemIndex].next;
return (itemIndex != headIndex);
}
}
public int ReadNext()
{
if (MoveNext())
return Current;
else
return -1;
}
public int ReadNext()
{
if (MoveNext())
return Current;
else
return -1;
}
public void Reset()
{
itemIndex = headIndex;
}
public void Reset()
{
itemIndex = headIndex;
}
public void Dispose()
{
// foo
}
public void Dispose()
{
// foo
}
}
}

187
Runtime/Utility/LinkedIndexListArray.cs


using System;
[Serializable]
public struct LinkedIndexListArray
namespace Unity.DemoTeam.DigitalHuman
public LinkedIndexList[] lists;
public LinkedIndexItem[] items;
[Serializable]
public struct LinkedIndexListArray
{
public LinkedIndexList[] lists;
public LinkedIndexItem[] items;
public int listCount;
public int itemCount;
public int listCount;
public int itemCount;
public void Allocate(int listCapacity, int itemCapacity)
{
ArrayUtils.ResizeCheckedIfLessThan(ref lists, listCapacity);
ArrayUtils.ResizeCheckedIfLessThan(ref items, itemCapacity);
public void Allocate(int listCapacity, int itemCapacity)
{
ArrayUtils.ResizeCheckedIfLessThan(ref lists, listCapacity);
ArrayUtils.ResizeCheckedIfLessThan(ref items, itemCapacity);
Clear();
}
Clear();
}
public void Clear()
{
listCount = lists.Length;
itemCount = 0;
public void Clear()
{
listCount = lists.Length;
itemCount = 0;
for (int i = 0; i != listCount; i++)
{
lists[i].head = -1;
lists[i].size = 0;
}
}
for (int i = 0; i != listCount; i++)
{
lists[i].head = -1;
lists[i].size = 0;
}
}
public void Append(int listIndex, int value)
{
if (itemCount == items.Length)
{
ArrayUtils.ResizeCheckedIfLessThan(ref items, items.Length * 2);
}
public void Append(int listIndex, int value)
{
if (itemCount == items.Length)
{
ArrayUtils.ResizeCheckedIfLessThan(ref items, items.Length * 2);
}
int headIndex = lists[listIndex].head;
if (headIndex == -1)
{
int itemIndex = itemCount++;
int headIndex = lists[listIndex].head;
if (headIndex == -1)
{
int itemIndex = itemCount++;
items[itemIndex] = new LinkedIndexItem
{
next = itemIndex,
prev = itemIndex,
data = value,
};
items[itemIndex] = new LinkedIndexItem
{
next = itemIndex,
prev = itemIndex,
data = value,
};
lists[listIndex].head = itemIndex;
lists[listIndex].size = 1;
}
else
{
int itemIndex = itemCount++;
int tailIndex = items[headIndex].prev;
lists[listIndex].head = itemIndex;
lists[listIndex].size = 1;
}
else
{
int itemIndex = itemCount++;
int tailIndex = items[headIndex].prev;
items[itemIndex] = new LinkedIndexItem
{
next = headIndex,
prev = tailIndex,
data = value,
};
items[itemIndex] = new LinkedIndexItem
{
next = headIndex,
prev = tailIndex,
data = value,
};
items[tailIndex].next = itemIndex;
items[headIndex].prev = itemIndex;
items[tailIndex].next = itemIndex;
items[headIndex].prev = itemIndex;
lists[listIndex].size++;
}
}
lists[listIndex].size++;
}
}
public void AppendMove(int listIndex, int listOther)
{
int headOther = lists[listOther].head;
if (headOther != -1)
{
int headIndex = lists[listIndex].head;
if (headIndex != -1)
{
int tailIndex = items[headIndex].prev;
int tailOther = items[headOther].prev;
public void AppendMove(int listIndex, int listOther)
{
int headOther = lists[listOther].head;
if (headOther != -1)
{
int headIndex = lists[listIndex].head;
if (headIndex != -1)
{
int tailIndex = items[headIndex].prev;
int tailOther = items[headOther].prev;
items[headIndex].prev = tailOther;
items[tailIndex].next = headOther;
items[headIndex].prev = tailOther;
items[tailIndex].next = headOther;
items[headOther].prev = tailIndex;
items[tailOther].next = headIndex;
items[headOther].prev = tailIndex;
items[tailOther].next = headIndex;
lists[listIndex].size += lists[listOther].size;
}
else
{
lists[listIndex].head = lists[listOther].head;
lists[listIndex].size = lists[listOther].size;
}
lists[listIndex].size += lists[listOther].size;
}
else
{
lists[listIndex].head = lists[listOther].head;
lists[listIndex].size = lists[listOther].size;
}
lists[listOther].head = -1;
lists[listOther].size = 0;
}
}
lists[listOther].head = -1;
lists[listOther].size = 0;
}
}
public int GetCount(int listIndex)
{
return lists[listIndex].size;
}
public int GetCount(int listIndex)
{
return lists[listIndex].size;
}
public LinkedIndexEnumerable this[int listIndex]
{
get
{
return new LinkedIndexEnumerable(this.items, this.lists[listIndex].head);
}
}
public LinkedIndexEnumerable this[int listIndex]
{
get
{
return new LinkedIndexEnumerable(this.items, this.lists[listIndex].head);
}
}
}
}

381
Runtime/Utility/MeshAdjacency.cs


using Unity.Collections;
using Unity.Collections.LowLevel.Unsafe;
public class MeshAdjacency
namespace Unity.DemoTeam.DigitalHuman
public LinkedIndexListArray vertexTriangles;
public LinkedIndexListArray vertexVertices;
public LinkedIndexListArray vertexWelded;
public int[] vertexResolve;
public int vertexCount;
public class MeshAdjacency
{
public LinkedIndexListArray vertexTriangles;
public LinkedIndexListArray vertexVertices;
public LinkedIndexListArray vertexWelded;
public int[] vertexResolve;
public int vertexCount;
public LinkedIndexListArray triangleTriangles;
public LinkedIndexListArray triangleVertices;
public int triangleCount;
public LinkedIndexListArray triangleTriangles;
public LinkedIndexListArray triangleVertices;
public int triangleCount;
public MeshAdjacency(MeshBuffers meshBuffers, bool welded = false)
{
LoadFrom(meshBuffers, welded);
}
public MeshAdjacency(MeshBuffers meshBuffers, bool welded = false)
{
LoadFrom(meshBuffers, welded);
}
public void LoadFrom(MeshBuffers meshBuffers, bool welded = false)
{
vertexCount = meshBuffers.vertexCount;
vertexTriangles.Allocate(vertexCount, vertexCount * 8);
vertexVertices.Allocate(vertexCount, vertexCount * 8);
vertexWelded.Allocate(vertexCount, vertexCount);
public void LoadFrom(MeshBuffers meshBuffers, bool welded = false)
{
vertexCount = meshBuffers.vertexCount;
vertexTriangles.Allocate(vertexCount, vertexCount * 8);
vertexVertices.Allocate(vertexCount, vertexCount * 8);
vertexWelded.Allocate(vertexCount, vertexCount);
ArrayUtils.ResizeCheckedIfLessThan(ref vertexResolve, vertexCount);
ArrayUtils.ResizeCheckedIfLessThan(ref vertexResolve, vertexCount);
triangleCount = meshBuffers.triangleCount / 3;
triangleTriangles.Allocate(triangleCount, triangleCount * 8);
triangleVertices.Allocate(triangleCount, triangleCount * 3);
triangleCount = meshBuffers.triangleCount / 3;
triangleTriangles.Allocate(triangleCount, triangleCount * 8);
triangleVertices.Allocate(triangleCount, triangleCount * 3);
int[] triangles = meshBuffers.triangles;
int[] triangles = meshBuffers.triangles;
// build vertex-triangle
{
for (int i = 0; i != triangleCount; i++)
{
int _0 = i * 3;
int v0 = triangles[_0 + 0];
int v1 = triangles[_0 + 1];
int v2 = triangles[_0 + 2];
// build vertex-triangle
{
for (int i = 0; i != triangleCount; i++)
{
int _0 = i * 3;
int v0 = triangles[_0 + 0];
int v1 = triangles[_0 + 1];
int v2 = triangles[_0 + 2];
vertexTriangles.Append(v0, i);
vertexTriangles.Append(v1, i);
vertexTriangles.Append(v2, i);
}
}
vertexTriangles.Append(v0, i);
vertexTriangles.Append(v1, i);
vertexTriangles.Append(v2, i);
}
}
// build vertex-welded
unsafe
{
if (welded)
{
// for each vertex
// if vertex != closest vertex
// replace references to vertex with closest vertex
triangles = triangles.Clone() as int[];
// build vertex-welded
unsafe
{
if (welded)
{
// for each vertex
// if vertex != closest vertex
// replace references to vertex with closest vertex
triangles = triangles.Clone() as int[];
using (var vertexWeldedMap = new UnsafeArrayBool(meshBuffers.vertexCount))
{
vertexWeldedMap.Clear(false);
using (var vertexWeldedMap = new UnsafeArrayBool(meshBuffers.vertexCount))
{
vertexWeldedMap.Clear(false);
var vertexBSP = new KdTree3(meshBuffers.vertexPositions, meshBuffers.vertexCount);
var vertexBSP = new KdTree3(meshBuffers.vertexPositions, meshBuffers.vertexCount);
for (int i = 0; i != vertexCount; i++)
{
int j = vertexBSP.FindNearest(ref meshBuffers.vertexPositions[i]);
if (j != i)
{
//Debug.Assert(vertexWeldedMap.val[j] == false);
for (int i = 0; i != vertexCount; i++)
{
int j = vertexBSP.FindNearest(ref meshBuffers.vertexPositions[i]);
if (j != i)
{
//Debug.Assert(vertexWeldedMap.val[j] == false);
// replace references to i with j, keeping j
foreach (var triangle in vertexTriangles[i])
{
int _0 = triangle * 3;
int v0 = triangles[_0 + 0];
int v1 = triangles[_0 + 1];
//..v2 = triangles[_0 + 2];
// replace references to i with j, keeping j
foreach (var triangle in vertexTriangles[i])
{
int _0 = triangle * 3;
int v0 = triangles[_0 + 0];
int v1 = triangles[_0 + 1];
//..v2 = triangles[_0 + 2];
if (v0 == i)
triangles[_0 + 0] = j;
else if (v1 == i)
triangles[_0 + 1] = j;
else // (v2 == i)
triangles[_0 + 2] = j;
if (v0 == i)
triangles[_0 + 0] = j;
else if (v1 == i)
triangles[_0 + 1] = j;
else // (v2 == i)
triangles[_0 + 2] = j;
// store i under j, so we can recover i at a later time
if (vertexWeldedMap.val[i] == false)
{
vertexWeldedMap.val[i] = true;
vertexWelded.Append(j, i);
}
}
}
}
}
// store i under j, so we can recover i at a later time
if (vertexWeldedMap.val[i] == false)
{
vertexWeldedMap.val[i] = true;
vertexWelded.Append(j, i);
}
}
}
}
}
// rebuild vertex-triangle
vertexTriangles.Clear();
// rebuild vertex-triangle
vertexTriangles.Clear();
for (int i = 0; i != triangleCount; i++)
{
int _0 = i * 3;
int v0 = triangles[_0 + 0];
int v1 = triangles[_0 + 1];
int v2 = triangles[_0 + 2];
for (int i = 0; i != triangleCount; i++)
{
int _0 = i * 3;
int v0 = triangles[_0 + 0];
int v1 = triangles[_0 + 1];
int v2 = triangles[_0 + 2];
vertexTriangles.Append(v0, i);
vertexTriangles.Append(v1, i);
vertexTriangles.Append(v2, i);
}
}
}
vertexTriangles.Append(v0, i);
vertexTriangles.Append(v1, i);
vertexTriangles.Append(v2, i);
}
}
}
// build vertex-resolve
{
for (int i = 0; i != vertexCount; i++)
{
vertexResolve[i] = i;
}
// build vertex-resolve
{
for (int i = 0; i != vertexCount; i++)
{
vertexResolve[i] = i;
}
for (int i = 0; i != vertexCount; i++)
{
foreach (var j in vertexWelded[i])
{
vertexResolve[j] = i;
}
}
}
for (int i = 0; i != vertexCount; i++)
{
foreach (var j in vertexWelded[i])
{
vertexResolve[j] = i;
}
}
}
// build vertex-vertex
unsafe
{
using (var vertexAdded = new UnsafeArrayBool(vertexCount))
{
vertexAdded.Clear(false);
// build vertex-vertex
unsafe
{
using (var vertexAdded = new UnsafeArrayBool(vertexCount))
{
vertexAdded.Clear(false);
for (int i = 0; i != vertexCount; i++)
{
foreach (int triangle in vertexTriangles[i])
{
int _0 = triangle * 3;
int v0 = triangles[_0 + 0];
int v1 = triangles[_0 + 1];
int v2 = triangles[_0 + 2];
for (int i = 0; i != vertexCount; i++)
{
foreach (int triangle in vertexTriangles[i])
{
int _0 = triangle * 3;
int v0 = triangles[_0 + 0];
int v1 = triangles[_0 + 1];
int v2 = triangles[_0 + 2];
int vA, vB;
if (i == v0)
{
vA = v1;
vB = v2;
}
else if (i == v1)
{
vA = v2;
vB = v0;
}
else // (i == v2)
{
vA = v0;
vB = v1;
}
int vA, vB;
if (i == v0)
{
vA = v1;
vB = v2;
}
else if (i == v1)
{
vA = v2;
vB = v0;
}
else // (i == v2)
{
vA = v0;
vB = v1;
}
if (vertexAdded.val[vA] == false && (vertexAdded.val[vA] = true))
vertexVertices.Append(i, vA);
if (vertexAdded.val[vA] == false && (vertexAdded.val[vA] = true))
vertexVertices.Append(i, vA);
if (vertexAdded.val[vB] == false && (vertexAdded.val[vB] = true))
vertexVertices.Append(i, vB);
}
if (vertexAdded.val[vB] == false && (vertexAdded.val[vB] = true))
vertexVertices.Append(i, vB);
}
foreach (int j in vertexVertices[i])
vertexAdded.val[j] = false;
}
}
}
foreach (int j in vertexVertices[i])
vertexAdded.val[j] = false;
}
}
}
// build triangle-triangle
unsafe
{
using (var triangleAdded = new UnsafeArrayBool(triangleCount))
{
triangleAdded.Clear(false);
// build triangle-triangle
unsafe
{
using (var triangleAdded = new UnsafeArrayBool(triangleCount))
{
triangleAdded.Clear(false);
for (int i = 0; i != triangleCount; i++)
{
int _0 = i * 3;
int v0 = triangles[_0 + 0];
int v1 = triangles[_0 + 1];
int v2 = triangles[_0 + 2];
for (int i = 0; i != triangleCount; i++)
{
int _0 = i * 3;
int v0 = triangles[_0 + 0];
int v1 = triangles[_0 + 1];
int v2 = triangles[_0 + 2];
triangleAdded.val[i] = true;
triangleAdded.val[i] = true;
foreach (int j in vertexTriangles[v0])
if (triangleAdded.val[j] == false && (triangleAdded.val[j] = true))
triangleTriangles.Append(i, j);
foreach (int j in vertexTriangles[v0])
if (triangleAdded.val[j] == false && (triangleAdded.val[j] = true))
triangleTriangles.Append(i, j);
foreach (int j in vertexTriangles[v1])
if (triangleAdded.val[j] == false && (triangleAdded.val[j] = true))
triangleTriangles.Append(i, j);
foreach (int j in vertexTriangles[v1])
if (triangleAdded.val[j] == false && (triangleAdded.val[j] = true))
triangleTriangles.Append(i, j);
foreach (int j in vertexTriangles[v2])
if (triangleAdded.val[j] == false && (triangleAdded.val[j] = true))
triangleTriangles.Append(i, j);
foreach (int j in vertexTriangles[v2])
if (triangleAdded.val[j] == false && (triangleAdded.val[j] = true))
triangleTriangles.Append(i, j);
triangleAdded.val[i] = false;
triangleAdded.val[i] = false;
foreach (int j in triangleTriangles[i])
triangleAdded.val[j] = false;
}
}
}
foreach (int j in triangleTriangles[i])
triangleAdded.val[j] = false;
}
}
}
// build triangle-vertex
{
for (int i = 0; i != triangleCount; i++)
{
int _0 = i * 3;
int v0 = triangles[_0 + 0];
int v1 = triangles[_0 + 1];
int v2 = triangles[_0 + 2];
// build triangle-vertex
{
for (int i = 0; i != triangleCount; i++)
{
int _0 = i * 3;
int v0 = triangles[_0 + 0];
int v1 = triangles[_0 + 1];
int v2 = triangles[_0 + 2];
triangleVertices.Append(i, v0);
triangleVertices.Append(i, v1);
triangleVertices.Append(i, v2);
}
}
}
triangleVertices.Append(i, v0);
triangleVertices.Append(i, v1);
triangleVertices.Append(i, v2);
}
}
}
}
}

501
Runtime/Utility/MeshBuffers.cs


using Unity.Jobs;
using Unity.Burst;
public class MeshBuffers
namespace Unity.DemoTeam.DigitalHuman
public static List<Vector3> __tempVertexPositions = new List<Vector3>();
public static List<Vector4> __tempVertexTangents = new List<Vector4>();
public static List<Vector3> __tempVertexNormals = new List<Vector3>();
public class MeshBuffers
{
public static List<Vector3> __tempVertexPositions = new List<Vector3>();
public static List<Vector4> __tempVertexTangents = new List<Vector4>();
public static List<Vector3> __tempVertexNormals = new List<Vector3>();
public static Vector4[] __tempVector4;
public static List<int> __tempIndices = new List<int>();
public static Vector4[] __tempVector4;
public static List<int> __tempIndices = new List<int>();
public int vertexCount;
public Vector3[] vertexPositions;
public Vector3[] vertexTangents;
public Vector3[] vertexNormals;
public int vertexCount;
public Vector3[] vertexPositions;
public Vector3[] vertexTangents;
public Vector3[] vertexNormals;
public int triangleCount;
public int[] triangles;
public int triangleCount;
public int[] triangles;
public MeshBuffers(int vertexCapacity)
{
vertexCount = 0;
vertexPositions = new Vector3[vertexCapacity];
vertexTangents = new Vector3[vertexCapacity];
vertexNormals = new Vector3[vertexCapacity];
public MeshBuffers(int vertexCapacity)
{
vertexCount = 0;
vertexPositions = new Vector3[vertexCapacity];
vertexTangents = new Vector3[vertexCapacity];
vertexNormals = new Vector3[vertexCapacity];
triangleCount = 0;
triangles = new int[vertexCapacity];
}
triangleCount = 0;
triangles = new int[vertexCapacity];
}
public MeshBuffers(Mesh mesh) : this(mesh.vertexCount)
{
LoadFrom(mesh);
}
public MeshBuffers(Mesh mesh) : this(mesh.vertexCount)
{
LoadFrom(mesh);
}
public void LoadFrom(Mesh mesh)
{
// copy vertices
Profiler.BeginSample("copy-verts");
public void LoadFrom(Mesh mesh)
mesh.GetVertices(__tempVertexPositions);
mesh.GetTangents(__tempVertexTangents);
mesh.GetNormals(__tempVertexNormals);
// copy vertices
Profiler.BeginSample("copy-verts");
{
mesh.GetVertices(__tempVertexPositions);
mesh.GetTangents(__tempVertexTangents);
mesh.GetNormals(__tempVertexNormals);
vertexCount = mesh.vertexCount;
vertexCount = mesh.vertexCount;
ArrayUtils.ResizeCheckedIfLessThan(ref vertexPositions, vertexCount);
__tempVertexPositions.CopyTo(vertexPositions);
ArrayUtils.ResizeCheckedIfLessThan(ref vertexPositions, vertexCount);
__tempVertexPositions.CopyTo(vertexPositions);
ArrayUtils.ResizeCheckedIfLessThan(ref __tempVector4, vertexCount);
__tempVertexTangents.CopyTo(__tempVector4);
ArrayUtils.ResizeCheckedIfLessThan(ref __tempVector4, vertexCount);
__tempVertexTangents.CopyTo(__tempVector4);
ArrayUtils.ResizeCheckedIfLessThan(ref vertexTangents, vertexCount);
unsafe
{
fixed (Vector3* dst = vertexTangents)
fixed (Vector4* src = __tempVector4)
ArrayUtils.ResizeCheckedIfLessThan(ref vertexTangents, vertexCount);
unsafe
var job = new CopyTangentsJob()
fixed (Vector3* dst = vertexTangents)
fixed (Vector4* src = __tempVector4)
dst = dst,
src = src,
};
job.Schedule(vertexCount, 1024).Complete();
var job = new CopyTangentsJob()
{
dst = dst,
src = src,
};
job.Schedule(vertexCount, 1024).Complete();
}
ArrayUtils.ResizeCheckedIfLessThan(ref vertexNormals, vertexCount);
__tempVertexNormals.CopyTo(vertexNormals);
Profiler.EndSample();
ArrayUtils.ResizeCheckedIfLessThan(ref vertexNormals, vertexCount);
__tempVertexNormals.CopyTo(vertexNormals);
}
Profiler.EndSample();
// copy triangles
Profiler.BeginSample("copy-tris");
{
triangleCount = 0;
// copy triangles
Profiler.BeginSample("copy-tris");
{
triangleCount = 0;
int submeshCount = mesh.subMeshCount;
if (submeshCount > 0)
{
for (int i = 0; i != submeshCount; i++)
{
mesh.GetTriangles(__tempIndices, i);
int submeshCount = mesh.subMeshCount;
if (submeshCount > 0)
{
for (int i = 0; i != submeshCount; i++)
{
mesh.GetTriangles(__tempIndices, i);
int submeshTriangleCount = __tempIndices.Count;
if (submeshTriangleCount > 0)
{
ArrayUtils.ResizeCheckedIfLessThan(ref triangles, triangleCount + submeshTriangleCount);
__tempIndices.CopyTo(triangles, triangleCount);
}
int submeshTriangleCount = __tempIndices.Count;
if (submeshTriangleCount > 0)
{
ArrayUtils.ResizeCheckedIfLessThan(ref triangles, triangleCount + submeshTriangleCount);
__tempIndices.CopyTo(triangles, triangleCount);
triangleCount += submeshTriangleCount;
triangleCount += submeshTriangleCount;
Profiler.EndSample();
Profiler.EndSample();
}
public void LoadFrom(in NativeMeshSOA nativeMesh)
{
// copy vertices
Profiler.BeginSample("copy-verts");
public void LoadFrom(in NativeMeshSOA nativeMesh)
vertexCount = nativeMesh.vertexCount;
// copy vertices
Profiler.BeginSample("copy-verts");
{
vertexCount = nativeMesh.vertexCount;
ArrayUtils.ResizeCheckedIfLessThan(ref vertexPositions, vertexCount);
ArrayUtils.ResizeCheckedIfLessThan(ref vertexTangents, vertexCount);
ArrayUtils.ResizeCheckedIfLessThan(ref vertexNormals, vertexCount);
nativeMesh.vertexPositions.CopyTo(vertexPositions);
Array.Clear(vertexTangents, 0, vertexTangents.Length);
nativeMesh.vertexNormals.CopyTo(vertexNormals);
}
Profiler.EndSample();
ArrayUtils.ResizeCheckedIfLessThan(ref vertexPositions, vertexCount);
ArrayUtils.ResizeCheckedIfLessThan(ref vertexTangents, vertexCount);
ArrayUtils.ResizeCheckedIfLessThan(ref vertexNormals, vertexCount);
// copy triangles
Profiler.BeginSample("copy-tris");
{
triangleCount = nativeMesh.faceIndicesCount;
nativeMesh.vertexPositions.CopyTo(vertexPositions);
Array.Clear(vertexTangents, 0, vertexTangents.Length);
nativeMesh.vertexNormals.CopyTo(vertexNormals);
ArrayUtils.ResizeCheckedIfLessThan(ref triangles, triangleCount);
nativeMesh.faceIndices.CopyTo(triangles);
}
Profiler.EndSample();
Profiler.EndSample();
// copy triangles
Profiler.BeginSample("copy-tris");
public void LoadPositionsFrom(Mesh mesh)
triangleCount = nativeMesh.faceIndicesCount;
Profiler.BeginSample("inject-verts-pos");
{
mesh.GetVertices(__tempVertexPositions);
ArrayUtils.ResizeCheckedIfLessThan(ref triangles, triangleCount);
nativeMesh.faceIndices.CopyTo(triangles);
ArrayUtils.ResizeCheckedIfLessThan(ref vertexPositions, vertexCount);
__tempVertexPositions.CopyTo(vertexPositions);
}
Profiler.EndSample();
Profiler.EndSample();
}
public void LoadPositionsFrom(Mesh mesh)
{
Profiler.BeginSample("inject-verts-pos");
public void LoadNormalsFrom(Mesh mesh)
mesh.GetVertices(__tempVertexPositions);
Profiler.BeginSample("inject-verts-nrm");
{
mesh.GetNormals(__tempVertexNormals);
ArrayUtils.ResizeCheckedIfLessThan(ref vertexPositions, vertexCount);
__tempVertexPositions.CopyTo(vertexPositions);
ArrayUtils.ResizeCheckedIfLessThan(ref vertexNormals, vertexCount);
__tempVertexNormals.CopyTo(vertexNormals);
}
Profiler.EndSample();
Profiler.EndSample();
}
public void LoadNormalsFrom(Mesh mesh)
{
Profiler.BeginSample("inject-verts-nrm");
public void CopyTo(MeshBuffers meshBuffers)
mesh.GetNormals(__tempVertexNormals);
Profiler.BeginSample("copy-existing");
{
ArrayUtils.CopyChecked(vertexPositions, ref meshBuffers.vertexPositions, vertexCount);
ArrayUtils.CopyChecked(vertexTangents, ref meshBuffers.vertexTangents, vertexCount);
ArrayUtils.CopyChecked(vertexNormals, ref meshBuffers.vertexNormals, vertexCount);
meshBuffers.vertexCount = vertexCount;
ArrayUtils.ResizeCheckedIfLessThan(ref vertexNormals, vertexCount);
__tempVertexNormals.CopyTo(vertexNormals);
ArrayUtils.CopyChecked(triangles, ref meshBuffers.triangles, triangleCount);
meshBuffers.triangleCount = triangleCount;
}
Profiler.EndSample();
Profiler.EndSample();
}
public void CopyTo(MeshBuffers meshBuffers)
{
Profiler.BeginSample("copy-existing");
[BurstCompile]
unsafe struct CopyTangentsJob : IJobParallelFor
ArrayUtils.CopyChecked(vertexPositions, ref meshBuffers.vertexPositions, vertexCount);
ArrayUtils.CopyChecked(vertexTangents, ref meshBuffers.vertexTangents, vertexCount);
ArrayUtils.CopyChecked(vertexNormals, ref meshBuffers.vertexNormals, vertexCount);
meshBuffers.vertexCount = vertexCount;
[NativeDisableUnsafePtrRestriction] public Vector3* dst;
[NativeDisableUnsafePtrRestriction] public Vector4* src;
ArrayUtils.CopyChecked(triangles, ref meshBuffers.triangles, triangleCount);
meshBuffers.triangleCount = triangleCount;
public void Execute(int i)
{
dst[i].x = src[i].x * src[i].w;
dst[i].y = src[i].y * src[i].w;
dst[i].z = src[i].z * src[i].w;
}
Profiler.EndSample();
}
[BurstCompile]
unsafe struct CopyTangentsJob : IJobParallelFor
{
[NativeDisableUnsafePtrRestriction] public Vector3* dst;
[NativeDisableUnsafePtrRestriction] public Vector4* src;
public void Execute(int i)
public void ApplyRotation(Quaternion q)
dst[i].x = src[i].x * src[i].w;
dst[i].y = src[i].y * src[i].w;
dst[i].z = src[i].z * src[i].w;
for (int i = 0; i != vertexCount; i++)
vertexPositions[i] = q * vertexPositions[i];
for (int i = 0; i != vertexCount; i++)
vertexTangents[i] = q * vertexTangents[i];
for (int i = 0; i != vertexCount; i++)
vertexNormals[i] = q * vertexNormals[i];
}
public void ApplyRotation(Quaternion q)
{
for (int i = 0; i != vertexCount; i++)
vertexPositions[i] = q * vertexPositions[i];
for (int i = 0; i != vertexCount; i++)
vertexTangents[i] = q * vertexTangents[i];
for (int i = 0; i != vertexCount; i++)
vertexNormals[i] = q * vertexNormals[i];
}
public void ApplyScale(float s)
{
for (int i = 0; i != vertexCount; i++)
vertexPositions[i] = s * vertexPositions[i];
}
public void ApplyScale(float s)
{
for (int i = 0; i != vertexCount; i++)
vertexPositions[i] = s * vertexPositions[i];
}
public void ApplySmoothing(MeshAdjacency meshAdjacency, int iterations)
{
Debug.Assert(vertexCount == meshAdjacency.vertexCount);
unsafe
public void ApplySmoothing(MeshAdjacency meshAdjacency, int iterations)
fixed (Vector3* __vertexPositions = vertexPositions)
Debug.Assert(vertexCount == meshAdjacency.vertexCount);
unsafe
using (var v = new UnsafeArrayVector3(meshAdjacency.vertexCount))
fixed (Vector3* __vertexPositions = vertexPositions)
while (iterations-- >= 0)
using (var v = new UnsafeArrayVector3(meshAdjacency.vertexCount))
for (int i = 0; i != meshAdjacency.vertexCount; i++)
while (iterations-- >= 0)
var s = new Vector3(0.0f, 0.0f, 0.0f);
var d = meshAdjacency.vertexVertices.lists[i].size;
foreach (int j in meshAdjacency.vertexVertices[i])
for (int i = 0; i != meshAdjacency.vertexCount; i++)
s.x += __vertexPositions[j].x;
s.y += __vertexPositions[j].y;
s.z += __vertexPositions[j].z;
var s = new Vector3(0.0f, 0.0f, 0.0f);
var d = meshAdjacency.vertexVertices.lists[i].size;
foreach (int j in meshAdjacency.vertexVertices[i])
{
s.x += __vertexPositions[j].x;
s.y += __vertexPositions[j].y;
s.z += __vertexPositions[j].z;
}
v.val[i] = s / d;
v.val[i] = s / d;
UnsafeUtility.MemCpy(__vertexPositions, v.val, sizeof(Vector3) * vertexCount);
UnsafeUtility.MemCpy(__vertexPositions, v.val, sizeof(Vector3) * vertexCount);
}
public void ApplyWeldedChanges(MeshAdjacency meshAdjacency)
{
Debug.Assert(vertexCount == meshAdjacency.vertexCount);
for (int i = 0; i != meshAdjacency.vertexCount; i++)
public void ApplyWeldedChanges(MeshAdjacency meshAdjacency)
foreach (int j in meshAdjacency.vertexWelded[i])
Debug.Assert(vertexCount == meshAdjacency.vertexCount);
for (int i = 0; i != meshAdjacency.vertexCount; i++)
vertexPositions[j] = vertexPositions[i];
vertexTangents[j] = vertexTangents[i];
vertexNormals[j] = vertexNormals[i];
foreach (int j in meshAdjacency.vertexWelded[i])
{
vertexPositions[j] = vertexPositions[i];
vertexTangents[j] = vertexTangents[i];
vertexNormals[j] = vertexNormals[i];
}
}
public Vector3 CalcMeshCenter()
{
Vector3 average = Vector3.zero;
for (int i = 0; i != vertexCount; i++)
public Vector3 CalcMeshCenter()
average += vertexPositions[i];
Vector3 average = Vector3.zero;
for (int i = 0; i != vertexCount; i++)
{
average += vertexPositions[i];
}
return average / vertexCount;
return average / vertexCount;
}
public Vector3 CalcAABBCenter()
{
Vector3 min;
Vector3 max;
CalcAABBMinMax(out min, out max);
return 0.5f * (min + max);
}
public Vector3 CalcAABBExtent()
{
Vector3 min;
Vector3 max;
CalcAABBMinMax(out min, out max);
return 0.5f * (max - min);
}
public Vector3 CalcAABBCenter()
{
Vector3 min;
Vector3 max;
CalcAABBMinMax(out min, out max);
return 0.5f * (min + max);
}
public void CalcAABBMinMax(out Vector3 min, out Vector3 max)
{
min = Vector3.positiveInfinity;
max = Vector3.negativeInfinity;
for (int i = 0; i != vertexCount; i++)
public Vector3 CalcAABBExtent()
min = Vector3.Min(min, vertexPositions[i]);
max = Vector3.Max(max, vertexPositions[i]);
Vector3 min;
Vector3 max;
CalcAABBMinMax(out min, out max);
return 0.5f * (max - min);
}
public void RecalculateNormals(MeshAdjacency meshAdjacency)
{
unsafe
public void CalcAABBMinMax(out Vector3 min, out Vector3 max)
using (var triangleProducts = new UnsafeArrayVector3(meshAdjacency.triangleCount))
min = Vector3.positiveInfinity;
max = Vector3.negativeInfinity;
for (int i = 0; i != vertexCount; i++)
triangleProducts.Clear(Vector3.zero);
min = Vector3.Min(min, vertexPositions[i]);
max = Vector3.Max(max, vertexPositions[i]);
}
}
for (int i = 0; i != meshAdjacency.triangleCount; i++)
public void RecalculateNormals(MeshAdjacency meshAdjacency)
{
unsafe
{
using (var triangleProducts = new UnsafeArrayVector3(meshAdjacency.triangleCount))
var _e = meshAdjacency.triangleVertices[i].GetEnumerator();
int v0 = _e.ReadNext();
int v1 = _e.ReadNext();
int v2 = _e.ReadNext();
triangleProducts.Clear(Vector3.zero);
Vector3 v0v1 = vertexPositions[v1] - vertexPositions[v0];
Vector3 v0v2 = vertexPositions[v2] - vertexPositions[v0];
for (int i = 0; i != meshAdjacency.triangleCount; i++)
{
var _e = meshAdjacency.triangleVertices[i].GetEnumerator();
int v0 = _e.ReadNext();
int v1 = _e.ReadNext();
int v2 = _e.ReadNext();
triangleProducts.val[i] = Vector3.Cross(v0v1, v0v2);
}
Vector3 v0v1 = vertexPositions[v1] - vertexPositions[v0];
Vector3 v0v2 = vertexPositions[v2] - vertexPositions[v0];
for (int i = 0; i != meshAdjacency.vertexCount; i++)
{
Vector3 sumProducts = Vector3.zero;
foreach (var triangle in meshAdjacency.vertexTriangles[i])
{
sumProducts += triangleProducts.val[triangle];
triangleProducts.val[i] = Vector3.Cross(v0v1, v0v2);
var sumProductsSqNorm = Vector3.SqrMagnitude(sumProducts);
if (sumProductsSqNorm != 0.0f)
for (int i = 0; i != meshAdjacency.vertexCount; i++)
vertexNormals[i] = sumProducts / Mathf.Sqrt(sumProductsSqNorm);
}
else
{
var numVertexTriangles = meshAdjacency.vertexTriangles.lists[i].size;
if (numVertexTriangles != 0)
Vector3 sumProducts = Vector3.zero;
foreach (var triangle in meshAdjacency.vertexTriangles[i])
{
sumProducts += triangleProducts.val[triangle];
}
var sumProductsSqNorm = Vector3.SqrMagnitude(sumProducts);
if (sumProductsSqNorm != 0.0f)
Debug.LogError("degenerate vertex " + i + ": all " + numVertexTriangles + " adjacent triangles have zero area");
break;
vertexNormals[i] = sumProducts / Mathf.Sqrt(sumProductsSqNorm);
}
else
{
var numVertexTriangles = meshAdjacency.vertexTriangles.lists[i].size;
if (numVertexTriangles != 0)
{
Debug.LogError("degenerate vertex " + i + ": all " + numVertexTriangles + " adjacent triangles have zero area");
break;
}
}
public void DrawTriangle(int triangle)
{
int _0 = triangle * 3;
int v0 = triangles[_0];
int v1 = triangles[_0 + 1];
int v2 = triangles[_0 + 2];
Gizmos.DrawLine(vertexPositions[v0], vertexPositions[v1]);
Gizmos.DrawLine(vertexPositions[v1], vertexPositions[v2]);
Gizmos.DrawLine(vertexPositions[v2], vertexPositions[v0]);
}
public void DrawTriangles(IEnumerable<int> triangleEnumerable)
{
var triangleEnumerator = triangleEnumerable.GetEnumerator();
while (triangleEnumerator.MoveNext())
public void DrawGizmoTriangle(int triangle)
int _0 = triangleEnumerator.Current * 3;
int _0 = triangle * 3;
int v0 = triangles[_0];
int v1 = triangles[_0 + 1];
int v2 = triangles[_0 + 2];

Gizmos.DrawLine(vertexPositions[v2], vertexPositions[v0]);
}
public void DrawGizmoTriangles(IEnumerable<int> triangleEnumerable)
{
var triangleEnumerator = triangleEnumerable.GetEnumerator();
while (triangleEnumerator.MoveNext())
{
int _0 = triangleEnumerator.Current * 3;
int v0 = triangles[_0];
int v1 = triangles[_0 + 1];
int v2 = triangles[_0 + 2];
Gizmos.DrawLine(vertexPositions[v0], vertexPositions[v1]);
Gizmos.DrawLine(vertexPositions[v1], vertexPositions[v2]);
Gizmos.DrawLine(vertexPositions[v2], vertexPositions[v0]);
}
}
#endif
#endif
}
}

189
Runtime/Utility/MeshEdges.cs


using UnityEngine;
using Unity.Collections.LowLevel.Unsafe;
public class MeshEdges
namespace Unity.DemoTeam.DigitalHuman
public Edge[] edges;
public struct Edge
{
public int p1;
public int p2;
}
public class MeshEdges
{
public Edge[] edges;
public struct Edge
{
public int p1;
public int p2;
}
private static HashSet<ulong> __hashedPairs = new HashSet<ulong>();
private static void __hashedPairsClear() { __hashedPairs.Clear(); }
private static bool __hashedPairsAdd(int i, int j)
{
ulong i32 = (ulong)i;
ulong j32 = (ulong)j;
private static HashSet<ulong> __hashedPairs = new HashSet<ulong>();
private static void __hashedPairsClear() { __hashedPairs.Clear(); }
private static bool __hashedPairsAdd(int i, int j)
{
ulong i32 = (ulong)i;
ulong j32 = (ulong)j;
ulong hashedPair = (i < j) ? (i32 | (j32 << 32)) : (j32 | (i32 << 32));
if (__hashedPairs.Contains(hashedPair) == false)
{
__hashedPairs.Add(hashedPair);
return true;
}
else
{
return false;
}
}
ulong hashedPair = (i < j) ? (i32 | (j32 << 32)) : (j32 | (i32 << 32));
if (__hashedPairs.Contains(hashedPair) == false)
{
__hashedPairs.Add(hashedPair);
return true;
}
else
{
return false;
}
}
public MeshEdges()
{
ArrayUtils.ResizeChecked(ref edges, 0);
}
public MeshEdges()
{
ArrayUtils.ResizeChecked(ref edges, 0);
}
public MeshEdges(int[] triangles)
{
LoadFrom(triangles);
}
public MeshEdges(int[] triangles)
{
LoadFrom(triangles);
}
public void LoadFrom(int[] triangles)
{
unsafe
{
var numTriangles = triangles.Length / 3;
var numEdges = 0;
public void LoadFrom(int[] triangles)
{
unsafe
{
var numTriangles = triangles.Length / 3;
var numEdges = 0;
var buffer = (Edge*)UnsafeUtility.Malloc(sizeof(Edge) * numTriangles * 3, 1, Unity.Collections.Allocator.Temp);
var buffer = (Edge*)UnsafeUtility.Malloc(sizeof(Edge) * numTriangles * 3, 1, Unity.Collections.Allocator.Temp);
__hashedPairsClear();
__hashedPairsClear();
for (int triangleIndex = 0; triangleIndex != numTriangles; triangleIndex++)
{
var i = triangles[triangleIndex * 3 + 0];
var j = triangles[triangleIndex * 3 + 1];
var k = triangles[triangleIndex * 3 + 2];
for (int triangleIndex = 0; triangleIndex != numTriangles; triangleIndex++)
{
var i = triangles[triangleIndex * 3 + 0];
var j = triangles[triangleIndex * 3 + 1];
var k = triangles[triangleIndex * 3 + 2];
if (__hashedPairsAdd(i, j))
buffer[numEdges++] = new Edge { p1 = i, p2 = j };
if (__hashedPairsAdd(i, j))
buffer[numEdges++] = new Edge { p1 = i, p2 = j };
if (__hashedPairsAdd(j, k))
buffer[numEdges++] = new Edge { p1 = j, p2 = k };
if (__hashedPairsAdd(j, k))
buffer[numEdges++] = new Edge { p1 = j, p2 = k };
if (__hashedPairsAdd(k, i))
buffer[numEdges++] = new Edge { p1 = k, p2 = i };
}
if (__hashedPairsAdd(k, i))
buffer[numEdges++] = new Edge { p1 = k, p2 = i };
}
ArrayUtils.ResizeChecked(ref edges, numEdges);
ArrayUtils.ResizeChecked(ref edges, numEdges);
fixed (Edge* edgesPtr = edges)
{
UnsafeUtility.MemCpy(edgesPtr, buffer, sizeof(Edge) * numEdges);
UnsafeUtility.Free(buffer, Unity.Collections.Allocator.Temp);
}
//Debug.Log("numTriangles = " + numTriangles + ", numEdges = " + numEdges);
}
}
fixed (Edge* edgesPtr = edges)
{
UnsafeUtility.MemCpy(edgesPtr, buffer, sizeof(Edge) * numEdges);
UnsafeUtility.Free(buffer, Unity.Collections.Allocator.Temp);
}
//Debug.Log("numTriangles = " + numTriangles + ", numEdges = " + numEdges);
}
}
public void ComputeLengths(ref float[] lengths, Vector3[] positions)
{
ArrayUtils.ResizeChecked(ref lengths, edges.Length);
for (int i = 0; i != edges.Length; i++)
{
Vector3 p1 = positions[edges[i].p1];
Vector3 p2 = positions[edges[i].p2];
lengths[i] = Vector3.Magnitude(p2 - p1);
}
}
public void ComputeLengths(ref float[] lengths, Vector3[] positions)
{
ArrayUtils.ResizeChecked(ref lengths, edges.Length);
for (int i = 0; i != edges.Length; i++)
{
Vector3 p1 = positions[edges[i].p1];
Vector3 p2 = positions[edges[i].p2];
lengths[i] = Vector3.Magnitude(p2 - p1);
}
}
public void ComputeCurvatures(ref float[] curvatures, Vector3[] positions, Vector3[] normals)
{
ArrayUtils.ResizeChecked(ref curvatures, edges.Length);
for (int i = 0; i != edges.Length; i++)
{
// https://computergraphics.stackexchange.com/a/1719
var p1 = positions[edges[i].p1];
var p2 = positions[edges[i].p2];
var p1p2 = p2 - p1;
var squaredLength = Vector3.Dot(p1p2, p1p2);
if (squaredLength != 0.0f)
{
var n1 = normals[edges[i].p1];
var n2 = normals[edges[i].p2];
curvatures[i] = Vector3.Dot(n2 - n1, p1p2) / squaredLength;
}
else
{
curvatures[i] = 0.0f;
}
}
}
public void ComputeCurvatures(ref float[] curvatures, Vector3[] positions, Vector3[] normals)
{
ArrayUtils.ResizeChecked(ref curvatures, edges.Length);
for (int i = 0; i != edges.Length; i++)
{
// https://computergraphics.stackexchange.com/a/1719
var p1 = positions[edges[i].p1];
var p2 = positions[edges[i].p2];
var p1p2 = p2 - p1;
var squaredLength = Vector3.Dot(p1p2, p1p2);
if (squaredLength != 0.0f)
{
var n1 = normals[edges[i].p1];
var n2 = normals[edges[i].p2];
curvatures[i] = Vector3.Dot(n2 - n1, p1p2) / squaredLength;
}
else
{
curvatures[i] = 0.0f;
}
}
}
}
}

89
Runtime/Utility/MeshEx.cs


using UnityEngine;
using UnityEngine.Rendering;
public static class MeshEx
namespace Unity.DemoTeam.DigitalHuman
public static class MeshEx
{
const MeshUpdateFlags UPDATE_FLAGS_SILENT =
MeshUpdateFlags.DontNotifyMeshUsers |
MeshUpdateFlags.DontRecalculateBounds |
MeshUpdateFlags.DontResetBoneBounds;
const MeshUpdateFlags UPDATE_FLAGS_SILENT =
MeshUpdateFlags.DontNotifyMeshUsers |
MeshUpdateFlags.DontRecalculateBounds |
MeshUpdateFlags.DontResetBoneBounds;
public static void EnableSilentWrites(this Mesh mesh, bool enable)
{
public static void EnableSilentWrites(this Mesh mesh, bool enable)
{
mesh.enableSilentWrites = enable;
mesh.enableSilentWrites = enable;
}
}
public static void SilentlySetVertices(this Mesh mesh, Vector3[] positions)
{
public static void SilentlySetVertices(this Mesh mesh, Vector3[] positions)
{
mesh.SetVertices(positions, 0, positions.Length, UPDATE_FLAGS_SILENT);
mesh.SetVertices(positions, 0, positions.Length, UPDATE_FLAGS_SILENT);
mesh.EnableSilentWrites(true);
mesh.SetVertices(positions, 0, positions.Length);
mesh.EnableSilentWrites(false);
mesh.EnableSilentWrites(true);
mesh.SetVertices(positions, 0, positions.Length);
mesh.EnableSilentWrites(false);
}
}
public static void SilentlySetNormals(this Mesh mesh, Vector3[] normals)
{
public static void SilentlySetNormals(this Mesh mesh, Vector3[] normals)
{
mesh.SetNormals(normals, 0, normals.Length, UPDATE_FLAGS_SILENT);
mesh.SetNormals(normals, 0, normals.Length, UPDATE_FLAGS_SILENT);
mesh.EnableSilentWrites(true);
mesh.SetNormals(normals, 0, normals.Length);
mesh.EnableSilentWrites(false);
mesh.EnableSilentWrites(true);
mesh.SetNormals(normals, 0, normals.Length);
mesh.EnableSilentWrites(false);
}
}
public static void SilentlyRecalculateTangents(this Mesh mesh)
{
public static void SilentlyRecalculateTangents(this Mesh mesh)
{
mesh.RecalculateTangents(UPDATE_FLAGS_SILENT);
mesh.RecalculateTangents(UPDATE_FLAGS_SILENT);
mesh.EnableSilentWrites(true);
mesh.RecalculateTangents();
mesh.EnableSilentWrites(false);
mesh.EnableSilentWrites(true);
mesh.RecalculateTangents();
mesh.EnableSilentWrites(false);
}
}
public static void SilentlyRecalculateNormals(this Mesh mesh)
{
public static void SilentlyRecalculateNormals(this Mesh mesh)
{
mesh.RecalculateNormals(UPDATE_FLAGS_SILENT);
mesh.RecalculateNormals(UPDATE_FLAGS_SILENT);
mesh.EnableSilentWrites(true);
mesh.RecalculateNormals();
mesh.EnableSilentWrites(false);
mesh.EnableSilentWrites(true);
mesh.RecalculateNormals();
mesh.EnableSilentWrites(false);
}
}
public static void SilentlyRecalculateBounds(this Mesh mesh)
{
public static void SilentlyRecalculateBounds(this Mesh mesh)
{
mesh.RecalculateBounds(UPDATE_FLAGS_SILENT);
mesh.RecalculateBounds(UPDATE_FLAGS_SILENT);
mesh.EnableSilentWrites(true);
mesh.RecalculateBounds();
mesh.EnableSilentWrites(false);
mesh.EnableSilentWrites(true);
mesh.RecalculateBounds();
mesh.EnableSilentWrites(false);
}
}
}

183
Runtime/Utility/MeshInstanceBehaviour.cs


using UnityEditor.Experimental.SceneManagement;
#endif
[ExecuteAlways, DisallowMultipleComponent]
public abstract class MeshInstanceBehaviour : MonoBehaviour
namespace Unity.DemoTeam.DigitalHuman
public const string meshInstanceSuffix = "(MeshInstance)";
[ExecuteAlways, DisallowMultipleComponent]
public abstract class MeshInstanceBehaviour : MonoBehaviour
{
public const string meshInstanceSuffix = "(MeshInstance)";
[HideInInspector]
public Mesh meshAsset;
[NonSerialized]
public Mesh meshInstance;
[HideInInspector]
public Mesh meshAsset;
[NonSerialized]
public Mesh meshInstance;
protected virtual void OnMeshInstanceCreated() { }
protected virtual void OnMeshInstanceDeleted() { }
protected virtual void OnMeshInstanceCreated() { }
protected virtual void OnMeshInstanceDeleted() { }
public void EnsureMeshInstance()
{
var smr = GetComponent<SkinnedMeshRenderer>();
if (smr != null)
public void EnsureMeshInstance()
if (smr.sharedMesh == null || (smr.sharedMesh.GetInstanceID() < 0 && smr.sharedMesh != meshInstance))
smr.sharedMesh = meshAsset;
var smr = GetComponent<SkinnedMeshRenderer>();
if (smr != null)
{
if (smr.sharedMesh == null || (smr.sharedMesh.GetInstanceID() < 0 && smr.sharedMesh != meshInstance))
smr.sharedMesh = meshAsset;
if (smr.sharedMesh != null && smr.sharedMesh.GetInstanceID() >= 0)
smr.sharedMesh = EnsureMeshInstanceAux(smr.sharedMesh);
if (smr.sharedMesh != null && smr.sharedMesh.GetInstanceID() >= 0)
smr.sharedMesh = EnsureMeshInstanceAux(smr.sharedMesh);
return;
}
return;
}
var mf = GetComponent<MeshFilter>();
if (mf != null)
{
if (mf.sharedMesh == null || (mf.sharedMesh.GetInstanceID() < 0 && mf.sharedMesh != meshInstance))
mf.sharedMesh = meshAsset;
var mf = GetComponent<MeshFilter>();
if (mf != null)
{
if (mf.sharedMesh == null || (mf.sharedMesh.GetInstanceID() < 0 && mf.sharedMesh != meshInstance))
mf.sharedMesh = meshAsset;
if (mf.sharedMesh != null && mf.sharedMesh.GetInstanceID() >= 0)
mf.sharedMesh = EnsureMeshInstanceAux(mf.sharedMesh);
if (mf.sharedMesh != null && mf.sharedMesh.GetInstanceID() >= 0)
mf.sharedMesh = EnsureMeshInstanceAux(mf.sharedMesh);
return;
return;
}
}
Mesh EnsureMeshInstanceAux(Mesh mesh)
{
if (meshInstance != null)
Mesh EnsureMeshInstanceAux(Mesh mesh)
Mesh.DestroyImmediate(meshInstance);
meshInstance = null;
}
if (meshInstance != null)
{
Mesh.DestroyImmediate(meshInstance);
meshInstance = null;
}
meshAsset = mesh;
meshInstance = Mesh.Instantiate(meshAsset);
meshInstance.name = meshAsset.name + meshInstanceSuffix;
meshInstance.hideFlags = HideFlags.HideAndDontSave & ~HideFlags.DontUnloadUnusedAsset;
meshInstance.MarkDynamic();
meshAsset = mesh;
meshInstance = Mesh.Instantiate(meshAsset);
meshInstance.name = meshAsset.name + meshInstanceSuffix;
meshInstance.hideFlags = HideFlags.HideAndDontSave & ~HideFlags.DontUnloadUnusedAsset;
meshInstance.MarkDynamic();
//Debug.Log("ensureMeshInstance " + meshAsset.name + " -> " + meshInstance.name);
//Debug.Log("ensureMeshInstance " + meshAsset.name + " -> " + meshInstance.name);
OnMeshInstanceCreated();
OnMeshInstanceCreated();
return meshInstance;
}
return meshInstance;
}
public void RemoveMeshInstance()
{
var smr = GetComponent<SkinnedMeshRenderer>();
if (smr != null)
public void RemoveMeshInstance()
if (smr.sharedMesh == null || smr.sharedMesh.GetInstanceID() < 0)
smr.sharedMesh = meshAsset;
var smr = GetComponent<SkinnedMeshRenderer>();
if (smr != null)
{
if (smr.sharedMesh == null || smr.sharedMesh.GetInstanceID() < 0)
smr.sharedMesh = meshAsset;
RemoveMeshInstanceAux();
return;
}
RemoveMeshInstanceAux();
return;
}
var mf = GetComponent<MeshFilter>();
if (mf != null)
{
if (mf.sharedMesh == null || mf.sharedMesh.GetInstanceID() < 0)
mf.sharedMesh = meshAsset;
var mf = GetComponent<MeshFilter>();
if (mf != null)
{
if (mf.sharedMesh == null || mf.sharedMesh.GetInstanceID() < 0)
mf.sharedMesh = meshAsset;
RemoveMeshInstanceAux();
return;
RemoveMeshInstanceAux();
return;
}
}
void RemoveMeshInstanceAux()
{
if (meshInstance != null)
void RemoveMeshInstanceAux()
Mesh.DestroyImmediate(meshInstance);
meshInstance = null;
if (meshInstance != null)
{
Mesh.DestroyImmediate(meshInstance);
meshInstance = null;
}
OnMeshInstanceDeleted();
OnMeshInstanceDeleted();
}
static MeshInstanceBehaviour()
{
PrefabStage.prefabSaving += (GameObject prefab) =>
static MeshInstanceBehaviour()
var prefabStage = PrefabStageUtility.GetCurrentPrefabStage();
if (prefabStage != null)
PrefabStage.prefabSaving += (GameObject prefab) =>
var meshInstanceBehaviours = prefab.GetComponentsInChildren<MeshInstanceBehaviour>(includeInactive: true);
foreach (var meshInstanceBehaviour in meshInstanceBehaviours)
var prefabStage = PrefabStageUtility.GetCurrentPrefabStage();
if (prefabStage != null)
meshInstanceBehaviour.RemoveMeshInstance();
//Debug.Log("reverted mesh instance for " + meshInstanceBehaviour.ToString());
var meshInstanceBehaviours = prefab.GetComponentsInChildren<MeshInstanceBehaviour>(includeInactive: true);
foreach (var meshInstanceBehaviour in meshInstanceBehaviours)
{
meshInstanceBehaviour.RemoveMeshInstance();
//Debug.Log("reverted mesh instance for " + meshInstanceBehaviour.ToString());
}
}
};
};
PrefabStage.prefabSaved += (GameObject prefab) =>
{
var prefabStage = PrefabStageUtility.GetCurrentPrefabStage();
if (prefabStage != null)
PrefabStage.prefabSaved += (GameObject prefab) =>
var meshInstanceBehaviours = prefab.GetComponentsInChildren<MeshInstanceBehaviour>(includeInactive: false);
foreach (var meshInstanceBehaviour in meshInstanceBehaviours)
var prefabStage = PrefabStageUtility.GetCurrentPrefabStage();
if (prefabStage != null)
meshInstanceBehaviour.EnsureMeshInstance();
//Debug.Log("reinstated mesh instance for " + meshInstanceBehaviour.ToString());
var meshInstanceBehaviours = prefab.GetComponentsInChildren<MeshInstanceBehaviour>(includeInactive: false);
foreach (var meshInstanceBehaviour in meshInstanceBehaviours)
{
meshInstanceBehaviour.EnsureMeshInstance();
//Debug.Log("reinstated mesh instance for " + meshInstanceBehaviour.ToString());
}
}
};
};
}
#endif
#endif
}

120
Runtime/Utility/MeshIslands.cs


using System.Collections.Generic;
using UnityEngine;
public class MeshIslands
namespace Unity.DemoTeam.DigitalHuman
public int[] vertexIsland;
public int vertexCount;
public class MeshIslands
{
public int[] vertexIsland;
public int vertexCount;
public LinkedIndexListArray islandVertices;
public int islandCount;
public LinkedIndexListArray islandVertices;
public int islandCount;
public MeshIslands(MeshAdjacency meshAdjacency)
{
LoadFrom(meshAdjacency);
}
public MeshIslands(MeshAdjacency meshAdjacency)
{
LoadFrom(meshAdjacency);
}
public void LoadFrom(MeshAdjacency meshAdjacency)
{
vertexCount = meshAdjacency.vertexCount;
public void LoadFrom(MeshAdjacency meshAdjacency)
{
vertexCount = meshAdjacency.vertexCount;
ArrayUtils.ResizeCheckedIfLessThan(ref vertexIsland, vertexCount);
ArrayUtils.ResizeCheckedIfLessThan(ref vertexIsland, vertexCount);
islandCount = 0;
islandVertices.Allocate(vertexCount, vertexCount);
islandCount = 0;
islandVertices.Allocate(vertexCount, vertexCount);
for (int i = 0; i != vertexCount; i++)
{
vertexIsland[i] = i;
islandVertices.Append(i, i);
}
for (int i = 0; i != vertexCount; i++)
{
vertexIsland[i] = i;
islandVertices.Append(i, i);
}
for (int i = 0; i != vertexCount; i++)
{
foreach (int j in meshAdjacency.vertexVertices[i])
{
int islandA = vertexIsland[i];
int islandB = vertexIsland[j];
if (islandB != islandA)
{
// update vertex->island lookup
foreach (int vertex in islandVertices[islandB])
{
vertexIsland[vertex] = islandA;
}
for (int i = 0; i != vertexCount; i++)
{
foreach (int j in meshAdjacency.vertexVertices[i])
{
int islandA = vertexIsland[i];
int islandB = vertexIsland[j];
if (islandB != islandA)
{
// update vertex->island lookup
foreach (int vertex in islandVertices[islandB])
{
vertexIsland[vertex] = islandA;
}
// move adjacent island
islandVertices.AppendMove(islandA, islandB);
}
}
}
// move adjacent island
islandVertices.AppendMove(islandA, islandB);
}
}
}
// remove empty islands
for (int i = 0; i != vertexCount; i++)
{
if (islandVertices.lists[i].size != 0)
islandVertices.lists[islandCount++] = islandVertices.lists[i];
}
// remove empty islands
for (int i = 0; i != vertexCount; i++)
{
if (islandVertices.lists[i].size != 0)
islandVertices.lists[islandCount++] = islandVertices.lists[i];
}
for (int i = islandCount; i != vertexCount; i++)
{
islandVertices.lists[i].head = -1;
islandVertices.lists[i].size = 0;
}
for (int i = islandCount; i != vertexCount; i++)
{
islandVertices.lists[i].head = -1;
islandVertices.lists[i].size = 0;
}
// update vertex->island lookup
for (int i = 0; i != islandCount; i++)
{
foreach (int vertex in islandVertices[i])
{
vertexIsland[vertex] = i;
}
}
}
// update vertex->island lookup
for (int i = 0; i != islandCount; i++)
{
foreach (int vertex in islandVertices[i])
{
vertexIsland[vertex] = i;
}
}
}
}

33
Runtime/Utility/NativeMesh.cs


using UnityEngine;
using Unity.Collections;
public struct NativeMeshSOA : IDisposable
namespace Unity.DemoTeam.DigitalHuman
public NativeArray<Vector3> vertexPositions;
public NativeArray<Vector2> vertexTexCoords;
public NativeArray<Vector3> vertexNormals;
public int vertexCount;
public struct NativeMeshSOA : IDisposable
{
public NativeArray<Vector3> vertexPositions;
public NativeArray<Vector2> vertexTexCoords;
public NativeArray<Vector3> vertexNormals;
public int vertexCount;
public NativeArray<int> faceIndices;
public int faceIndicesCount;
public NativeArray<int> faceIndices;
public int faceIndicesCount;
public void Dispose()
{
vertexPositions.Dispose();
vertexTexCoords.Dispose();
vertexNormals.Dispose();
vertexCount = 0;
public void Dispose()
{
vertexPositions.Dispose();
vertexTexCoords.Dispose();
vertexNormals.Dispose();
vertexCount = 0;
faceIndices.Dispose();
faceIndicesCount = 0;
faceIndices.Dispose();
faceIndicesCount = 0;
}
}
}

759
Runtime/Utility/NativeMeshObjLoader.cs


using Unity.Collections;
using UnityEngine;
public static class NativeMeshObjLoader
namespace Unity.DemoTeam.DigitalHuman
[Flags]
public enum VertexAttribs
public static class NativeMeshObjLoader
Position = 1 << 0,
TexCoord = 1 << 1,
Normal = 1 << 2,
}
[Flags]
public enum VertexAttribs
{
Position = 1 << 0,
TexCoord = 1 << 1,
Normal = 1 << 2,
}
public enum VertexOrder
{
ByDefinition = 0,
ByReference = 1,
}
public enum VertexOrder
{
ByDefinition = 0,
ByReference = 1,
}
struct InputVertex
{
public uint idxPosition;
public uint idxTexCoord;
public uint idxNormal;
}
struct InputVertex
{
public uint idxPosition;
public uint idxTexCoord;
public uint idxNormal;
}
struct InputFace
{
public InputVertex v0;
public InputVertex v1;
public InputVertex v2;
}
struct InputFace
{
public InputVertex v0;
public InputVertex v1;
public InputVertex v2;
}
public unsafe static NativeMeshSOA Parse(string path, VertexAttribs vertexAttribs = VertexAttribs.Position, VertexOrder vertexOrder = VertexOrder.ByDefinition)
{
public unsafe static NativeMeshSOA Parse(string path, VertexAttribs vertexAttribs = VertexAttribs.Position, VertexOrder vertexOrder = VertexOrder.ByDefinition)
{
Debug.LogFormat("trying {0}", path);
Debug.LogFormat("trying {0}", path);
var text = File.ReadAllText(path);// TODO replace with native variant
var textSize = text.Length;
var text = File.ReadAllText(path);// TODO replace with native variant
var textSize = text.Length;
// measure the data
int numPositions = 0;
int numTexCoords = 0;
int numNormals = 0;
int numFaces = 0;
// measure the data
int numPositions = 0;
int numTexCoords = 0;
int numNormals = 0;
int numFaces = 0;
for (int i = 0; i < text.Length; i++)
{
if (ReadChar(text, ref i, 'v'))
for (int i = 0; i < text.Length; i++)
if (ReadBlank(text, ref i))
{
numPositions++;
}
else if (ReadChar(text, ref i, 't') && ReadBlank(text, ref i))
{
numTexCoords++;
}
else if (ReadChar(text, ref i, 'n') && ReadBlank(text, ref i))
if (ReadChar(text, ref i, 'v'))
numNormals++;
}
}
else if (ReadChar(text, ref i, 'f') && ReadBlankGreedy(text, ref i))
{
int readVerts = 0;
while (ReadDigit(text, ref i))
{
ReadUntilNewlineOrBlank(text, ref i);
ReadBlankGreedy(text, ref i);
readVerts++;
if (ReadBlank(text, ref i))
{
numPositions++;
}
else if (ReadChar(text, ref i, 't') && ReadBlank(text, ref i))
{
numTexCoords++;
}
else if (ReadChar(text, ref i, 'n') && ReadBlank(text, ref i))
{
numNormals++;
}
if (readVerts > 2)
else if (ReadChar(text, ref i, 'f') && ReadBlankGreedy(text, ref i))
numFaces += readVerts - 2;
int readVerts = 0;
while (ReadDigit(text, ref i))
{
ReadUntilNewlineOrBlank(text, ref i);
ReadBlankGreedy(text, ref i);
readVerts++;
}
if (readVerts > 2)
{
numFaces += readVerts - 2;
}
}
ReadUntilNewline(text, ref i);
}
ReadUntilNewline(text, ref i);
}
Debug.LogFormat("-- numPositions = {0}", numPositions);
Debug.LogFormat("-- numTexCoords = {0}", numTexCoords);
Debug.LogFormat("-- numNormals = {0}", numNormals);
Debug.LogFormat("-- numFaces = {0}", numFaces);
Debug.LogFormat("-- numPositions = {0}", numPositions);
Debug.LogFormat("-- numTexCoords = {0}", numTexCoords);
Debug.LogFormat("-- numNormals = {0}", numNormals);
Debug.LogFormat("-- numFaces = {0}", numFaces);
// allocate buffers
var inputPositions = new NativeArray<Vector3>(numPositions, Allocator.Temp, NativeArrayOptions.UninitializedMemory);
var inputTexCoords = new NativeArray<Vector2>(numTexCoords, Allocator.Temp, NativeArrayOptions.UninitializedMemory);
var inputNormals = new NativeArray<Vector3>(numNormals, Allocator.Temp, NativeArrayOptions.UninitializedMemory);
var inputFaces = new NativeArray<InputFace>(numFaces, Allocator.Temp, NativeArrayOptions.UninitializedMemory);
// allocate buffers
var inputPositions = new NativeArray<Vector3>(numPositions, Allocator.Temp, NativeArrayOptions.UninitializedMemory);
var inputTexCoords = new NativeArray<Vector2>(numTexCoords, Allocator.Temp, NativeArrayOptions.UninitializedMemory);
var inputNormals = new NativeArray<Vector3>(numNormals, Allocator.Temp, NativeArrayOptions.UninitializedMemory);
var inputFaces = new NativeArray<InputFace>(numFaces, Allocator.Temp, NativeArrayOptions.UninitializedMemory);
var outputIndicesMax = numFaces * 3;
var outputIndicesLUT = new NativeHashMap<Hash128, int>(outputIndicesMax, Allocator.Temp);
var outputPositions = new NativeArray<Vector3>(outputIndicesMax, Allocator.Temp, NativeArrayOptions.UninitializedMemory);
var outputTexCoords = new NativeArray<Vector2>(outputIndicesMax, Allocator.Temp, NativeArrayOptions.UninitializedMemory);
var outputNormals = new NativeArray<Vector3>(outputIndicesMax, Allocator.Temp, NativeArrayOptions.UninitializedMemory);
var outputIndices = new NativeArray<int>(outputIndicesMax, Allocator.Temp, NativeArrayOptions.UninitializedMemory);
var outputIndicesMax = numFaces * 3;
var outputIndicesLUT = new NativeHashMap<Hash128, int>(outputIndicesMax, Allocator.Temp);
var outputPositions = new NativeArray<Vector3>(outputIndicesMax, Allocator.Temp, NativeArrayOptions.UninitializedMemory);
var outputTexCoords = new NativeArray<Vector2>(outputIndicesMax, Allocator.Temp, NativeArrayOptions.UninitializedMemory);
var outputNormals = new NativeArray<Vector3>(outputIndicesMax, Allocator.Temp, NativeArrayOptions.UninitializedMemory);
var outputIndices = new NativeArray<int>(outputIndicesMax, Allocator.Temp, NativeArrayOptions.UninitializedMemory);
// read the data
numPositions = 0;
numTexCoords = 0;
numNormals = 0;
numFaces = 0;
// read the data
numPositions = 0;
numTexCoords = 0;
numNormals = 0;
numFaces = 0;
for (int i = 0; i < text.Length; i++)
{
if (ReadChar(text, ref i, 'v'))
for (int i = 0; i < text.Length; i++)
if (ReadBlank(text, ref i))
{
Vector3 position;
ReadFloat(text, ref i, out position.x);
position.x *= -1.0f;//TODO remove this hack
ReadBlankGreedy(text, ref i);
ReadFloat(text, ref i, out position.y);
ReadBlankGreedy(text, ref i);
ReadFloat(text, ref i, out position.z);
inputPositions[numPositions++] = position;
}
else if (ReadChar(text, ref i, 't') && ReadBlank(text, ref i))
{
Vector2 texCoord;
ReadFloat(text, ref i, out texCoord.x);
ReadBlankGreedy(text, ref i);
ReadFloat(text, ref i, out texCoord.y);
inputTexCoords[numTexCoords++] = texCoord;
}
else if (ReadChar(text, ref i, 'n') && ReadBlank(text, ref i))
if (ReadChar(text, ref i, 'v'))
Vector3 normal;
ReadFloat(text, ref i, out normal.x);
normal.x *= -1.0f;//TODO remove this hack
ReadBlankGreedy(text, ref i);
ReadFloat(text, ref i, out normal.y);
ReadBlankGreedy(text, ref i);
ReadFloat(text, ref i, out normal.z);
inputNormals[numNormals++] = normal;
if (ReadBlank(text, ref i))
{
Vector3 position;
ReadFloat(text, ref i, out position.x);
position.x *= -1.0f;//TODO remove this hack
ReadBlankGreedy(text, ref i);
ReadFloat(text, ref i, out position.y);
ReadBlankGreedy(text, ref i);
ReadFloat(text, ref i, out position.z);
inputPositions[numPositions++] = position;
}
else if (ReadChar(text, ref i, 't') && ReadBlank(text, ref i))
{
Vector2 texCoord;
ReadFloat(text, ref i, out texCoord.x);
ReadBlankGreedy(text, ref i);
ReadFloat(text, ref i, out texCoord.y);
inputTexCoords[numTexCoords++] = texCoord;
}
else if (ReadChar(text, ref i, 'n') && ReadBlank(text, ref i))
{
Vector3 normal;
ReadFloat(text, ref i, out normal.x);
normal.x *= -1.0f;//TODO remove this hack
ReadBlankGreedy(text, ref i);
ReadFloat(text, ref i, out normal.y);
ReadBlankGreedy(text, ref i);
ReadFloat(text, ref i, out normal.z);
inputNormals[numNormals++] = normal;
}
}
else if (ReadChar(text, ref i, 'f') && ReadBlankGreedy(text, ref i))
{
InputFace face = new InputFace();
if (ReadUInt(text, ref i, out face.v0.idxPosition))
else if (ReadChar(text, ref i, 'f') && ReadBlankGreedy(text, ref i))
ReadChar(text, ref i, '/');
ReadUInt(text, ref i, out face.v0.idxTexCoord);
ReadChar(text, ref i, '/');
ReadUInt(text, ref i, out face.v0.idxNormal);
InputFace face = new InputFace();
if (ReadUInt(text, ref i, out face.v0.idxPosition))
{
ReadChar(text, ref i, '/');
ReadUInt(text, ref i, out face.v0.idxTexCoord);
ReadChar(text, ref i, '/');
ReadUInt(text, ref i, out face.v0.idxNormal);
int readVerts = 1;
while (ReadBlankGreedy(text, ref i))
{
face.v1 = face.v2;
if (ReadUInt(text, ref i, out face.v2.idxPosition))
int readVerts = 1;
while (ReadBlankGreedy(text, ref i))
ReadChar(text, ref i, '/');
ReadUInt(text, ref i, out face.v2.idxTexCoord);
ReadChar(text, ref i, '/');
ReadUInt(text, ref i, out face.v2.idxNormal);
if (++readVerts > 2)
face.v1 = face.v2;
if (ReadUInt(text, ref i, out face.v2.idxPosition))
inputFaces[numFaces++] = face;
ReadChar(text, ref i, '/');
ReadUInt(text, ref i, out face.v2.idxTexCoord);
ReadChar(text, ref i, '/');
ReadUInt(text, ref i, out face.v2.idxNormal);
if (++readVerts > 2)
{
inputFaces[numFaces++] = face;
}
ReadUntilNewline(text, ref i);
ReadUntilNewline(text, ref i);
}
// process the data
int numOutputVertices = 0;
int numOutputIndices = 0;
// process the data
int numOutputVertices = 0;
int numOutputIndices = 0;
if (vertexOrder == VertexOrder.ByReference)
{
for (int i = 0; i != numFaces; i++)
if (vertexOrder == VertexOrder.ByReference)
InputFace face = inputFaces[i];
for (int i = 0; i != numFaces; i++)
{
InputFace face = inputFaces[i];
var key0 = Hash(in face.v0);
var key1 = Hash(in face.v1);
var key2 = Hash(in face.v2);
int idx0, idx1, idx2;
var key0 = Hash(in face.v0);
var key1 = Hash(in face.v1);
var key2 = Hash(in face.v2);
int idx0, idx1, idx2;
if (outputIndicesLUT.TryGetValue(key0, out idx0) == false)
outputIndicesLUT[key0] = idx0 = numOutputVertices++;
if (outputIndicesLUT.TryGetValue(key1, out idx1) == false)
outputIndicesLUT[key1] = idx1 = numOutputVertices++;
if (outputIndicesLUT.TryGetValue(key2, out idx2) == false)
outputIndicesLUT[key2] = idx2 = numOutputVertices++;
if (outputIndicesLUT.TryGetValue(key0, out idx0) == false)
outputIndicesLUT[key0] = idx0 = numOutputVertices++;
if (outputIndicesLUT.TryGetValue(key1, out idx1) == false)
outputIndicesLUT[key1] = idx1 = numOutputVertices++;
if (outputIndicesLUT.TryGetValue(key2, out idx2) == false)
outputIndicesLUT[key2] = idx2 = numOutputVertices++;
outputPositions[idx0] = inputPositions[(int)face.v0.idxPosition - 1];
outputPositions[idx1] = inputPositions[(int)face.v1.idxPosition - 1];
outputPositions[idx2] = inputPositions[(int)face.v2.idxPosition - 1];
outputPositions[idx0] = inputPositions[(int)face.v0.idxPosition - 1];
outputPositions[idx1] = inputPositions[(int)face.v1.idxPosition - 1];
outputPositions[idx2] = inputPositions[(int)face.v2.idxPosition - 1];
outputTexCoords[idx0] = inputTexCoords[(int)face.v0.idxTexCoord - 1];
outputTexCoords[idx1] = inputTexCoords[(int)face.v1.idxTexCoord - 1];
outputTexCoords[idx2] = inputTexCoords[(int)face.v2.idxTexCoord - 1];
outputTexCoords[idx0] = inputTexCoords[(int)face.v0.idxTexCoord - 1];
outputTexCoords[idx1] = inputTexCoords[(int)face.v1.idxTexCoord - 1];
outputTexCoords[idx2] = inputTexCoords[(int)face.v2.idxTexCoord - 1];
outputNormals[idx0] = inputNormals[(int)face.v0.idxNormal - 1];
outputNormals[idx1] = inputNormals[(int)face.v1.idxNormal - 1];
outputNormals[idx2] = inputNormals[(int)face.v2.idxNormal - 1];
outputNormals[idx0] = inputNormals[(int)face.v0.idxNormal - 1];
outputNormals[idx1] = inputNormals[(int)face.v1.idxNormal - 1];
outputNormals[idx2] = inputNormals[(int)face.v2.idxNormal - 1];
outputIndices[numOutputIndices++] = idx0;
outputIndices[numOutputIndices++] = idx1;
outputIndices[numOutputIndices++] = idx2;
outputIndices[numOutputIndices++] = idx0;
outputIndices[numOutputIndices++] = idx1;
outputIndices[numOutputIndices++] = idx2;
}
}
else if (vertexOrder == VertexOrder.ByDefinition)
{
numOutputVertices = numPositions;
else if (vertexOrder == VertexOrder.ByDefinition)
{
numOutputVertices = numPositions;
var indexVisited = new NativeArray<bool>(numPositions, Allocator.Temp, NativeArrayOptions.ClearMemory);
var indexVisited = new NativeArray<bool>(numPositions, Allocator.Temp, NativeArrayOptions.ClearMemory);
for (int i = 0; i != numFaces; i++)
{
InputFace face = inputFaces[i];
for (int i = 0; i != numFaces; i++)
{
InputFace face = inputFaces[i];
var key0 = Hash(in face.v0);
var key1 = Hash(in face.v1);
var key2 = Hash(in face.v2);
int idx0, idx1, idx2;
var key0 = Hash(in face.v0);
var key1 = Hash(in face.v1);
var key2 = Hash(in face.v2);
int idx0, idx1, idx2;
if (outputIndicesLUT.TryGetValue(key0, out idx0) == false)
{
if (indexVisited[idx0 = (int)face.v0.idxPosition - 1])
outputIndicesLUT[key0] = idx0 = numOutputVertices++;
else
outputIndicesLUT[key0] = idx0;
}
if (outputIndicesLUT.TryGetValue(key0, out idx0) == false)
{
if (indexVisited[idx0 = (int)face.v0.idxPosition - 1])
outputIndicesLUT[key0] = idx0 = numOutputVertices++;
else
outputIndicesLUT[key0] = idx0;
}
if (outputIndicesLUT.TryGetValue(key1, out idx1) == false)
{
if (indexVisited[idx1 = (int)face.v1.idxPosition - 1])
outputIndicesLUT[key1] = idx1 = numOutputVertices++;
else
outputIndicesLUT[key1] = idx1;
}
if (outputIndicesLUT.TryGetValue(key1, out idx1) == false)
{
if (indexVisited[idx1 = (int)face.v1.idxPosition - 1])
outputIndicesLUT[key1] = idx1 = numOutputVertices++;
else
outputIndicesLUT[key1] = idx1;
}
if (outputIndicesLUT.TryGetValue(key2, out idx2) == false)
{
if (indexVisited[idx2 = (int)face.v2.idxPosition - 1])
outputIndicesLUT[key2] = idx2 = numOutputVertices++;
else
outputIndicesLUT[key2] = idx2;
}
if (outputIndicesLUT.TryGetValue(key2, out idx2) == false)
{
if (indexVisited[idx2 = (int)face.v2.idxPosition - 1])
outputIndicesLUT[key2] = idx2 = numOutputVertices++;
else
outputIndicesLUT[key2] = idx2;
}
indexVisited[(int)face.v0.idxPosition - 1] = true;
indexVisited[(int)face.v1.idxPosition - 1] = true;
indexVisited[(int)face.v2.idxPosition - 1] = true;
indexVisited[(int)face.v0.idxPosition - 1] = true;
indexVisited[(int)face.v1.idxPosition - 1] = true;
indexVisited[(int)face.v2.idxPosition - 1] = true;
outputPositions[idx0] = inputPositions[(int)face.v0.idxPosition - 1];
outputPositions[idx1] = inputPositions[(int)face.v1.idxPosition - 1];
outputPositions[idx2] = inputPositions[(int)face.v2.idxPosition - 1];
outputPositions[idx0] = inputPositions[(int)face.v0.idxPosition - 1];
outputPositions[idx1] = inputPositions[(int)face.v1.idxPosition - 1];
outputPositions[idx2] = inputPositions[(int)face.v2.idxPosition - 1];
outputTexCoords[idx0] = inputTexCoords[(int)face.v0.idxTexCoord - 1];
outputTexCoords[idx1] = inputTexCoords[(int)face.v1.idxTexCoord - 1];
outputTexCoords[idx2] = inputTexCoords[(int)face.v2.idxTexCoord - 1];
outputTexCoords[idx0] = inputTexCoords[(int)face.v0.idxTexCoord - 1];
outputTexCoords[idx1] = inputTexCoords[(int)face.v1.idxTexCoord - 1];
outputTexCoords[idx2] = inputTexCoords[(int)face.v2.idxTexCoord - 1];
outputNormals[idx0] = inputNormals[(int)face.v0.idxNormal - 1];
outputNormals[idx1] = inputNormals[(int)face.v1.idxNormal - 1];
outputNormals[idx2] = inputNormals[(int)face.v2.idxNormal - 1];
outputNormals[idx0] = inputNormals[(int)face.v0.idxNormal - 1];
outputNormals[idx1] = inputNormals[(int)face.v1.idxNormal - 1];
outputNormals[idx2] = inputNormals[(int)face.v2.idxNormal - 1];
outputIndices[numOutputIndices++] = idx0;
outputIndices[numOutputIndices++] = idx1;
outputIndices[numOutputIndices++] = idx2;
}
outputIndices[numOutputIndices++] = idx0;
outputIndices[numOutputIndices++] = idx1;
outputIndices[numOutputIndices++] = idx2;
indexVisited.Dispose();
indexVisited.Dispose();
}
Debug.LogFormat("output vertex count = {0}", numOutputVertices);
Debug.LogFormat("output index count = {0}", numOutputIndices);
Debug.LogFormat("output vertex count = {0}", numOutputVertices);
Debug.LogFormat("output index count = {0}", numOutputIndices);
// copy to container
NativeMeshSOA mesh = new NativeMeshSOA()
{
vertexPositions = new NativeArray<Vector3>(numOutputVertices, Allocator.Persistent, NativeArrayOptions.UninitializedMemory),
vertexTexCoords = new NativeArray<Vector2>(numOutputVertices, Allocator.Persistent, NativeArrayOptions.UninitializedMemory),
vertexNormals = new NativeArray<Vector3>(numOutputVertices, Allocator.Persistent, NativeArrayOptions.UninitializedMemory),
vertexCount = numOutputVertices,
// copy to container
NativeMeshSOA mesh = new NativeMeshSOA()
{
vertexPositions = new NativeArray<Vector3>(numOutputVertices, Allocator.Persistent, NativeArrayOptions.UninitializedMemory),
vertexTexCoords = new NativeArray<Vector2>(numOutputVertices, Allocator.Persistent, NativeArrayOptions.UninitializedMemory),
vertexNormals = new NativeArray<Vector3>(numOutputVertices, Allocator.Persistent, NativeArrayOptions.UninitializedMemory),
vertexCount = numOutputVertices,
faceIndices = new NativeArray<int>(numOutputIndices, Allocator.Persistent, NativeArrayOptions.UninitializedMemory),
faceIndicesCount = numOutputIndices,
};
faceIndices = new NativeArray<int>(numOutputIndices, Allocator.Persistent, NativeArrayOptions.UninitializedMemory),
faceIndicesCount = numOutputIndices,
};
NativeArray<Vector3>.Copy(outputPositions, mesh.vertexPositions, numOutputVertices);
NativeArray<Vector2>.Copy(outputTexCoords, mesh.vertexTexCoords, numOutputVertices);
NativeArray<Vector3>.Copy(outputNormals, mesh.vertexNormals, numOutputVertices);
NativeArray<int>.Copy(outputIndices, mesh.faceIndices, numOutputIndices);
NativeArray<Vector3>.Copy(outputPositions, mesh.vertexPositions, numOutputVertices);
NativeArray<Vector2>.Copy(outputTexCoords, mesh.vertexTexCoords, numOutputVertices);
NativeArray<Vector3>.Copy(outputNormals, mesh.vertexNormals, numOutputVertices);
NativeArray<int>.Copy(outputIndices, mesh.faceIndices, numOutputIndices);
// free buffers
inputPositions.Dispose();
inputTexCoords.Dispose();
inputNormals.Dispose();
inputFaces.Dispose();
outputIndicesLUT.Dispose();
outputPositions.Dispose();
outputTexCoords.Dispose();
outputNormals.Dispose();
outputIndices.Dispose();
// free buffers
inputPositions.Dispose();
inputTexCoords.Dispose();
inputNormals.Dispose();
inputFaces.Dispose();
// done
return mesh;
}
outputIndicesLUT.Dispose();
outputPositions.Dispose();
outputTexCoords.Dispose();
outputNormals.Dispose();
outputIndices.Dispose();
static Hash128 Hash(in InputVertex v)
{
return new Hash128(v.idxPosition, v.idxTexCoord, v.idxNormal, 0);
}
// done
return mesh;
}
static bool ReadChar(string text, ref int index, char value)
{
if (text[index] == value)
static Hash128 Hash(in InputVertex v)
index++;
return true;
return new Hash128(v.idxPosition, v.idxTexCoord, v.idxNormal, 0);
else
static bool ReadChar(string text, ref int index, char value)
return false;
if (text[index] == value)
{
index++;
return true;
}
else
{
return false;
}
}
static bool ReadDigit(string text, ref int index)
{
if (text[index] >= '0' && text[index] <= '9')
static bool ReadDigit(string text, ref int index)
index++;
return true;
if (text[index] >= '0' && text[index] <= '9')
{
index++;
return true;
}
else
{
return false;
}
else
static bool ReadUInt(string text, ref int index, out uint value)
return false;
unsafe
{
const uint READ_BASE = '0';
const uint READ_FAIL = uint.MaxValue;
const int READ_MAX = 32;
char* readBuf = stackalloc char[READ_MAX];
uint readPos = 0;
if (text[index] >= '0' && text[index] <= '9')
{
readBuf[readPos++] = text[index++];
while (text[index] >= '0' && text[index] <= '9')
{
if (readPos == READ_MAX)
{
value = READ_FAIL;
return false;
}
readBuf[readPos++] = text[index++];
}
value = readBuf[0] - READ_BASE;
for (uint i = 1; i != readPos; i++)
{
value = (value * 10) + (readBuf[i] - READ_BASE);
}
return true;
}
else
{
value = READ_FAIL;
return false;
}
}
}
static bool ReadUInt(string text, ref int index, out uint value)
{
unsafe
//static int readfloat = 0;
static bool ReadFloat(string text, ref int index, out float value)
const uint READ_BASE = '0';
const uint READ_FAIL = uint.MaxValue;
const int READ_MAX = 32;
uint valueInt = 0u;
uint valueFrac = 0u;
char* readBuf = stackalloc char[READ_MAX];
uint readPos = 0;
bool readSign = ReadChar(text, ref index, '-');
bool readInt = ReadUInt(text, ref index, out valueInt);
if (text[index] >= '0' && text[index] <= '9')
int indexFrac = index;
bool readFrac = ReadChar(text, ref index, '.') && ReadUInt(text, ref index, out valueFrac);
int countFrac = index - indexFrac;
if (readInt || readFrac)
readBuf[readPos++] = text[index++];
while (text[index] >= '0' && text[index] <= '9')
if (readFrac && valueFrac > 0)
if (readPos == READ_MAX)
{
value = READ_FAIL;
return false;
}
readBuf[readPos++] = text[index++];
value = (float)valueFrac;
value *= Mathf.Pow(10.0f, -(countFrac - 1));
value = readBuf[0] - READ_BASE;
for (uint i = 1; i != readPos; i++)
else
value = (value * 10) + (readBuf[i] - READ_BASE);
value = 0.0f;
}
if (readInt && valueInt > 0)
{
value = ((float)valueInt + value);
}
if (readSign)
{
value = -value;
//readfloat++;
//if (readfloat == 1)
//{
// Debug.Log("read float (" + readfloat + ")");
// Debug.Log("-- readSign " + readSign);
// Debug.Log("-- readInt " + readInt);
// Debug.Log("-- readFrac " + readFrac);
// Debug.Log("-- valueInt " + valueInt);
// Debug.Log("-- valueFrac " + valueFrac);
// Debug.Log("read float VALUE " + value);
//}
value = READ_FAIL;
value = float.NaN;
}
//static int readfloat = 0;
static bool ReadFloat(string text, ref int index, out float value)
{
uint valueInt = 0u;
uint valueFrac = 0u;
bool readSign = ReadChar(text, ref index, '-');
bool readInt = ReadUInt(text, ref index, out valueInt);
int indexFrac = index;
bool readFrac = ReadChar(text, ref index, '.') && ReadUInt(text, ref index, out valueFrac);
int countFrac = index - indexFrac;
if (readInt || readFrac)
static bool ReadBlank(string text, ref int index)
if (readFrac && valueFrac > 0)
if (text[index] == ' ' || text[index] == '\t')
value = (float)valueFrac;
value *= Mathf.Pow(10.0f, -(countFrac - 1));
index++;
return true;
value = 0.0f;
return false;
if (readInt && valueInt > 0)
}
static bool ReadBlankGreedy(string text, ref int index)
{
if (text[index] == ' ' || text[index] == '\t')
value = ((float)valueInt + value);
index++;
while (text[index] == ' ' || text[index] == '\t')
{
index++;
}
return true;
if (readSign)
else
value = -value;
return false;
//readfloat++;
//if (readfloat == 1)
//{
// Debug.Log("read float (" + readfloat + ")");
// Debug.Log("-- readSign " + readSign);
// Debug.Log("-- readInt " + readInt);
// Debug.Log("-- readFrac " + readFrac);
// Debug.Log("-- valueInt " + valueInt);
// Debug.Log("-- valueFrac " + valueFrac);
// Debug.Log("read float VALUE " + value);
//}
return true;
}
else
{
value = float.NaN;
return false;
}
static bool ReadBlank(string text, ref int index)
{
if (text[index] == ' ' || text[index] == '\t')
{
index++;
return true;
}
else
static bool ReadUntilNewline(string text, ref int index)
return false;
}
}
static bool ReadBlankGreedy(string text, ref int index)
{
if (text[index] == ' ' || text[index] == '\t')
{
index++;
while (text[index] == ' ' || text[index] == '\t')
if (text[index] != '\n')
while (text[index] != '\n')
{
index++;
}
return true;
return true;
}
else
{
return false;
else
{
return false;
}
}
static bool ReadUntilNewline(string text, ref int index)
{
if (text[index] != '\n')
static bool ReadUntilNewlineOrBlank(string text, ref int index)
index++;
while (text[index] != '\n')
if (text[index] != '\n' && text[index] != ' ' && text[index] != '\t')
while (text[index] != '\n' && text[index] != ' ' && text[index] != '\t')
{
index++;
}
return true;
return true;
}
else
{
return false;
}
}
static bool ReadUntilNewlineOrBlank(string text, ref int index)
{
if (text[index] != '\n' && text[index] != ' ' && text[index] != '\t')
{
index++;
while (text[index] != '\n' && text[index] != ' ' && text[index] != '\t')
else
index++;
return false;
return true;
}
else
{
return false;
}
}
}

47
Runtime/Utility/UnsafeArrayBool.cs


using Unity.Collections;
using Unity.Collections.LowLevel.Unsafe;
public unsafe struct UnsafeArrayBool : IDisposable
namespace Unity.DemoTeam.DigitalHuman
public bool* val;
private long valSize;
public unsafe struct UnsafeArrayBool : IDisposable
{
public bool* val;
private long valSize;
private Allocator allocator;
private Allocator allocator;
public UnsafeArrayBool(int capacity, Allocator allocator = Allocator.Temp)
{
this.val = (bool*)UnsafeUtility.Malloc(sizeof(bool) * capacity, 1, allocator);
this.valSize = sizeof(bool) * capacity;
public UnsafeArrayBool(int capacity, Allocator allocator = Allocator.Temp)
{
this.val = (bool*)UnsafeUtility.Malloc(sizeof(bool) * capacity, 1, allocator);
this.valSize = sizeof(bool) * capacity;
this.allocator = allocator;
}
this.allocator = allocator;
}
public void Clear(bool value)
{
if (value == false)
UnsafeUtility.MemClear(val, valSize);
else
UnsafeUtility.MemCpyReplicate(val, &value, sizeof(bool), (int)valSize / sizeof(bool));
}
public void Clear(bool value)
{
if (value == false)
UnsafeUtility.MemClear(val, valSize);
else
UnsafeUtility.MemCpyReplicate(val, &value, sizeof(bool), (int)valSize / sizeof(bool));
}
public void Dispose()
{
if (val != null)
UnsafeUtility.Free(val, allocator);
}
public void Dispose()
{
if (val != null)
UnsafeUtility.Free(val, allocator);
}
}
}

47
Runtime/Utility/UnsafeArrayFloat.cs


using Unity.Collections;
using Unity.Collections.LowLevel.Unsafe;
public unsafe struct UnsafeArrayFloat : IDisposable
namespace Unity.DemoTeam.DigitalHuman
public float* val;
private long valSize;
public unsafe struct UnsafeArrayFloat : IDisposable
{
public float* val;
private long valSize;
private Allocator allocator;
private Allocator allocator;
public UnsafeArrayFloat(int capacity, Allocator allocator = Allocator.Temp)
{
this.val = (float*)UnsafeUtility.Malloc(sizeof(float) * capacity, 1, allocator);
this.valSize = sizeof(float) * capacity;
public UnsafeArrayFloat(int capacity, Allocator allocator = Allocator.Temp)
{
this.val = (float*)UnsafeUtility.Malloc(sizeof(float) * capacity, 1, allocator);
this.valSize = sizeof(float) * capacity;
this.allocator = allocator;
}
this.allocator = allocator;
}
public void Clear(float value)
{
if (value == 0.0f)
UnsafeUtility.MemClear(val, valSize);
else
UnsafeUtility.MemCpyReplicate(val, &value, sizeof(float), (int)valSize / sizeof(float));
}
public void Clear(float value)
{
if (value == 0.0f)
UnsafeUtility.MemClear(val, valSize);
else
UnsafeUtility.MemCpyReplicate(val, &value, sizeof(float), (int)valSize / sizeof(float));
}
public void Dispose()
{
if (val != null)
UnsafeUtility.Free(val, allocator);
}
public void Dispose()
{
if (val != null)
UnsafeUtility.Free(val, allocator);
}
}
}

47
Runtime/Utility/UnsafeArrayInt.cs


using Unity.Collections;
using Unity.Collections.LowLevel.Unsafe;
public unsafe struct UnsafeArrayInt : IDisposable
namespace Unity.DemoTeam.DigitalHuman
public int* val;
private long valSize;
public unsafe struct UnsafeArrayInt : IDisposable
{
public int* val;
private long valSize;
private Allocator allocator;
private Allocator allocator;
public UnsafeArrayInt(int capacity, Allocator allocator = Allocator.Temp)
{
this.val = (int*)UnsafeUtility.Malloc(sizeof(int) * capacity, 1, allocator);
this.valSize = sizeof(int) * capacity;
public UnsafeArrayInt(int capacity, Allocator allocator = Allocator.Temp)
{
this.val = (int*)UnsafeUtility.Malloc(sizeof(int) * capacity, 1, allocator);
this.valSize = sizeof(int) * capacity;
this.allocator = allocator;
}
this.allocator = allocator;
}
public void Clear(int value)
{
if (value == 0)
UnsafeUtility.MemClear(val, valSize);
else
UnsafeUtility.MemCpyReplicate(val, &value, sizeof(int), (int)valSize / sizeof(int));
}
public void Clear(int value)
{
if (value == 0)
UnsafeUtility.MemClear(val, valSize);
else
UnsafeUtility.MemCpyReplicate(val, &value, sizeof(int), (int)valSize / sizeof(int));
}
public void Dispose()
{
if (val != null)
UnsafeUtility.Free(val, allocator);
}
public void Dispose()
{
if (val != null)
UnsafeUtility.Free(val, allocator);
}
}
}

47
Runtime/Utility/UnsafeArrayULong.cs


using Unity.Collections;
using Unity.Collections.LowLevel.Unsafe;
public unsafe struct UnsafeArrayULong : IDisposable
namespace Unity.DemoTeam.DigitalHuman
public ulong* val;
private long valSize;
public unsafe struct UnsafeArrayULong : IDisposable
{
public ulong* val;
private long valSize;
private Allocator allocator;
private Allocator allocator;
public UnsafeArrayULong(int capacity, Allocator allocator = Allocator.Temp)
{
this.val = (ulong*)UnsafeUtility.Malloc(sizeof(ulong) * capacity, 1, allocator);
this.valSize = sizeof(ulong) * capacity;
public UnsafeArrayULong(int capacity, Allocator allocator = Allocator.Temp)
{
this.val = (ulong*)UnsafeUtility.Malloc(sizeof(ulong) * capacity, 1, allocator);
this.valSize = sizeof(ulong) * capacity;
this.allocator = allocator;
}
this.allocator = allocator;
}
public void Clear(ulong value)
{
if (value == 0uL)
UnsafeUtility.MemClear(val, valSize);
else
UnsafeUtility.MemCpyReplicate(val, &value, sizeof(ulong), (int)valSize / sizeof(ulong));
}
public void Clear(ulong value)
{
if (value == 0uL)
UnsafeUtility.MemClear(val, valSize);
else
UnsafeUtility.MemCpyReplicate(val, &value, sizeof(ulong), (int)valSize / sizeof(ulong));
}
public void Dispose()
{
if (val != null)
UnsafeUtility.Free(val, allocator);
}
public void Dispose()
{
if (val != null)
UnsafeUtility.Free(val, allocator);
}
}
}

47
Runtime/Utility/UnsafeArrayVector3.cs


using Unity.Collections;
using Unity.Collections.LowLevel.Unsafe;
public unsafe struct UnsafeArrayVector3 : IDisposable
namespace Unity.DemoTeam.DigitalHuman
public Vector3* val;
private long valSize;
public unsafe struct UnsafeArrayVector3 : IDisposable
{
public Vector3* val;
private long valSize;
private Allocator allocator;
private Allocator allocator;
public UnsafeArrayVector3(int capacity, Allocator allocator = Allocator.Temp)
{
this.val = (Vector3*)UnsafeUtility.Malloc(sizeof(Vector3) * capacity, 1, allocator);
this.valSize = sizeof(Vector3) * capacity;
public UnsafeArrayVector3(int capacity, Allocator allocator = Allocator.Temp)
{
this.val = (Vector3*)UnsafeUtility.Malloc(sizeof(Vector3) * capacity, 1, allocator);
this.valSize = sizeof(Vector3) * capacity;
this.allocator = allocator;
}
this.allocator = allocator;
}
public void Clear(Vector3 value)
{
if (value.x == 0.0f && value.y == 0.0f && value.z == 0.0f)
UnsafeUtility.MemClear(val, valSize);
else
UnsafeUtility.MemCpyReplicate(val, &value, sizeof(Vector3), (int)valSize / sizeof(Vector3));
}
public void Clear(Vector3 value)
{
if (value.x == 0.0f && value.y == 0.0f && value.z == 0.0f)
UnsafeUtility.MemClear(val, valSize);
else
UnsafeUtility.MemCpyReplicate(val, &value, sizeof(Vector3), (int)valSize / sizeof(Vector3));
}
public void Dispose()
{
if (val != null)
UnsafeUtility.Free(val, allocator);
}
public void Dispose()
{
if (val != null)
UnsafeUtility.Free(val, allocator);
}
}
}

113
Runtime/Utility/UnsafeBFS.cs


using System;
using Unity.Collections;
public unsafe struct UnsafeBFS : IDisposable
namespace Unity.DemoTeam.DigitalHuman
public int position;
public int depth;
public unsafe struct UnsafeBFS : IDisposable
{
public int position;
public int depth;
private UnsafeArrayULong pending;// pending[i] == (depth << 32) | position
private int pendingHead;
private int pendingTail;
private UnsafeArrayULong pending;// pending[i] == (depth << 32) | position
private int pendingHead;
private int pendingTail;
private UnsafeArrayBool visited;
private UnsafeArrayBool visited;
public UnsafeBFS(int nodeCount, Allocator allocator = Allocator.Temp)
{
this.position = -1;
this.depth = -1;
public UnsafeBFS(int nodeCount, Allocator allocator = Allocator.Temp)
{
this.position = -1;
this.depth = -1;
this.pending = new UnsafeArrayULong(nodeCount, allocator);
this.pendingHead = 0;
this.pendingTail = 0;
this.pending = new UnsafeArrayULong(nodeCount, allocator);
this.pendingHead = 0;
this.pendingTail = 0;
this.visited = new UnsafeArrayBool(nodeCount, allocator);
this.visited.Clear(false);
}
this.visited = new UnsafeArrayBool(nodeCount, allocator);
this.visited.Clear(false);
}
public void Dispose()
{
pending.Dispose();
visited.Dispose();
}
public void Dispose()
{
pending.Dispose();
visited.Dispose();
}
public void Clear()
{
visited.Clear(false);
}
public void Clear()
{
visited.Clear(false);
}
public void Ignore(int node)
{
visited.val[node] = true;
}
public void Ignore(int node)
{
visited.val[node] = true;
}
public void Insert(int node)
{
if (visited.val[node])
return;
public void Insert(int node)
{
if (visited.val[node])
return;
ulong pack_position = (ulong)node;
ulong pack_depth = (ulong)(depth + 1) << 32;
ulong pack_position = (ulong)node;
ulong pack_depth = (ulong)(depth + 1) << 32;
pending.val[pendingTail++] = pack_depth | pack_position;
visited.val[node] = true;
}
pending.val[pendingTail++] = pack_depth | pack_position;
visited.val[node] = true;
}
public bool MoveNext()
{
if (pendingHead != pendingTail)
{
ulong packed = pending.val[pendingHead++];
position = (int)(packed & 0xffffffffuL);
depth = (int)(packed >> 32);
return true;
}
else
{
position = -1;
depth = -1;
return false;
}
}
public bool MoveNext()
{
if (pendingHead != pendingTail)
{
ulong packed = pending.val[pendingHead++];
position = (int)(packed & 0xffffffffuL);
depth = (int)(packed >> 32);
return true;
}
else
{
position = -1;
depth = -1;
return false;
}
}
}
}

109
Runtime/Utility/UnsafeDFS.cs


using System;
using Unity.Collections;
public unsafe struct UnsafeDFS : IDisposable
namespace Unity.DemoTeam.DigitalHuman
public int position;
public int depth;
public unsafe struct UnsafeDFS : IDisposable
{
public int position;
public int depth;
private UnsafeArrayULong pending;// pending[i] == (depth << 32) | position
private int pendingHead;
private UnsafeArrayULong pending;// pending[i] == (depth << 32) | position
private int pendingHead;
private UnsafeArrayBool visited;
private UnsafeArrayBool visited;
public UnsafeDFS(int nodeCount, Allocator allocator = Allocator.Temp)
{
this.position = -1;
this.depth = -1;
public UnsafeDFS(int nodeCount, Allocator allocator = Allocator.Temp)
{
this.position = -1;
this.depth = -1;
this.pending = new UnsafeArrayULong(nodeCount, allocator);
this.pendingHead = 0;
this.pending = new UnsafeArrayULong(nodeCount, allocator);
this.pendingHead = 0;
this.visited = new UnsafeArrayBool(nodeCount, allocator);
this.visited.Clear(false);
}
this.visited = new UnsafeArrayBool(nodeCount, allocator);
this.visited.Clear(false);
}
public void Dispose()
{
pending.Dispose();
visited.Dispose();
}
public void Dispose()
{
pending.Dispose();
visited.Dispose();
}
public void Clear()
{
visited.Clear(false);
}
public void Clear()
{
visited.Clear(false);
}
public void Ignore(int node)
{
visited.val[node] = true;
}
public void Ignore(int node)
{
visited.val[node] = true;
}
public void Insert(int node)
{
if (visited.val[node])
return;
public void Insert(int node)
{
if (visited.val[node])
return;
ulong pack_position = (ulong)node;
ulong pack_depth = (ulong)(depth + 1) << 32;
ulong pack_position = (ulong)node;
ulong pack_depth = (ulong)(depth + 1) << 32;
pending.val[++pendingHead] = pack_depth | pack_position;
visited.val[node] = true;
}
pending.val[++pendingHead] = pack_depth | pack_position;
visited.val[node] = true;
}
public bool MoveNext()
{
if (pendingHead > 0)
{
ulong packed = pending.val[--pendingHead];
position = (int)(packed & 0xffffffffuL);
depth = (int)(packed >> 32);
return true;
}
else
{
position = -1;
depth = -1;
return false;
}
}
public bool MoveNext()
{
if (pendingHead > 0)
{
ulong packed = pending.val[--pendingHead];
position = (int)(packed & 0xffffffffuL);
depth = (int)(packed >> 32);
return true;
}
else
{
position = -1;
depth = -1;
return false;
}
}
}
}

622
Runtime/Utility/KdTree3.cs


using Unity.Jobs;
using Unity.Burst;
[Serializable]
public class KdTree3
namespace Unity.DemoTeam.DigitalHuman
public struct Node
{
public int point;
public int stepL;
public int stepR;
}
[Serializable]
public class KdTree3
{
public struct Node
{
public int point;
public int stepL;
public int stepR;
}
public struct Point3
{
public float x;// note: 'x' MUST be first field
public float y;
public float z;
public int index;
}
public struct Point3
{
public float x;// note: 'x' MUST be first field
public float y;
public float z;
public int index;
}
public int size;
public Node[] nodes;
public Point3[] points;
public int size;
public Node[] nodes;
public Point3[] points;
public KdTree3(Vector3[] pointCloud, int pointCount)
{
BuildFrom(pointCloud, pointCount);
}
public KdTree3(Vector3[] pointCloud, int pointCount)
{
BuildFrom(pointCloud, pointCount);
}
//----------------------
// kd-tree construction
//----------------------
// kd-tree construction
public void BuildFrom(Vector3[] pointBuffer, int pointCount)
{
ArrayUtils.ResizeCheckedIfLessThan(ref this.nodes, pointCount);
ArrayUtils.ResizeCheckedIfLessThan(ref this.points, pointCount);
public void BuildFrom(Vector3[] pointBuffer, int pointCount)
{
ArrayUtils.ResizeCheckedIfLessThan(ref this.nodes, pointCount);
ArrayUtils.ResizeCheckedIfLessThan(ref this.points, pointCount);
Profiler.BeginSample("kd-prep");
for (int i = 0; i != pointCount; i++)
{
this.points[i].x = pointBuffer[i].x;
this.points[i].y = pointBuffer[i].y;
this.points[i].z = pointBuffer[i].z;
this.points[i].index = i;
}
Profiler.EndSample();
Profiler.BeginSample("kd-prep");
for (int i = 0; i != pointCount; i++)
{
this.points[i].x = pointBuffer[i].x;
this.points[i].y = pointBuffer[i].y;
this.points[i].z = pointBuffer[i].z;
this.points[i].index = i;
}
Profiler.EndSample();
Profiler.BeginSample("kd-build");
if (pointCount > 0)
{
unsafe
{
int numThreads = SystemInfo.processorCount;
//Debug.Log("numThreads = " + numThreads);
Profiler.BeginSample("kd-build");
if (pointCount > 0)
{
unsafe
{
int numThreads = SystemInfo.processorCount;
//Debug.Log("numThreads = " + numThreads);
int schedLeaves = Mathf.NextPowerOfTwo(numThreads) * 2;
int schedNodes = BalancedBinaryTreeInfo.NodeCountFromLeafCount(schedLeaves);
int schedDepth = BalancedBinaryTreeInfo.DepthFromLeafCount(schedLeaves) - 1;
int schedLeaves = Mathf.NextPowerOfTwo(numThreads) * 2;
int schedNodes = BalancedBinaryTreeInfo.NodeCountFromLeafCount(schedLeaves);
int schedDepth = BalancedBinaryTreeInfo.DepthFromLeafCount(schedLeaves) - 1;
//Debug.Log("numThreads=" + numThreads + ", schedLeaves=" + schedLeaves + ", schedNodes=" + schedNodes + ", schedDepth=" + schedDepth);
//Debug.Log("numThreads=" + numThreads + ", schedLeaves=" + schedLeaves + ", schedNodes=" + schedNodes + ", schedDepth=" + schedDepth);
var jobArray = (JobHandle*)UnsafeUtility.Malloc(sizeof(JobHandle) * schedNodes, 1, Allocator.Temp);
var jobSched = jobArray;
var jobArray = (JobHandle*)UnsafeUtility.Malloc(sizeof(JobHandle) * schedNodes, 1, Allocator.Temp);
var jobSched = jobArray;
fixed (Node* __node = this.nodes)
fixed (Point3* __points = this.points)
{
ScheduleNode(ref jobSched, null, __node, __points, 0, pointCount, 0, schedDepth);
fixed (Node* __node = this.nodes)
fixed (Point3* __points = this.points)
{
ScheduleNode(ref jobSched, null, __node, __points, 0, pointCount, 0, schedDepth);
JobHandle.ScheduleBatchedJobs();
JobHandle.ScheduleBatchedJobs();
long jobCount = jobSched - jobArray;
for (long i = 0; i != jobCount; i++)
{
jobArray[i].Complete();
}
}
long jobCount = jobSched - jobArray;
for (long i = 0; i != jobCount; i++)
{
jobArray[i].Complete();
}
}
UnsafeUtility.Free(jobArray, Allocator.Temp);
}
}
Profiler.EndSample();
UnsafeUtility.Free(jobArray, Allocator.Temp);
}
}
Profiler.EndSample();
size = pointCount;
}
size = pointCount;
}
unsafe static void ScheduleNode(ref JobHandle* jobSched, JobHandle* jobDepends, Node* node, Point3* points, int offset, int length, int depth, int depthSingleThreaded)
{
// pick median
int median = length >> 1;
unsafe static void ScheduleNode(ref JobHandle* jobSched, JobHandle* jobDepends, Node* node, Point3* points, int offset, int length, int depth, int depthSingleThreaded)
{
// pick median
int median = length >> 1;
// calc offsets
var offsetL = offset;
var offsetR = offset + median + 1;
var lengthL = median;
var lengthR = length - median - 1;
var stepL = lengthL > 0 ? 1 : 0;
var stepR = lengthR > 0 ? 1 + lengthL : 0;
// calc offsets
var offsetL = offset;
var offsetR = offset + median + 1;
var lengthL = median;
var lengthR = length - median - 1;
var stepL = lengthL > 0 ? 1 : 0;
var stepR = lengthR > 0 ? 1 + lengthL : 0;
// make job
var job = new BuildNodeJob()
{
node = node,
points = points,
offset = offset,
length = length,
depth = depth,
leaf = (depth >= depthSingleThreaded),
};
// make job
var job = new BuildNodeJob()
{
node = node,
points = points,
offset = offset,
length = length,
depth = depth,
leaf = (depth >= depthSingleThreaded),
};
var jobHandle = jobSched++;
if (jobDepends != null)
*jobHandle = job.Schedule(*jobDepends);
else
*jobHandle = job.Schedule();
var jobHandle = jobSched++;
if (jobDepends != null)
*jobHandle = job.Schedule(*jobDepends);
else
*jobHandle = job.Schedule();
if (depth == 0)
JobHandle.ScheduleBatchedJobs();
if (depth == 0)
JobHandle.ScheduleBatchedJobs();
if (job.leaf)
return;
if (job.leaf)
return;
// schedule subtrees
if (lengthL > 0) ScheduleNode(ref jobSched, jobHandle, node + stepL, points, offsetL, lengthL, depth + 1, depthSingleThreaded);
if (lengthR > 0) ScheduleNode(ref jobSched, jobHandle, node + stepR, points, offsetR, lengthR, depth + 1, depthSingleThreaded);
}
// schedule subtrees
if (lengthL > 0) ScheduleNode(ref jobSched, jobHandle, node + stepL, points, offsetL, lengthL, depth + 1, depthSingleThreaded);
if (lengthR > 0) ScheduleNode(ref jobSched, jobHandle, node + stepR, points, offsetR, lengthR, depth + 1, depthSingleThreaded);
}
[BurstCompile]
unsafe struct BuildNodeJob : IJob
{
[NativeDisableUnsafePtrRestriction] public Node* node;
[NativeDisableUnsafePtrRestriction] public Point3* points;// shared
[BurstCompile]
unsafe struct BuildNodeJob : IJob
{
[NativeDisableUnsafePtrRestriction] public Node* node;
[NativeDisableUnsafePtrRestriction] public Point3* points;// shared
public int offset;
public int length;
public int depth;
public bool leaf;
public int offset;
public int length;
public int depth;
public bool leaf;
public void Execute()
{
if (leaf)
BuildNode(node, points, offset, length, depth);
else
BuildNodeDeferSubtrees(node, points, offset, length, depth);
}
}
public void Execute()
{
if (leaf)
BuildNode(node, points, offset, length, depth);
else
BuildNodeDeferSubtrees(node, points, offset, length, depth);
}
}
unsafe static void BuildNode(Node* node, Point3* points, int offset, int length, int depth)
{
// pick median
int median = length >> 1;
unsafe static void BuildNode(Node* node, Point3* points, int offset, int length, int depth)
{
// pick median
int median = length >> 1;
// pick splitting axis
int axis = depth % 3;
// pick splitting axis
int axis = depth % 3;
// split points by median
SelectByAxis(median, points + offset, length, axis);
// split points by median
SelectByAxis(median, points + offset, length, axis);
// calc offsets
var offsetL = offset;
var offsetR = offset + median + 1;
var lengthL = median;
var lengthR = length - median - 1;
var stepL = lengthL > 0 ? 1 : 0;
var stepR = lengthR > 0 ? 1 + lengthL : 0;
// calc offsets
var offsetL = offset;
var offsetR = offset + median + 1;
var lengthL = median;
var lengthR = length - median - 1;
var stepL = lengthL > 0 ? 1 : 0;
var stepR = lengthR > 0 ? 1 + lengthL : 0;
// make node
node->point = offset + median;
node->stepL = stepL;
node->stepR = stepR;
// make node
node->point = offset + median;
node->stepL = stepL;
node->stepR = stepR;
// build subtrees
if (lengthL > 0) BuildNode(node + stepL, points, offsetL, lengthL, depth + 1);
if (lengthR > 0) BuildNode(node + stepR, points, offsetR, lengthR, depth + 1);
}
// build subtrees
if (lengthL > 0) BuildNode(node + stepL, points, offsetL, lengthL, depth + 1);
if (lengthR > 0) BuildNode(node + stepR, points, offsetR, lengthR, depth + 1);
}
unsafe static void BuildNodeDeferSubtrees(Node* node, Point3* points, int offset, int length, int depth)
{
// pick median
int median = length >> 1;
unsafe static void BuildNodeDeferSubtrees(Node* node, Point3* points, int offset, int length, int depth)
{
// pick median
int median = length >> 1;
// pick splitting axis
int axis = depth % 3;
// pick splitting axis
int axis = depth % 3;
// split points by median
SelectByAxis(median, points + offset, length, axis);
// split points by median
SelectByAxis(median, points + offset, length, axis);
// calc offsets
var lengthL = median;
var lengthR = length - median - 1;
var stepL = lengthL > 0 ? 1 : 0;
var stepR = lengthR > 0 ? 1 + lengthL : 0;
// calc offsets
var lengthL = median;
var lengthR = length - median - 1;
var stepL = lengthL > 0 ? 1 : 0;
var stepR = lengthR > 0 ? 1 + lengthL : 0;
// make node
node->point = offset + median;
node->stepL = stepL;
node->stepR = stepR;
}
// make node
node->point = offset + median;
node->stepL = stepL;
node->stepR = stepR;
}
unsafe static void SelectByAxis(int nth, Point3* points, int length, int axis)
{
// note: this function adapted from public domain variants listed in KdTreeUtils.cs
const int strideLsh = 2;
unsafe static void SelectByAxis(int nth, Point3* points, int length, int axis)
{
// note: this function has been adapted from public domain
// variants listed in 'KdTree_nth_element.txt'
const int strideLsh = 2;
var i = 0;
var j = length - 1;
var v = &points->x + axis;
var i = 0;
var j = length - 1;
var v = &points->x + axis;
while (i < j)
{
var r = i;
var w = j;
while (i < j)
{
var r = i;
var w = j;
float k = v[((r + w) >> 1) << strideLsh];
float k = v[((r + w) >> 1) << strideLsh];
while (r < w)
{
if (v[r << strideLsh] >= k)
{
Point3 pw = points[w];
points[w] = points[r];
points[r] = pw;
w--;
}
else
{
r++;
}
}
while (r < w)
{
if (v[r << strideLsh] >= k)
{
Point3 pw = points[w];
points[w] = points[r];
points[r] = pw;
w--;
}
else
{
r++;
}
}
if (v[r << strideLsh] > k)
r--;
if (v[r << strideLsh] > k)
r--;
if (nth <= r)
j = r;
else
i = r + 1;
}
}
if (nth <= r)
j = r;
else
i = r + 1;
}
}
//-----------------
// kd-tree queries
//-----------------
// kd-tree queries
public int FindNearest(ref Vector3 target)
{
var bestDist = float.PositiveInfinity;
var bestNode = -1;
public int FindNearest(ref Vector3 target)
{
var bestDist = float.PositiveInfinity;
var bestNode = -1;
Profiler.BeginSample("kd-nearest");
FindNearest(ref bestDist, ref bestNode, 0, 0, ref target);
Profiler.EndSample();
Profiler.BeginSample("kd-nearest");
FindNearest(ref bestDist, ref bestNode, 0, 0, ref target);
Profiler.EndSample();
if (bestNode != -1)
return points[nodes[bestNode].point].index;
else
return -1;
}
if (bestNode != -1)
return points[nodes[bestNode].point].index;
else
return -1;
}
public bool FindNearest(ref float bestDist, ref int bestNode, ref Vector3 target)
{
var __bestDist = float.PositiveInfinity;
var __bestNode = -1;
public bool FindNearest(ref float bestDist, ref int bestNode, ref Vector3 target)
{
var __bestDist = float.PositiveInfinity;
var __bestNode = -1;
Profiler.BeginSample("kd-nearest");
FindNearest(ref __bestDist, ref __bestNode, 0, 0, ref target);
Profiler.EndSample();
Profiler.BeginSample("kd-nearest");
FindNearest(ref __bestDist, ref __bestNode, 0, 0, ref target);
Profiler.EndSample();
if (__bestNode != -1)
{
bestDist = __bestDist;
bestNode = points[nodes[__bestNode].point].index;
return true;
}
else
{
return false;
}
}
if (__bestNode != -1)
{
bestDist = __bestDist;
bestNode = points[nodes[__bestNode].point].index;
return true;
}
else
{
return false;
}
}
unsafe void FindNearest(ref float bestDist, ref int bestNode, int node, int depth, ref Vector3 target)
{
// update best index
int point = nodes[node].point;
Vector3 r;
r.x = target.x - points[point].x;
r.y = target.y - points[point].y;
r.z = target.z - points[point].z;
unsafe void FindNearest(ref float bestDist, ref int bestNode, int node, int depth, ref Vector3 target)
{
// update best index
int point = nodes[node].point;
Vector3 r;
r.x = target.x - points[point].x;
r.y = target.y - points[point].y;
r.z = target.z - points[point].z;
var dist = r.x * r.x + r.y * r.y + r.z * r.z;
if (dist < bestDist)
{
bestDist = dist;
bestNode = node;
}
var dist = r.x * r.x + r.y * r.y + r.z * r.z;
if (dist < bestDist)
{
bestDist = dist;
bestNode = node;
}
// pick search axis
int axis = depth % 3;
// pick search axis
int axis = depth % 3;
// pick near, far
var delta = *(&r.x + axis);// avoid calling operator[]
int stepN = delta < 0.0f ? nodes[node].stepL : nodes[node].stepR;
int stepF = delta < 0.0f ? nodes[node].stepR : nodes[node].stepL;
// pick near, far
var delta = *(&r.x + axis);// avoid calling operator[]
int stepN = delta < 0.0f ? nodes[node].stepL : nodes[node].stepR;
int stepF = delta < 0.0f ? nodes[node].stepR : nodes[node].stepL;
// search near
if (stepN != 0)
{
FindNearest(ref bestDist, ref bestNode, node + stepN, depth + 1, ref target);
}
// search near
if (stepN != 0)
{
FindNearest(ref bestDist, ref bestNode, node + stepN, depth + 1, ref target);
}
// search far
if (stepF != 0 && delta * delta < bestDist)
{
FindNearest(ref bestDist, ref bestNode, node + stepF, depth + 1, ref target);
}
}
// search far
if (stepF != 0 && delta * delta < bestDist)
{
FindNearest(ref bestDist, ref bestNode, node + stepF, depth + 1, ref target);
}
}
public int RaycastApprox(ref Vector3 origin, ref Vector3 direction, int maxIterations = 100)
{
var position = origin;
var numIterations = 0;
public int RaycastApprox(ref Vector3 origin, ref Vector3 direction, int maxIterations = 100)
{
var position = origin;
var numIterations = 0;
var bestDist = float.PositiveInfinity;
var bestNode = -1;
var bestDist = float.PositiveInfinity;
var bestNode = -1;
while (numIterations++ < maxIterations)
{
var stepDist = float.PositiveInfinity;
var stepNode = -1;
while (numIterations++ < maxIterations)
{
var stepDist = float.PositiveInfinity;
var stepNode = -1;
FindNearest(ref stepDist, ref stepNode, ref position);
FindNearest(ref stepDist, ref stepNode, ref position);
if (stepDist < bestDist)
{
bestDist = stepDist;
bestNode = stepNode;
if (stepDist < bestDist)
{
bestDist = stepDist;
bestNode = stepNode;
if (bestDist < float.Epsilon)
{
break;// crude termination criteria
}
}
if (bestDist < float.Epsilon)
{
break;// crude termination criteria
}
}
position = position + Mathf.Sqrt(stepDist) * direction;
}
position = position + Mathf.Sqrt(stepDist) * direction;
}
return bestNode;
}
}
return bestNode;
}
}
public static class BalancedBinaryTreeInfo
{
public static int LeafCountFromDepth(int depth)
{
int leafCount = (depth > 0) ? 1 : 0;
while (--depth > 0) leafCount = (leafCount << 1);
return leafCount;
}
public static class BalancedBinaryTreeInfo
{
public static int LeafCountFromDepth(int depth)
{
int leafCount = (depth > 0) ? 1 : 0;
while (--depth > 0) leafCount = (leafCount << 1);
return leafCount;
}
public static int NodeCountFromDepth(int depth)
{
int nodeCount = 0;
while (--depth >= 0) nodeCount = (nodeCount << 1) | 1;
return nodeCount;
}
public static int NodeCountFromDepth(int depth)
{
int nodeCount = 0;
while (--depth >= 0) nodeCount = (nodeCount << 1) | 1;
return nodeCount;
}
public static int NodeCountFromLeafCount(int leafCount)
{
Debug.Assert(Mathf.IsPowerOfTwo(leafCount));
int nodeCount = leafCount;
while ((leafCount >>= 1) > 0) nodeCount += leafCount;
return nodeCount;
}
public static int NodeCountFromLeafCount(int leafCount)
{
Debug.Assert(Mathf.IsPowerOfTwo(leafCount));
int nodeCount = leafCount;
while ((leafCount >>= 1) > 0) nodeCount += leafCount;
return nodeCount;
}
public static int DepthFromLeafCount(int leafCount)
{
Debug.Assert(Mathf.IsPowerOfTwo(leafCount));
int depth = 0;
while (leafCount > 0) { leafCount >>= 1; depth++; }
return depth;
}
public static int DepthFromLeafCount(int leafCount)
{
Debug.Assert(Mathf.IsPowerOfTwo(leafCount));
int depth = 0;
while (leafCount > 0) { leafCount >>= 1; depth++; }
return depth;
}
}
}

8
Runtime/MeshTools.meta


fileFormatVersion: 2
guid: f8884fe2d3f7df14e8e8c905b1c42905
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

12
TODO.txt


X missing specular for some reason
X make the snappers setup a bit more generic
X move eye code to shadergraph
X fix attachments conservative bounds
X fix attachments scaling
X pending HDRP tasks
X EyeMasterNode
X StackLitMasterNode custom specular occlusion
X implement the tearline
X blur decals?
X CustomPassInjectionPoint.AfterGBuffer (-> AfterOpaqueDepthAndNormal)
X implement the control rig

7
TODO.txt.meta


fileFormatVersion: 2
guid: 2ead9af64b3f86b47ad1c448ec147e12
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

/Editor/MeshTools.meta → /Editor/Utility.meta

/Editor/MeshTools → /Editor/Utility

/Runtime/EditorUtilityProxy.cs → /Runtime/Utility/EditorUtilityProxy.cs

/Runtime/EditorUtilityProxy.cs.meta → /Runtime/Utility/EditorUtilityProxy.cs.meta

/Runtime/MeshTools/ArrayUtils.cs → /Runtime/Utility/ArrayUtils.cs

/Runtime/MeshTools/ArrayUtils.cs.meta → /Runtime/Utility/ArrayUtils.cs.meta

/Runtime/MeshTools/Barycentric.cs → /Runtime/Utility/Barycentric.cs

/Runtime/MeshTools/Barycentric.cs.meta → /Runtime/Utility/Barycentric.cs.meta

/Runtime/MeshTools/KdTree3.cs.meta → /Runtime/Utility/KdTree3.cs.meta

/Runtime/MeshTools/KdTree3Utils.cs → /Runtime/Utility/KdTree3Utils.cs

/Runtime/MeshTools/KdTree3Utils.cs.meta → /Runtime/Utility/KdTree3Utils.cs.meta

/Runtime/MeshTools/LinkedIndexList.cs → /Runtime/Utility/LinkedIndexList.cs

/Runtime/MeshTools/LinkedIndexList.cs.meta → /Runtime/Utility/LinkedIndexList.cs.meta

/Runtime/MeshTools/LinkedIndexListArray.cs → /Runtime/Utility/LinkedIndexListArray.cs

/Runtime/MeshTools/LinkedIndexListArray.cs.meta → /Runtime/Utility/LinkedIndexListArray.cs.meta

/Runtime/MeshTools/MeshAdjacency.cs → /Runtime/Utility/MeshAdjacency.cs

/Runtime/MeshTools/MeshAdjacency.cs.meta → /Runtime/Utility/MeshAdjacency.cs.meta

/Runtime/MeshTools/MeshBuffers.cs → /Runtime/Utility/MeshBuffers.cs

/Runtime/MeshTools/MeshBuffers.cs.meta → /Runtime/Utility/MeshBuffers.cs.meta

/Runtime/MeshTools/MeshEdges.cs → /Runtime/Utility/MeshEdges.cs

/Runtime/MeshTools/MeshEdges.cs.meta → /Runtime/Utility/MeshEdges.cs.meta

/Runtime/MeshTools/MeshEx.cs → /Runtime/Utility/MeshEx.cs

/Runtime/MeshTools/MeshEx.cs.meta → /Runtime/Utility/MeshEx.cs.meta

/Runtime/MeshTools/MeshInstanceBehaviour.cs → /Runtime/Utility/MeshInstanceBehaviour.cs

/Runtime/MeshTools/MeshInstanceBehaviour.cs.meta → /Runtime/Utility/MeshInstanceBehaviour.cs.meta

/Runtime/MeshTools/MeshIslands.cs → /Runtime/Utility/MeshIslands.cs

/Runtime/MeshTools/MeshIslands.cs.meta → /Runtime/Utility/MeshIslands.cs.meta

/Runtime/MeshTools/NativeMesh.cs → /Runtime/Utility/NativeMesh.cs

/Runtime/MeshTools/NativeMesh.cs.meta → /Runtime/Utility/NativeMesh.cs.meta

/Runtime/MeshTools/NativeMeshObjLoader.cs → /Runtime/Utility/NativeMeshObjLoader.cs

/Runtime/MeshTools/NativeMeshObjLoader.cs.meta → /Runtime/Utility/NativeMeshObjLoader.cs.meta

/Runtime/MeshTools/UnsafeArrayBool.cs → /Runtime/Utility/UnsafeArrayBool.cs

/Runtime/MeshTools/UnsafeArrayBool.cs.meta → /Runtime/Utility/UnsafeArrayBool.cs.meta

/Runtime/MeshTools/UnsafeArrayFloat.cs → /Runtime/Utility/UnsafeArrayFloat.cs

/Runtime/MeshTools/UnsafeArrayFloat.cs.meta → /Runtime/Utility/UnsafeArrayFloat.cs.meta

/Runtime/MeshTools/UnsafeArrayInt.cs → /Runtime/Utility/UnsafeArrayInt.cs

/Runtime/MeshTools/UnsafeArrayInt.cs.meta → /Runtime/Utility/UnsafeArrayInt.cs.meta

/Runtime/MeshTools/UnsafeArrayULong.cs → /Runtime/Utility/UnsafeArrayULong.cs

/Runtime/MeshTools/UnsafeArrayULong.cs.meta → /Runtime/Utility/UnsafeArrayULong.cs.meta

/Runtime/MeshTools/UnsafeArrayVector3.cs → /Runtime/Utility/UnsafeArrayVector3.cs

/Runtime/MeshTools/UnsafeArrayVector3.cs.meta → /Runtime/Utility/UnsafeArrayVector3.cs.meta

/Runtime/MeshTools/UnsafeBFS.cs → /Runtime/Utility/UnsafeBFS.cs

/Runtime/MeshTools/UnsafeBFS.cs.meta → /Runtime/Utility/UnsafeBFS.cs.meta

/Runtime/MeshTools/UnsafeDFS.cs → /Runtime/Utility/UnsafeDFS.cs

/Runtime/MeshTools/UnsafeDFS.cs.meta → /Runtime/Utility/UnsafeDFS.cs.meta

/Runtime/MeshTools/KdTree3.cs → /Runtime/Utility/KdTree3.cs

正在加载...
取消
保存