如何在trimesh中对glb模型的指定节点施加旋转?
解决GLB模型特定节点旋转渲染问题
你之前的方法无效,核心原因有两个:
- 直接遍历
self.mesh.geometry.values()添加到pyrender场景时,丢失了trimesh场景的节点层级和变换信息——GLB模型的网格存储在本地坐标系,节点变换是相对于父节点的,直接取几何不会应用这些变换。 - 传入的四元数未归一化,导致生成的旋转矩阵包含缩放,无法实现纯旋转。
以下是完整的修复方案:
步骤1:修复rotate方法,正确处理四元数与节点变换
def rotate(self, node_name: str, quaternion: np.ndarray): # 归一化四元数,确保是单位长度(纯旋转的必要条件) quaternion = quaternion / np.linalg.norm(quaternion) # 将四元数转换为4x4旋转矩阵(trimesh使用scipy格式,四元数顺序为[x,y,z,w]) rotation_matrix = trimesh.transformations.quaternion_matrix(quaternion) # 获取节点当前的变换矩阵,保留原有平移信息,替换旋转部分 current_transform = self.mesh.graph[node_name][0] rotation_matrix[:3, 3] = current_transform[:3, 3] # 修改节点变换(需解除数组只读限制) self.mesh.graph[node_name][0].setflags(write=1) self.mesh.graph[node_name][0][:] = rotation_matrix
步骤2:重构make_scene方法,保留节点层级与变换
原来的方法直接添加原始几何,现在需要遍历trimesh场景的节点层级,将每个节点的变换应用到pyrender节点上:
def make_scene(self): scene = pyrender.Scene() # 递归遍历trimesh节点,构建pyrender节点层级 def add_trimesh_node(trimesh_node_name, parent_pyrender_node=None): # 获取当前节点的变换矩阵(相对于父节点) node_transform = self.mesh.graph[trimesh_node_name][0] # 如果节点绑定了几何,创建pyrender网格节点 if trimesh_node_name in self.mesh.geometry: trimesh_mesh = self.mesh.geometry[trimesh_node_name] pyrender_mesh = pyrender.Mesh.from_trimesh(trimesh_mesh, smooth=True) pyrender_node = pyrender.Node(mesh=pyrender_mesh, matrix=node_transform) scene.add(pyrender_node, parent=parent_pyrender_node) parent_pyrender_node = pyrender_node # 递归添加子节点 for child_node in self.mesh.graph.children.get(trimesh_node_name, []): add_trimesh_node(child_node, parent_pyrender_node) # 从场景根节点开始遍历添加 for root_node in self.mesh.graph.roots: add_trimesh_node(root_node) # 相机与灯光设置保持不变 camera = pyrender.PerspectiveCamera(yfov=float(np.radians(54)), aspectRatio=1) camera_pose = np.array([ [1, 0, 0, 0], [0, 1, 0, 3.5], [0, 0, 1, 4], [0, 0, 0, 1], ]) @ rotation_x(-20) scene.add(camera, pose=camera_pose) light = pyrender.DirectionalLight(color=np.ones(3), intensity=3.0) light_pose = np.array([ [1, 0, 0, 0], [0, 1, 0, 5], [0, 0, 1, 3], [0, 0, 0, 1], ]) scene.add(light, pose=light_pose) return scene
关键说明
- 节点层级保留:通过递归遍历trimesh的场景节点,确保每个网格都应用了对应的节点变换,子节点会自动继承父节点的变换效果。
- 四元数归一化:必须保证四元数是单位长度,否则旋转矩阵会引入缩放,导致模型变形或旋转失效。
- 变换矩阵处理:保留节点原有平移信息,仅替换旋转部分,避免修改节点位置。
内容的提问来源于stack exchange,提问作者Amit
相关产品推荐
相关产品推荐

