在c#中按每个Bolygon的材质分割网格

问题描述 投票:0回答:1

我有一个包含 FBX 网格日期的类

其中 VertexData 具有顶点数据,例如位置、uv、颜色...等

材质有这个网格的材质

VertexIndices 是三角形面索引

MaterialIndices 是每个三角形的材质索引

我希望能够通过 bolygon 材质将 FBXMeshData 拆分为列表

public class FBXMeshData { public string Name { get; set; } public Vector3 Position { get; set; } public Vector3 Rotation { get; set; } public Vector3 Scale { get; set; } private List<FBXVertexData> VertexData { get; set; } public List<FBXMaterialData> Materials { get; set; } = new List<FBXMaterialData>(); private List<int> VertexIndices { get; set; } public List<int> MaterialIndices { get; set; } public FBXMeshData(FBXMeshData meshData) { Name = meshData.Name; Position = meshData.Position; Rotation = meshData.Rotation; Scale = meshData.Scale; VertexData = meshData.VertexData.Select(x => new FBXVertexData(x.Position, x.Normal, x.Tangents, x.UVs, x.Colors, x.BoneNames.ToArray(), x.BoneWeights.ToArray())) .ToList(); VertexIndices = meshData.VertexIndices; MaterialIndices = meshData.MaterialIndices; if (meshData.MaterialIndices != null) { for (int i = 0; i < meshData.Materials.Count; i++) { Materials.Add(meshData.Materials[i]); } } } public FBXMeshData(FbxMeshData meshData) { Name = meshData.Name; Position = MySF.ToVector3(meshData.Position); Rotation = MySF.QToYawPitchRoll(meshData.Rotation); Scale = MySF.ToVector3(meshData.Scale); VertexData = meshData.VertexData.Select(x => new FBXVertexData(x.Position, x.Normal, x.Tangents, x.UVs, x.Colors, x.BoneNames.ToArray(), x.BoneWeights.ToArray())) .ToList(); VertexIndices = meshData.VertexIndices; MaterialIndices = meshData.MaterialIndices; if (meshData.MaterialIndices != null) { for (int i = 0; i < meshData.MaterialData.Count; i++) { Materials.Add(new FBXMaterialData(meshData.MaterialData[i])); } } } }
我的想法:MaterialIndices中的每个materialindex都指向由VertexIndices中的三个整数组成的多边形,每个整数是VertexData中一个Vertex的索引

首先我检查网格是否有材质或没有材质,然后按原样返回网格 如果不 按材质索引按多边形索引对顶点进行分组 字典

>>>materialToFacetoVertex = 新字典>>>(); 所以每种材质都有一个面列表,每个面都有它的顶点

为每个材质组创建一个新的网格

public static List<FBXMeshData> SplitByMaterial(FBXMeshData meshData) { if (meshData.Materials.Count == 0 || meshData.Materials.Count == 1) { return new List<FBXMeshData> { meshData }; } // Group vertices by polygon index and material index var materialToFaceToVertex = new Dictionary<int, Dictionary<int, List<FBXVertexData>>>(); //int faceindex = 0; for (int i = 0; i < meshData.MaterialIndices.Count; i++) { int materialIndex = meshData.MaterialIndices[i]; FBXVertexData vertex = meshData.VertexData[meshData.VertexIndices[i]]; FBXVertexData vertex1 = meshData.VertexData[meshData.VertexIndices[i+1]]; FBXVertexData vertex2 = meshData.VertexData[meshData.VertexIndices[i+2]]; int faceindex =i; if (!materialToFaceToVertex.TryGetValue(materialIndex, out var faceToVertex)) { faceToVertex = new Dictionary<int, List<FBXVertexData>>(); materialToFaceToVertex[materialIndex] = faceToVertex; } if (!faceToVertex.TryGetValue(faceindex, out var vertexList)) { vertexList = new List<FBXVertexData>(); faceToVertex[faceindex] = vertexList; } vertexList.Add(vertex); vertexList.Add(vertex1); vertexList.Add(vertex2); } // Create separate mesh data for each material group var meshList = new List<FBXMeshData>(); foreach (var kvp in materialToFaceToVertex) { var materialIndex = kvp.Key; var faceToVertex = kvp.Value; FBXMaterialData materialData = meshData.Materials[kvp.Key]; string materialName = materialData.Name; var newMeshData = new FBXMeshData(meshData) { Name = materialName, Materials = new List<FBXMaterialData> { materialData }, VertexData = new List<FBXVertexData>(), VertexIndices = new List<int>(), MaterialIndices = new List<int> { 0 }, }; int currentvertindex = 0; foreach (var faceVertices in faceToVertex.Values) { newMeshData.VertexData.AddRange(faceVertices); // Add indices for the current triangle (assuming triangles) newMeshData.VertexIndices.Add(currentvertindex); newMeshData.VertexIndices.Add(currentvertindex + 1); newMeshData.VertexIndices.Add(currentvertindex + 2); currentvertindex += 3; // Increment by 3 for each triangle's vertices } meshList.Add(newMeshData); } StringBuilder sb = new StringBuilder(); foreach (var mes in meshList) { sb.AppendLine(mes.ToString()); } MainWindow.debug.texView.Text = sb.ToString(); return meshList; }
但是此方法的输出有重复的顶点且索引错误

有人可以帮我吗?

图像显示了一个简单立方体的结果,其中每两个三角形(四边形)都有单独的材质


enter image description here 顺便说一句,这是我如何从 fbx sdk 获取材质索引

List<int>^ FbxSceneData::GetMaterialIndices(FbxMesh* fbxMesh) { List<int>^ materialIndices = gcnew List<int>(); FbxLayerElementMaterial* materialLayer = fbxMesh->GetLayer(0)->GetMaterials(); if (materialLayer) { FbxLayerElement::EMappingMode mappingMode = materialLayer->GetMappingMode(); if (mappingMode == FbxLayerElement::eByPolygon) { int polygonCount = fbxMesh->GetPolygonCount(); for (int p = 0; p < polygonCount; p++) { int materialIndex = materialLayer->GetIndexArray().GetAt(p); materialIndices->Add(materialIndex); // Now you have the material index for this polygon // You can use it to retrieve the material for further processing // FbxSurfaceMaterial* material = mesh->GetNode()->GetMaterial(materialIndex); // ... (do something with the material index) } } else if (mappingMode == FbxLayerElement::eAllSame) { // In this case, all polygons share the same material, and the material index is 0 int materialIndex = materialLayer->GetIndexArray().GetAt(0); materialIndices->Add(materialIndex); } else { // Other mapping modes are not supported in this example } } else { // The mesh does not have any material information } return materialIndices; }
    
c# wpf 3d
1个回答
0
投票
我可以轻松地在一个 linq 语句中创建字典。但是你的类必须正确定义。每个顶点都必须有一个材质。类应该是这样的

public class FBXMeshData { public string Name { get; set; } public Vector3 Position { get; set; } public Vector3 Rotation { get; set; } public Vector3 Scale { get; set; } private List<FBXVertexData> VertexData { get; set; } } public class FBXMaterialData { } public class FBXVertexData { FBXMaterialData material { get; set; } }
    
© www.soinside.com 2019 - 2024. All rights reserved.