mirror of
https://github.com/aelurum/AssetStudio.git
synced 2025-05-25 05:40:21 -04:00
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:
parent
ab98585b6a
commit
08b7bfcf9a
@ -132,6 +132,7 @@ namespace AssetStudio
|
|||||||
public class ImportedMesh
|
public class ImportedMesh
|
||||||
{
|
{
|
||||||
public string Path { get; set; }
|
public string Path { get; set; }
|
||||||
|
public List<ImportedVertex> VertexList { get; set; }
|
||||||
public List<ImportedSubmesh> SubmeshList { get; set; }
|
public List<ImportedSubmesh> SubmeshList { get; set; }
|
||||||
public List<ImportedBone> BoneList { get; set; }
|
public List<ImportedBone> BoneList { get; set; }
|
||||||
public bool hasNormal { get; set; }
|
public bool hasNormal { get; set; }
|
||||||
@ -142,9 +143,9 @@ namespace AssetStudio
|
|||||||
|
|
||||||
public class ImportedSubmesh
|
public class ImportedSubmesh
|
||||||
{
|
{
|
||||||
public List<ImportedVertex> VertexList { get; set; }
|
|
||||||
public List<ImportedFace> FaceList { get; set; }
|
public List<ImportedFace> FaceList { get; set; }
|
||||||
public string Material { get; set; }
|
public string Material { get; set; }
|
||||||
|
public int BaseVertex { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class ImportedVertex
|
public class ImportedVertex
|
||||||
|
@ -246,14 +246,7 @@ namespace AssetStudio.FbxInterop
|
|||||||
|
|
||||||
var mesh = AsFbxMeshCreateMesh(_pContext, frameNode);
|
var mesh = AsFbxMeshCreateMesh(_pContext, frameNode);
|
||||||
|
|
||||||
var totalVertexCount = 0;
|
AsFbxMeshInitControlPoints(mesh, importedMesh.VertexList.Count);
|
||||||
|
|
||||||
foreach (var m in importedMesh.SubmeshList)
|
|
||||||
{
|
|
||||||
totalVertexCount += m.VertexList.Count;
|
|
||||||
}
|
|
||||||
|
|
||||||
AsFbxMeshInitControlPoints(mesh, totalVertexCount);
|
|
||||||
|
|
||||||
if (importedMesh.hasNormal)
|
if (importedMesh.hasNormal)
|
||||||
{
|
{
|
||||||
@ -282,8 +275,6 @@ namespace AssetStudio.FbxInterop
|
|||||||
|
|
||||||
AsFbxMeshCreateElementMaterial(mesh);
|
AsFbxMeshCreateElementMaterial(mesh);
|
||||||
|
|
||||||
var firstVertex = 0;
|
|
||||||
|
|
||||||
foreach (var meshObj in importedMesh.SubmeshList)
|
foreach (var meshObj in importedMesh.SubmeshList)
|
||||||
{
|
{
|
||||||
var materialIndex = 0;
|
var materialIndex = 0;
|
||||||
@ -345,71 +336,70 @@ namespace AssetStudio.FbxInterop
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var vertexList = meshObj.VertexList;
|
|
||||||
|
|
||||||
var vertexCount = vertexList.Count;
|
|
||||||
|
|
||||||
for (var j = 0; j < vertexCount; j += 1)
|
|
||||||
{
|
|
||||||
var importedVertex = vertexList[j];
|
|
||||||
|
|
||||||
var vertex = importedVertex.Vertex;
|
|
||||||
AsFbxMeshSetControlPoint(mesh, j + firstVertex, vertex.X, vertex.Y, vertex.Z);
|
|
||||||
|
|
||||||
if (importedMesh.hasNormal)
|
|
||||||
{
|
|
||||||
var normal = importedVertex.Normal;
|
|
||||||
AsFbxMeshElementNormalAdd(mesh, 0, normal.X, normal.Y, normal.Z);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (var uvIndex = 0; uvIndex < 2; uvIndex += 1)
|
|
||||||
{
|
|
||||||
if (importedMesh.hasUV[uvIndex])
|
|
||||||
{
|
|
||||||
var uv = importedVertex.UV[uvIndex];
|
|
||||||
AsFbxMeshElementUVAdd(mesh, uvIndex, uv[0], uv[1]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (importedMesh.hasTangent)
|
|
||||||
{
|
|
||||||
var tangent = importedVertex.Tangent;
|
|
||||||
AsFbxMeshElementTangentAdd(mesh, 0, tangent.X, tangent.Y, tangent.Z, tangent.W);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (importedMesh.hasColor)
|
|
||||||
{
|
|
||||||
var color = importedVertex.Color;
|
|
||||||
AsFbxMeshElementVertexColorAdd(mesh, 0, color.R, color.G, color.B, color.A);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hasBones && importedVertex.BoneIndices != null)
|
|
||||||
{
|
|
||||||
var boneIndices = importedVertex.BoneIndices;
|
|
||||||
var boneWeights = importedVertex.Weights;
|
|
||||||
|
|
||||||
for (var k = 0; k < 4; k += 1)
|
|
||||||
{
|
|
||||||
if (boneIndices[k] < totalBoneCount && boneWeights[k] > 0)
|
|
||||||
{
|
|
||||||
AsFbxMeshSetBoneWeight(pClusterArray, boneIndices[k], j + firstVertex, boneWeights[k]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var face in meshObj.FaceList)
|
foreach (var face in meshObj.FaceList)
|
||||||
{
|
{
|
||||||
var index0 = face.VertexIndices[0] + firstVertex;
|
var index0 = face.VertexIndices[0] + meshObj.BaseVertex;
|
||||||
var index1 = face.VertexIndices[1] + firstVertex;
|
var index1 = face.VertexIndices[1] + meshObj.BaseVertex;
|
||||||
var index2 = face.VertexIndices[2] + firstVertex;
|
var index2 = face.VertexIndices[2] + meshObj.BaseVertex;
|
||||||
|
|
||||||
AsFbxMeshAddPolygon(mesh, materialIndex, index0, index1, index2);
|
AsFbxMeshAddPolygon(mesh, materialIndex, index0, index1, index2);
|
||||||
}
|
}
|
||||||
|
|
||||||
firstVertex += vertexCount;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var vertexList = importedMesh.VertexList;
|
||||||
|
|
||||||
|
var vertexCount = vertexList.Count;
|
||||||
|
|
||||||
|
for (var j = 0; j < vertexCount; j += 1)
|
||||||
|
{
|
||||||
|
var importedVertex = vertexList[j];
|
||||||
|
|
||||||
|
var vertex = importedVertex.Vertex;
|
||||||
|
AsFbxMeshSetControlPoint(mesh, j, vertex.X, vertex.Y, vertex.Z);
|
||||||
|
|
||||||
|
if (importedMesh.hasNormal)
|
||||||
|
{
|
||||||
|
var normal = importedVertex.Normal;
|
||||||
|
AsFbxMeshElementNormalAdd(mesh, 0, normal.X, normal.Y, normal.Z);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var uvIndex = 0; uvIndex < 2; uvIndex += 1)
|
||||||
|
{
|
||||||
|
if (importedMesh.hasUV[uvIndex])
|
||||||
|
{
|
||||||
|
var uv = importedVertex.UV[uvIndex];
|
||||||
|
AsFbxMeshElementUVAdd(mesh, uvIndex, uv[0], uv[1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (importedMesh.hasTangent)
|
||||||
|
{
|
||||||
|
var tangent = importedVertex.Tangent;
|
||||||
|
AsFbxMeshElementTangentAdd(mesh, 0, tangent.X, tangent.Y, tangent.Z, tangent.W);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (importedMesh.hasColor)
|
||||||
|
{
|
||||||
|
var color = importedVertex.Color;
|
||||||
|
AsFbxMeshElementVertexColorAdd(mesh, 0, color.R, color.G, color.B, color.A);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasBones && importedVertex.BoneIndices != null)
|
||||||
|
{
|
||||||
|
var boneIndices = importedVertex.BoneIndices;
|
||||||
|
var boneWeights = importedVertex.Weights;
|
||||||
|
|
||||||
|
for (var k = 0; k < 4; k += 1)
|
||||||
|
{
|
||||||
|
if (boneIndices[k] < totalBoneCount && boneWeights[k] > 0)
|
||||||
|
{
|
||||||
|
AsFbxMeshSetBoneWeight(pClusterArray, boneIndices[k], j, boneWeights[k]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
if (hasBones)
|
if (hasBones)
|
||||||
{
|
{
|
||||||
IntPtr pSkinContext = IntPtr.Zero;
|
IntPtr pSkinContext = IntPtr.Zero;
|
||||||
@ -646,4 +636,4 @@ namespace AssetStudio.FbxInterop
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -319,79 +319,8 @@ namespace AssetStudio
|
|||||||
}
|
}
|
||||||
ImportedMaterial iMat = ConvertMaterial(mat);
|
ImportedMaterial iMat = ConvertMaterial(mat);
|
||||||
iSubmesh.Material = iMat.Name;
|
iSubmesh.Material = iMat.Name;
|
||||||
iSubmesh.VertexList = new List<ImportedVertex>((int)submesh.vertexCount);
|
iSubmesh.BaseVertex = (int) mesh.m_SubMeshes[i].firstVertex;
|
||||||
for (var j = mesh.m_SubMeshes[i].firstVertex; j < mesh.m_SubMeshes[i].firstVertex + mesh.m_SubMeshes[i].vertexCount; j++)
|
|
||||||
{
|
|
||||||
var iVertex = new ImportedVertex();
|
|
||||||
//Vertices
|
|
||||||
int c = 3;
|
|
||||||
if (mesh.m_Vertices.Length == mesh.m_VertexCount * 4)
|
|
||||||
{
|
|
||||||
c = 4;
|
|
||||||
}
|
|
||||||
iVertex.Vertex = new Vector3(-mesh.m_Vertices[j * c], mesh.m_Vertices[j * c + 1], mesh.m_Vertices[j * c + 2]);
|
|
||||||
//Normals
|
|
||||||
if (iMesh.hasNormal)
|
|
||||||
{
|
|
||||||
if (mesh.m_Normals.Length == mesh.m_VertexCount * 3)
|
|
||||||
{
|
|
||||||
c = 3;
|
|
||||||
}
|
|
||||||
else if (mesh.m_Normals.Length == mesh.m_VertexCount * 4)
|
|
||||||
{
|
|
||||||
c = 4;
|
|
||||||
}
|
|
||||||
iVertex.Normal = new Vector3(-mesh.m_Normals[j * c], mesh.m_Normals[j * c + 1], mesh.m_Normals[j * c + 2]);
|
|
||||||
}
|
|
||||||
//UV
|
|
||||||
iVertex.UV = new float[8][];
|
|
||||||
for (int uv = 0; uv < 8; uv++)
|
|
||||||
{
|
|
||||||
if (iMesh.hasUV[uv])
|
|
||||||
{
|
|
||||||
var m_UV = mesh.GetUV(uv);
|
|
||||||
if (m_UV.Length == mesh.m_VertexCount * 2)
|
|
||||||
{
|
|
||||||
c = 2;
|
|
||||||
}
|
|
||||||
else if (m_UV.Length == mesh.m_VertexCount * 3)
|
|
||||||
{
|
|
||||||
c = 3;
|
|
||||||
}
|
|
||||||
iVertex.UV[uv] = new[] { m_UV[j * c], m_UV[j * c + 1] };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//Tangent
|
|
||||||
if (iMesh.hasTangent)
|
|
||||||
{
|
|
||||||
iVertex.Tangent = new Vector4(-mesh.m_Tangents[j * 4], mesh.m_Tangents[j * 4 + 1], mesh.m_Tangents[j * 4 + 2], mesh.m_Tangents[j * 4 + 3]);
|
|
||||||
}
|
|
||||||
//Colors
|
|
||||||
if (iMesh.hasColor)
|
|
||||||
{
|
|
||||||
if (mesh.m_Colors.Length == mesh.m_VertexCount * 3)
|
|
||||||
{
|
|
||||||
iVertex.Color = new Color(mesh.m_Colors[j * 3], mesh.m_Colors[j * 3 + 1], mesh.m_Colors[j * 3 + 2], 1.0f);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
iVertex.Color = new Color(mesh.m_Colors[j * 4], mesh.m_Colors[j * 4 + 1], mesh.m_Colors[j * 4 + 2], mesh.m_Colors[j * 4 + 3]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//BoneInfluence
|
|
||||||
if (mesh.m_Skin?.Length > 0)
|
|
||||||
{
|
|
||||||
var inf = mesh.m_Skin[j];
|
|
||||||
iVertex.BoneIndices = new int[4];
|
|
||||||
iVertex.Weights = new float[4];
|
|
||||||
for (var k = 0; k < 4; k++)
|
|
||||||
{
|
|
||||||
iVertex.BoneIndices[k] = inf.boneIndex[k];
|
|
||||||
iVertex.Weights[k] = inf.weight[k];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
iSubmesh.VertexList.Add(iVertex);
|
|
||||||
}
|
|
||||||
//Face
|
//Face
|
||||||
iSubmesh.FaceList = new List<ImportedFace>(numFaces);
|
iSubmesh.FaceList = new List<ImportedFace>(numFaces);
|
||||||
var end = firstFace + numFaces;
|
var end = firstFace + numFaces;
|
||||||
@ -405,9 +334,85 @@ namespace AssetStudio
|
|||||||
iSubmesh.FaceList.Add(face);
|
iSubmesh.FaceList.Add(face);
|
||||||
}
|
}
|
||||||
firstFace = end;
|
firstFace = end;
|
||||||
|
|
||||||
iMesh.SubmeshList.Add(iSubmesh);
|
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
|
||||||
|
int c = 3;
|
||||||
|
if (mesh.m_Vertices.Length == mesh.m_VertexCount * 4)
|
||||||
|
{
|
||||||
|
c = 4;
|
||||||
|
}
|
||||||
|
iVertex.Vertex = new Vector3(-mesh.m_Vertices[j * c], mesh.m_Vertices[j * c + 1], mesh.m_Vertices[j * c + 2]);
|
||||||
|
//Normals
|
||||||
|
if (iMesh.hasNormal)
|
||||||
|
{
|
||||||
|
if (mesh.m_Normals.Length == mesh.m_VertexCount * 3)
|
||||||
|
{
|
||||||
|
c = 3;
|
||||||
|
}
|
||||||
|
else if (mesh.m_Normals.Length == mesh.m_VertexCount * 4)
|
||||||
|
{
|
||||||
|
c = 4;
|
||||||
|
}
|
||||||
|
iVertex.Normal = new Vector3(-mesh.m_Normals[j * c], mesh.m_Normals[j * c + 1], mesh.m_Normals[j * c + 2]);
|
||||||
|
}
|
||||||
|
//UV
|
||||||
|
iVertex.UV = new float[8][];
|
||||||
|
for (int uv = 0; uv < 8; uv++)
|
||||||
|
{
|
||||||
|
if (iMesh.hasUV[uv])
|
||||||
|
{
|
||||||
|
var m_UV = mesh.GetUV(uv);
|
||||||
|
if (m_UV.Length == mesh.m_VertexCount * 2)
|
||||||
|
{
|
||||||
|
c = 2;
|
||||||
|
}
|
||||||
|
else if (m_UV.Length == mesh.m_VertexCount * 3)
|
||||||
|
{
|
||||||
|
c = 3;
|
||||||
|
}
|
||||||
|
iVertex.UV[uv] = new[] { m_UV[j * c], m_UV[j * c + 1] };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//Tangent
|
||||||
|
if (iMesh.hasTangent)
|
||||||
|
{
|
||||||
|
iVertex.Tangent = new Vector4(-mesh.m_Tangents[j * 4], mesh.m_Tangents[j * 4 + 1], mesh.m_Tangents[j * 4 + 2], mesh.m_Tangents[j * 4 + 3]);
|
||||||
|
}
|
||||||
|
//Colors
|
||||||
|
if (iMesh.hasColor)
|
||||||
|
{
|
||||||
|
if (mesh.m_Colors.Length == mesh.m_VertexCount * 3)
|
||||||
|
{
|
||||||
|
iVertex.Color = new Color(mesh.m_Colors[j * 3], mesh.m_Colors[j * 3 + 1], mesh.m_Colors[j * 3 + 2], 1.0f);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
iVertex.Color = new Color(mesh.m_Colors[j * 4], mesh.m_Colors[j * 4 + 1], mesh.m_Colors[j * 4 + 2], mesh.m_Colors[j * 4 + 3]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//BoneInfluence
|
||||||
|
if (mesh.m_Skin?.Length > 0)
|
||||||
|
{
|
||||||
|
var inf = mesh.m_Skin[j];
|
||||||
|
iVertex.BoneIndices = new int[4];
|
||||||
|
iVertex.Weights = new float[4];
|
||||||
|
for (var k = 0; k < 4; k++)
|
||||||
|
{
|
||||||
|
iVertex.BoneIndices[k] = inf.boneIndex[k];
|
||||||
|
iVertex.Weights[k] = inf.weight[k];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
iMesh.VertexList.Add(iVertex);
|
||||||
|
}
|
||||||
|
|
||||||
if (meshR is SkinnedMeshRenderer sMesh)
|
if (meshR is SkinnedMeshRenderer sMesh)
|
||||||
{
|
{
|
||||||
//Bone
|
//Bone
|
||||||
@ -524,7 +529,7 @@ namespace AssetStudio
|
|||||||
keyframe.VertexList.Add(destVertex);
|
keyframe.VertexList.Add(destVertex);
|
||||||
var morphVertex = mesh.m_Shapes.vertices[j];
|
var morphVertex = mesh.m_Shapes.vertices[j];
|
||||||
destVertex.Index = morphVertex.index;
|
destVertex.Index = morphVertex.index;
|
||||||
var sourceVertex = GetSourceVertex(iMesh.SubmeshList, (int)morphVertex.index);
|
var sourceVertex = iMesh.VertexList[(int)morphVertex.index];
|
||||||
destVertex.Vertex = new ImportedVertex();
|
destVertex.Vertex = new ImportedVertex();
|
||||||
var morphPos = morphVertex.vertex;
|
var morphPos = morphVertex.vertex;
|
||||||
destVertex.Vertex.Vertex = sourceVertex.Vertex + new Vector3(-morphPos.X, morphPos.Y, morphPos.Z);
|
destVertex.Vertex.Vertex = sourceVertex.Vertex + new Vector3(-morphPos.X, morphPos.Y, morphPos.Z);
|
||||||
@ -1014,20 +1019,6 @@ namespace AssetStudio
|
|||||||
return boneName;
|
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)
|
private void CreateBonePathHash(Transform m_Transform)
|
||||||
{
|
{
|
||||||
var name = GetTransformPathByFather(m_Transform);
|
var name = GetTransformPathByFather(m_Transform);
|
||||||
|
Loading…
Reference in New Issue
Block a user