Fix blend shape export with multiple submeshes

Share a single vertex list between submeshes in the exported mesh, which
makes the blend target vertex list indices line up correctly.

As a bonus, the exported FBX file will be smaller for meshes with more
than one submesh, since we're not duplicating vertices anymore.
This commit is contained in:
Dan Weatherford 2021-06-20 00:18:22 -05:00
parent ab98585b6a
commit 08b7bfcf9a
3 changed files with 140 additions and 158 deletions

View File

@ -132,6 +132,7 @@ namespace AssetStudio
public class ImportedMesh
{
public string Path { get; set; }
public List<ImportedVertex> VertexList { get; set; }
public List<ImportedSubmesh> SubmeshList { get; set; }
public List<ImportedBone> BoneList { get; set; }
public bool hasNormal { get; set; }
@ -142,9 +143,9 @@ namespace AssetStudio
public class ImportedSubmesh
{
public List<ImportedVertex> VertexList { get; set; }
public List<ImportedFace> FaceList { get; set; }
public string Material { get; set; }
public int BaseVertex { get; set; }
}
public class ImportedVertex

View File

@ -246,14 +246,7 @@ namespace AssetStudio.FbxInterop
var mesh = AsFbxMeshCreateMesh(_pContext, frameNode);
var totalVertexCount = 0;
foreach (var m in importedMesh.SubmeshList)
{
totalVertexCount += m.VertexList.Count;
}
AsFbxMeshInitControlPoints(mesh, totalVertexCount);
AsFbxMeshInitControlPoints(mesh, importedMesh.VertexList.Count);
if (importedMesh.hasNormal)
{
@ -282,8 +275,6 @@ namespace AssetStudio.FbxInterop
AsFbxMeshCreateElementMaterial(mesh);
var firstVertex = 0;
foreach (var meshObj in importedMesh.SubmeshList)
{
var materialIndex = 0;
@ -345,7 +336,17 @@ namespace AssetStudio.FbxInterop
}
}
var vertexList = meshObj.VertexList;
foreach (var face in meshObj.FaceList)
{
var index0 = face.VertexIndices[0] + meshObj.BaseVertex;
var index1 = face.VertexIndices[1] + meshObj.BaseVertex;
var index2 = face.VertexIndices[2] + meshObj.BaseVertex;
AsFbxMeshAddPolygon(mesh, materialIndex, index0, index1, index2);
}
}
var vertexList = importedMesh.VertexList;
var vertexCount = vertexList.Count;
@ -354,7 +355,7 @@ namespace AssetStudio.FbxInterop
var importedVertex = vertexList[j];
var vertex = importedVertex.Vertex;
AsFbxMeshSetControlPoint(mesh, j + firstVertex, vertex.X, vertex.Y, vertex.Z);
AsFbxMeshSetControlPoint(mesh, j, vertex.X, vertex.Y, vertex.Z);
if (importedMesh.hasNormal)
{
@ -392,23 +393,12 @@ namespace AssetStudio.FbxInterop
{
if (boneIndices[k] < totalBoneCount && boneWeights[k] > 0)
{
AsFbxMeshSetBoneWeight(pClusterArray, boneIndices[k], j + firstVertex, boneWeights[k]);
AsFbxMeshSetBoneWeight(pClusterArray, boneIndices[k], j, boneWeights[k]);
}
}
}
}
foreach (var face in meshObj.FaceList)
{
var index0 = face.VertexIndices[0] + firstVertex;
var index1 = face.VertexIndices[1] + firstVertex;
var index2 = face.VertexIndices[2] + firstVertex;
AsFbxMeshAddPolygon(mesh, materialIndex, index0, index1, index2);
}
firstVertex += vertexCount;
}
if (hasBones)
{

View File

@ -319,8 +319,28 @@ namespace AssetStudio
}
ImportedMaterial iMat = ConvertMaterial(mat);
iSubmesh.Material = iMat.Name;
iSubmesh.VertexList = new List<ImportedVertex>((int)submesh.vertexCount);
for (var j = mesh.m_SubMeshes[i].firstVertex; j < mesh.m_SubMeshes[i].firstVertex + mesh.m_SubMeshes[i].vertexCount; j++)
iSubmesh.BaseVertex = (int) mesh.m_SubMeshes[i].firstVertex;
//Face
iSubmesh.FaceList = new List<ImportedFace>(numFaces);
var end = firstFace + numFaces;
for (int f = firstFace; f < end; f++)
{
var face = new ImportedFace();
face.VertexIndices = new int[3];
face.VertexIndices[0] = (int)(mesh.m_Indices[f * 3 + 2] - submesh.firstVertex);
face.VertexIndices[1] = (int)(mesh.m_Indices[f * 3 + 1] - submesh.firstVertex);
face.VertexIndices[2] = (int)(mesh.m_Indices[f * 3] - submesh.firstVertex);
iSubmesh.FaceList.Add(face);
}
firstFace = end;
iMesh.SubmeshList.Add(iSubmesh);
}
// Shared vertex list
iMesh.VertexList = new List<ImportedVertex>((int)mesh.m_VertexCount);
for (var j = 0; j < mesh.m_VertexCount; j++)
{
var iVertex = new ImportedVertex();
//Vertices
@ -390,22 +410,7 @@ namespace AssetStudio
iVertex.Weights[k] = inf.weight[k];
}
}
iSubmesh.VertexList.Add(iVertex);
}
//Face
iSubmesh.FaceList = new List<ImportedFace>(numFaces);
var end = firstFace + numFaces;
for (int f = firstFace; f < end; f++)
{
var face = new ImportedFace();
face.VertexIndices = new int[3];
face.VertexIndices[0] = (int)(mesh.m_Indices[f * 3 + 2] - submesh.firstVertex);
face.VertexIndices[1] = (int)(mesh.m_Indices[f * 3 + 1] - submesh.firstVertex);
face.VertexIndices[2] = (int)(mesh.m_Indices[f * 3] - submesh.firstVertex);
iSubmesh.FaceList.Add(face);
}
firstFace = end;
iMesh.SubmeshList.Add(iSubmesh);
iMesh.VertexList.Add(iVertex);
}
if (meshR is SkinnedMeshRenderer sMesh)
@ -524,7 +529,7 @@ namespace AssetStudio
keyframe.VertexList.Add(destVertex);
var morphVertex = mesh.m_Shapes.vertices[j];
destVertex.Index = morphVertex.index;
var sourceVertex = GetSourceVertex(iMesh.SubmeshList, (int)morphVertex.index);
var sourceVertex = iMesh.VertexList[(int)morphVertex.index];
destVertex.Vertex = new ImportedVertex();
var morphPos = morphVertex.vertex;
destVertex.Vertex.Vertex = sourceVertex.Vertex + new Vector3(-morphPos.X, morphPos.Y, morphPos.Z);
@ -1014,20 +1019,6 @@ namespace AssetStudio
return boneName;
}
private static ImportedVertex GetSourceVertex(List<ImportedSubmesh> submeshList, int morphVertIndex)
{
foreach (var submesh in submeshList)
{
var vertList = submesh.VertexList;
if (morphVertIndex < vertList.Count)
{
return vertList[morphVertIndex];
}
morphVertIndex -= vertList.Count;
}
return null;
}
private void CreateBonePathHash(Transform m_Transform)
{
var name = GetTransformPathByFather(m_Transform);