-
Notifications
You must be signed in to change notification settings - Fork 636
Description
Description
I would like to request adding a vertex_tangents attribute to the trimesh.Trimesh object and updating the GLTF/GLB exporter to include these tangents when saving.
Motivation
The glTF 2.0 specification strongly recommends (and in practice requires for correct rendering) that meshes with a normal map include a TANGENT vertex attribute. This attribute is a VEC4 where the w component indicates the handedness of the tangent basis.
Currently, trimesh handles PBR materials (including normal textures) but does not appear to calculate or export the tangent vectors required to display them correctly. Without tangents, viewers (like three.js, Babylon.js, or model-viewer) must attempt to calculate them at runtime, which often fails or produces lighting artifacts because they lack the original geometry context or use a different algorithm than the MikkTSpace standard.
Proposed Changes
-
Add
vertex_tangentsProperty:
Add avertex_tangentsproperty totrimesh.base.Trimesh, similar tovertex_normals.- It should store a
(n, 4)float array. - Ideally, include a method to calculate these tangents (e.g.,
mesh.calculate_tangents()) using the MikkTSpace algorithm, which is the standard for glTF.
- It should store a
-
Update GLTF Exporter:
Modifytrimesh.exchange.gltf.export_gltf(and internal helper functions) to check forvertex_tangents.- If present, add the
TANGENTaccessor to the mesh primitive attributes in the exported GLB/GLTF file.
- If present, add the
Example Use Case
import trimesh
import numpy as np
# Load a mesh that has a PBR material with a normal map
mesh = trimesh.load('model_with_normal_map.obj')
# Current behavior: Tangents are ignored or missing
# mesh.vertex_tangents # -> AttributeError or None
# Desired behavior:
# Calculate tangents if they don't exist
if mesh.visual.material.normalTexture is not None:
mesh.calculate_tangents()
print(mesh.vertex_tangents.shape)
# -> (N, 4)
# Export to GLB with TANGENT attribute included
mesh.export('model_with_tangents.glb')Additional Context
- glTF Spec Reference: glTF 2.0 Specification - Meshes states: "When normals and tangents are specified, the client implementations SHOULD compute the bitangent... using the handedness stored in the w component of the tangent."
- Why Custom Attributes Aren't Enough: While we can hack this by adding
_TANGENTto vertex_attributes manually, having it as a first-class citizen ensures that operations like subdivision, slicing, or concatenation preserve or re-calculate the tangents correctly. _TANGENT isn't recognized by importers as the TANGENT attribute and requires modifying the gltf json after export from trimesh.