Accelerating split mesh.

This commit is contained in:
YZR 2018-05-02 19:53:06 +08:00
parent 53947ee6d3
commit 49233f4195

View File

@ -41,7 +41,7 @@ public unsafe class DracoMeshLoader
public Vector3[] vertices; public Vector3[] vertices;
public Vector3[] normals; public Vector3[] normals;
public Vector2[] uvs; public Vector2[] uvs;
public Vector3[] colors; public Color[] colors;
} }
[DllImport ("dracodec_unity")] private static extern int DecodeMeshForUnity ( [DllImport ("dracodec_unity")] private static extern int DecodeMeshForUnity (
@ -53,81 +53,99 @@ public unsafe class DracoMeshLoader
// to be splitted. // to be splitted.
private void SplitMesh (DecodedMesh mesh, ref List<DecodedMesh> splittedMeshes) private void SplitMesh (DecodedMesh mesh, ref List<DecodedMesh> splittedMeshes)
{ {
List<int> facesLeft = new List<int> (); int[] IndexNew = new int[maxNumVerticesPerMesh];
for (int i = 0; i < mesh.faces.Length; ++i) { int BaseIndex = 0;
facesLeft.Add (mesh.faces [i]); int FaceCount = mesh.faces.Length;
} int[] FaceIndex = new int[FaceCount];
int numSubMeshes = 0; int[] NewFace = new int[FaceCount];
List<int> newCorners = new List<int> ();
Dictionary<int, int> indexToNewIndex = new Dictionary<int, int> ();
List<int> facesExtracted = new List<int> (); for (int i = 0; i < FaceCount; i++)
List<Vector3> verticesExtracted = new List<Vector3> (); {
List<Vector2> uvsExtracted = new List<Vector2> (); FaceIndex[i] = -1;
List<Vector3> normalsExtracted = new List<Vector3> (); }
List<Vector3> colorsExtracted = new List<Vector3> ();
while (facesLeft.Count > 0) { while (BaseIndex < FaceCount)
numSubMeshes++; {
List<int> tmpLeftFaces = new List<int> (); int uniqueCornerId = 0;
facesExtracted.Clear (); int UseIndex = 0;
verticesExtracted.Clear (); int AddNew = 0;
uvsExtracted.Clear (); int[] NewCorner = new int[3];
normalsExtracted.Clear (); for (; BaseIndex + UseIndex < FaceCount;)
colorsExtracted.Clear (); {
AddNew = 0;
for (int i = 0; i < 3; i++)
{
if (FaceIndex[mesh.faces[BaseIndex + UseIndex + i]] == -1)
{
NewCorner[AddNew] = mesh.faces[BaseIndex + UseIndex + i];
AddNew++;
}
}
int uniqueCornerId = 0; if (uniqueCornerId + AddNew > maxNumVerticesPerMesh)
indexToNewIndex.Clear (); {
for (int face = 0; face < facesLeft.Count / 3; ++face) { break;
newCorners.Clear (); }
// If all indices has appeared or there's still space for more vertices.
for (int corner = 0; corner < 3; ++corner) {
if (!indexToNewIndex.ContainsKey (facesLeft [face * 3 + corner])) {
newCorners.Add (facesLeft [face * 3 + corner]);
}
}
if (newCorners.Count + uniqueCornerId > maxNumVerticesPerMesh) {
// Save face for the next sub-mesh.
for (int corner = 0; corner < 3; ++corner) {
tmpLeftFaces.Add (facesLeft [face * 3 + corner]);
}
} else {
// Add new corners.
for (int i = 0; i < newCorners.Count; ++i) {
indexToNewIndex.Add (newCorners [i], uniqueCornerId);
verticesExtracted.Add (mesh.vertices [newCorners [i]]);
if (mesh.normals != null)
normalsExtracted.Add (mesh.normals [newCorners [i]]);
if (mesh.colors != null)
colorsExtracted.Add (mesh.colors [newCorners [i]]);
if (mesh.uvs != null)
uvsExtracted.Add (mesh.uvs [newCorners [i]]);
uniqueCornerId++; for (int i = 0; i < AddNew; i++)
} {
// Add face to this sub-mesh. FaceIndex[NewCorner[i]] = uniqueCornerId;
for (int corner = 0; corner < 3; ++corner) { IndexNew[uniqueCornerId] = NewCorner[i];
facesExtracted.Add ( uniqueCornerId++;
indexToNewIndex [facesLeft [face * 3 + corner]]); }
}
}
}
DecodedMesh subMesh = new DecodedMesh (); for (int i = 0; i < 3; i++)
subMesh.faces = facesExtracted.ToArray (); {
subMesh.vertices = verticesExtracted.ToArray (); NewFace[UseIndex] = FaceIndex[mesh.faces[BaseIndex + UseIndex]];
if (normalsExtracted.Count > 0) { UseIndex++;
subMesh.normals = normalsExtracted.ToArray (); }
} }
if (uvsExtracted.Count > 0)
subMesh.uvs = uvsExtracted.ToArray ();
if (colorsExtracted.Count > 0)
subMesh.colors = colorsExtracted.ToArray ();
splittedMeshes.Add (subMesh);
facesLeft = tmpLeftFaces; for (int i = 0; i < uniqueCornerId; i++)
} {
FaceIndex[IndexNew[i]] = -1;
}
DecodedMesh subMesh = new DecodedMesh();
subMesh.faces = new int[UseIndex];
Array.Copy(NewFace, subMesh.faces, UseIndex);
subMesh.vertices = new Vector3[uniqueCornerId];
for (int i = 0; i < uniqueCornerId; i++)
{
subMesh.vertices[i] = mesh.vertices[IndexNew[i]];
}
if (mesh.normals != null)
{
subMesh.normals = new Vector3[uniqueCornerId];
for (int i = 0; i < uniqueCornerId; i++)
{
subMesh.normals[i] = mesh.normals[IndexNew[i]];
}
}
if (mesh.colors != null)
{
subMesh.colors = new Color[uniqueCornerId];
for (int i = 0; i < uniqueCornerId; i++)
{
subMesh.colors[i] = mesh.colors[IndexNew[i]];
}
}
if (mesh.uvs != null)
{
subMesh.uvs = new Vector2[uniqueCornerId];
for (int i = 0; i < uniqueCornerId; i++)
{
subMesh.uvs[i] = mesh.uvs[IndexNew[i]];
}
}
splittedMeshes.Add(subMesh);
BaseIndex += UseIndex;
}
} }
private float ReadFloatFromIntPtr (IntPtr data, int offset) private float ReadFloatFromIntPtr (IntPtr data, int offset)
@ -176,11 +194,10 @@ public unsafe class DracoMeshLoader
int numFaces = tmpMesh->numFaces; int numFaces = tmpMesh->numFaces;
int[] newTriangles = new int[tmpMesh->numFaces * 3]; int[] newTriangles = new int[tmpMesh->numFaces * 3];
for (int i = 0; i < tmpMesh->numFaces; ++i) { for (int i = 0; i < tmpMesh->numFaces; ++i) {
newTriangles [i * 3] = Marshal.ReadInt32 (tmpMesh->indices, i * 3 * 4); byte* addr = (byte*)tmpMesh->indices + i * 3 * 4;
newTriangles [i * 3 + 1] = newTriangles[i * 3] = *((int*)addr);
Marshal.ReadInt32 (tmpMesh->indices, i * 3 * 4 + 4); newTriangles[i * 3 + 1] = *((int*)(addr + 4));
newTriangles [i * 3 + 2] = newTriangles[i * 3 + 2] = *((int*)(addr + 8));
Marshal.ReadInt32 (tmpMesh->indices, i * 3 * 4 + 8);
} }
// For floating point numbers, there's no Marshal functions could directly // For floating point numbers, there's no Marshal functions could directly
@ -193,9 +210,9 @@ public unsafe class DracoMeshLoader
Vector3[] newNormals = new Vector3[0]; Vector3[] newNormals = new Vector3[0];
if (tmpMesh->hasNormal) if (tmpMesh->hasNormal)
newNormals = new Vector3[tmpMesh->numVertices]; newNormals = new Vector3[tmpMesh->numVertices];
Vector3[] newColors = new Vector3[0]; Color[] newColors = new Color[0];
if (tmpMesh->hasColor) if (tmpMesh->hasColor)
newColors = new Vector3[tmpMesh->numVertices]; newColors = new Color[tmpMesh->numVertices];
int byteStridePerValue = 4; int byteStridePerValue = 4;
/* /*
* TODO(zhafang): Change to: * TODO(zhafang): Change to:
@ -207,35 +224,40 @@ public unsafe class DracoMeshLoader
* } * }
* } * }
*/ */
byte* posaddr = (byte*)tmpMesh->position;
byte* normaladdr = (byte*)tmpMesh->normal;
byte* coloraddr = (byte*)tmpMesh->color;
byte* uvaddr = (byte*)tmpMesh->texcoord;
for (int i = 0; i < tmpMesh->numVertices; ++i) { for (int i = 0; i < tmpMesh->numVertices; ++i) {
int numValuePerVertex = 3; int numValuePerVertex = 3;
for (int j = 0; j < numValuePerVertex; ++j) {
int byteStridePerVertex = byteStridePerValue * numValuePerVertex; for (int j = 0; j < numValuePerVertex; ++j)
newVertices [i] [j] = {
ReadFloatFromIntPtr ( int byteStridePerVertex = byteStridePerValue * numValuePerVertex;
tmpMesh->position, int OffSet = i * byteStridePerVertex + byteStridePerValue * j;
i * byteStridePerVertex + byteStridePerValue * j);
if (tmpMesh->hasNormal) newVertices[i][j] = *((float*)(posaddr + OffSet));
newNormals [i] [j] = if (tmpMesh->hasNormal)
ReadFloatFromIntPtr ( {
tmpMesh->normal, newNormals[i][j] = *((float*)(normaladdr + OffSet));
i * byteStridePerVertex + byteStridePerValue * j); }
if (tmpMesh->hasColor) if (tmpMesh->hasColor)
newColors [i] [j] = {
ReadFloatFromIntPtr ( newColors[i][j] = *((float*)(coloraddr + OffSet));
tmpMesh->color, }
i * byteStridePerVertex + byteStridePerValue * j); }
}
if (tmpMesh->hasTexcoord) {
numValuePerVertex = 2; if (tmpMesh->hasTexcoord)
for (int j = 0; j < numValuePerVertex; ++j) { {
int byteStridePerVertex = byteStridePerValue * numValuePerVertex; numValuePerVertex = 2;
newUVs [i] [j] = for (int j = 0; j < numValuePerVertex; ++j)
ReadFloatFromIntPtr ( {
tmpMesh->texcoord, int byteStridePerVertex = byteStridePerValue * numValuePerVertex;
i * byteStridePerVertex + byteStridePerValue * j); newUVs[i][j] = *((float*)(uvaddr + (i * byteStridePerVertex + byteStridePerValue * j)));
} }
} }
} }
Marshal.FreeCoTaskMem (tmpMesh->indices); Marshal.FreeCoTaskMem (tmpMesh->indices);
@ -272,12 +294,8 @@ public unsafe class DracoMeshLoader
mesh.uv = splittedMeshes [i].uvs; mesh.uv = splittedMeshes [i].uvs;
if (splittedMeshes [i].colors != null) { if (splittedMeshes [i].colors != null) {
mesh.colors = new Color[splittedMeshes [i].colors.Length]; mesh.colors = splittedMeshes[i].colors;
for (int j = 0; j < splittedMeshes [i].colors.Length; ++j) { }
mesh.colors [j] = new Color (splittedMeshes [i].colors [j] [0],
splittedMeshes [i].colors [j] [1], splittedMeshes [i].colors [j] [2]);
}
}
if (splittedMeshes [i].normals != null) { if (splittedMeshes [i].normals != null) {
mesh.normals = splittedMeshes [i].normals; mesh.normals = splittedMeshes [i].normals;
@ -301,12 +319,8 @@ public unsafe class DracoMeshLoader
Debug.Log ("Mesh doesn't have normals, recomputed."); Debug.Log ("Mesh doesn't have normals, recomputed.");
} }
if (newColors.Length != 0) { if (newColors.Length != 0) {
mesh.colors = new Color[newColors.Length]; mesh.colors = newColors;
for (int i = 0; i < newColors.Length; ++i) { }
mesh.colors [i] = new Color (newColors [i] [0],
newColors [i] [1], newColors [i] [2]);
}
}
mesh.RecalculateBounds (); mesh.RecalculateBounds ();
meshes.Add (mesh); meshes.Add (mesh);