We are working with huge 3D mesh objects and are evaluating the Aspose library.
We Aspose reads the obj or fbx files we get 1 Mesh ChildNode with a million materials. When using Assimp we get 4 meshes and 4 materials. How can we merge all these materials during import and how can we get the 4 sub-meshes (1 per texture) instead of 1 huge mesh?
@njannink
To merge materials and split a large mesh into sub-meshes based on texture using Aspose.3D, follow these steps:
- Load the 3D model: Use the appropriate loading method for your file type (e.g., OBJ or FBX).
- Iterate through the mesh: Access the mesh nodes and their materials.
- Group by texture: Create a dictionary or similar structure to group sub-meshes by their textures.
- Create new sub-meshes: For each unique texture, create a new mesh and assign the corresponding vertices and materials.
Here’s a basic example in C#:
using Aspose.ThreeD;
using Aspose.ThreeD.Entities;
using System.Collections.Generic;
public void SplitMeshByTexture(string filePath)
{
// Load the 3D model
Scene scene = new Scene();
scene.Open(filePath);
// Dictionary to hold sub-meshes by texture
Dictionary<string, Mesh> subMeshes = new Dictionary<string, Mesh>();
foreach (var node in scene.RootNode.ChildNodes)
{
if (node is Mesh mesh)
{
foreach (var material in mesh.Materials)
{
string texturePath = material.DiffuseTexture?.FilePath;
if (!subMeshes.ContainsKey(texturePath))
{
subMeshes[texturePath] = new Mesh();
}
// Add vertices and indices to the sub-mesh based on the texture
// This part requires more detailed implementation based on your mesh structure
}
}
}
// Now you can save or further process the sub-meshes
}
This code provides a starting point. You will need to implement the logic for copying vertices and indices to the new sub-meshes based on the textures.
For further details, please consult the official Aspose.3D documentation directly within your development environment.
@njannink
Could you share the IFC file that’s giving you trouble? It would help me reproduce the exact issue you’re seeing and make sure the examples I’m working on address your specific case.
Thanks.
Sorry I cannot share the obj or fbx files because they are proprietary.
I use this algorithm now. The shapes of the sub-meshes seems to be fine, but the textures / uvs are completely distored. Maybe you have an idea why?
Dictionary<string, Mesh> meshes = new();
foreach (var child in root.ChildNodes.Where(x => x.Entity is Mesh))
{
var mesh = ((Mesh) child.Entity).Triangulate();
var materialVertex = mesh.VertexElements.OfType<VertexElementMaterial>().First();
var uvVertex = mesh.VertexElements.OfType<VertexElementUV>().First();
foreach (var material in child.Materials)
{
if (material.GetTexture(Material.MapDiffuse) is Texture tex && !meshes.ContainsKey(tex.FileName))
{
var index = meshes.Count;
meshes[tex.FileName] = new()
{
Index = index,
Uvs = [],
Trimesh = new() { Tris = [], Vertices = [] }
};
}
}
var polygonMap = new int[mesh.ControlPoints.Count, meshes.Count];
for (int i = 0; i < mesh.PolygonCount; i++)
{
var materialIndex = materialVertex.Indices[i];
var material = child.Materials[materialIndex];
var slot = material.GetTexture(Material.MapDiffuse) as Texture;
if (slot == null) continue;
if (!meshes.TryGetValue(slot.FileName, out var part)) continue;
var trimesh = part.Trimesh;
var polygon = mesh.Polygons[i];
var p1 = MapPolygonVertices(polygon[0]);
var p2 = MapPolygonVertices(polygon[1]);
var p3 = MapPolygonVertices(polygon[2]);
trimesh.Tris.AddRange([p1 - 1, p2 - 1, p3 - 1]);
continue;
int MapPolygonVertices(int p)
{
// 1-based index in map, 0 means not mapped yet
if (polygonMap[p, part.Index] == 0)
{
polygonMap[p, part.Index] = trimesh.Vertices.Count + 1;
var cp = mesh.ControlPoints[p];
trimesh.Vertices.Add(new float3
{
X = (float) cp.X,
Y = (float) cp.Y,
Z = (float) cp.Z
});
var uv = uvVertex.Data[uvVertex.Indices[p]];
part.Uvs.Add(new float2
{
X = (float) uv.X % 1f,
Y = (float) uv.Y % 1f
});
}
return polygonMap[p, part.Index];
}
}
}
@njannink
There’s no methods to merge materials directly, do you have duplicated(by reference or by definition) materials in the “million” materials?
Maybe you can try PolygonModifier.SplitMesh which allows you to split Mesh
to sub meshes by materials defined in VertexElementMaterial
:
Thanks.
The obj file in question has almost a million materials and only 4 texture files after loading the obj file. Assimp has the option to merge materials does Aspose have this option?
@njannink
We have opened the following new ticket(s) in our internal issue tracking system and will deliver their fixes according to the terms mentioned in Free Support Policies.
Issue ID(s): THREEDNET-1728
You can obtain Paid Support Services if you need support on a priority basis, along with the direct access to our Paid Support management team.
If I use the SplitMesh option on the obj file in question I run out of memory (64GB) while without split I can load the file. I will check with my team if I can share the obj.
If you mail me on my registered email I can share a download link to the obj file in question
Hi @njannink, I don’t have your email, can you please share me the file to lex.chou@aspose.com?
The file will be only used for analyzing the issue, and will be removed once the issue fixed.
Thanks!
Hi Lex I send the file through wetransfer because its big. This is what I do now to merge all the materials.
private static void RepairMaterials(Node root)
{
var original = (Mesh) root.Entity;
var materialVertex = original.VertexElements.OfType<VertexElementMaterial>().FirstOrDefault();
if (root.Materials.Count == 0 || materialVertex == null)
{
return;
}
var newMaterials = root.Materials
.GroupBy(x => x.Name)
.Select(x => x.First())
.ToList();
var materialIndex = newMaterials
.Select((m, i) => (m, i))
.ToDictionary(x => x.m.Name, y => y.i);
var newMapping = materialVertex
.Indices
.Select(i => materialIndex[root.Materials[i].Name])
.ToArray();
root.Materials.Clear();
foreach (var mat in newMaterials)
{
root.Materials.Add(mat);
}
materialVertex.Clear();
materialVertex.SetIndices(newMapping);
}
@njannink
Got the file, thanks! We’ll work through the issues next week.