4

I have a .glb glTF file that specifies a character. The character has 75 nodes, and no animation track.

I wrote the following code to render the character, and now I would like to apply some rotation to specific nodes before I render it.

My rendering code is:

import math

import pyrender
import numpy as np
from PIL import Image
import trimesh


def rotation_x(angle_degrees):
    angle = angle_degrees * math.pi / 180
    return np.array([
        [1, 0, 0, 0],
        [0, math.cos(angle), -math.sin(angle), 0],
        [0, math.sin(angle), math.cos(angle), 0],
        [0, 0, 0, 1],
    ])


class Renderer:
    def __init__(self, character_path: str):
        self.mesh = trimesh.load(character_path)

        # Just trying some random rotations
        self.rotate("mixamorig:LeftUpLeg", np.array([0.707, 1.0, 0.0, 0.707]))
        self.rotate("mixamorig:RightHand", np.array([0.707, 5.0, 0.0, 0.707]))
        self.rotate("mixamorig:LeftHand", np.array([0.707, 2.0, 0.0, 0.707]))
        self.rotate("mixamorig:Spine", np.array([1.707, 2.0, 0.0, 0.707]))

        self.scene = self.make_scene()
        self.renderer = pyrender.OffscreenRenderer(viewport_width=1024, viewport_height=1024)

    def rotate(self, node_name: str, quaternion: np.ndarray):
        raise NotImplementedError()

    def make_scene(self):
        # Create a pyrender scene
        scene = pyrender.Scene()

        # Add the mesh to the scene
        for geometry in self.mesh.geometry.values():
            node = pyrender.Mesh.from_trimesh(geometry, smooth=True)
            scene.add(node)

        # Set up a camera with an orthographic projection
        camera = pyrender.PerspectiveCamera(yfov=float(np.radians(54)), aspectRatio=1)
        camera_pose = np.array([
            [1, 0, 0, 0],
            [0, 1, 0, 3.5],  # Move the camera 1 meter up in the y-axis
            [0, 0, 1, 4],
            [0, 0, 0, 1],
        ]) @ rotation_x(-20)
        scene.add(camera, pose=camera_pose)

        # Set up a directional light
        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


    def __call__(self):
        color, depth = self.renderer.render(self.scene)
        return color, depth

I have tried many solutions, but to no avail. This solution returns no errors, but also does not perform the rotation.

def rotate(self, node_name: str, quaternion: np.ndarray):
    rotation_matrix = trimesh.transformations.quaternion_matrix(quaternion)
    self.mesh.graph[node_name][0].setflags(write=1)
    self.mesh.graph[node_name][0][:] = rotation_matrix

How can I control the rotation of a specific node before rendering it?

For testing purposes, the character I am using is: https://firebasestorage.googleapis.com/v0/b/sign-mt-assets/o/3d%2Fcharacter.glb?alt=media

0x01010
  • 168
  • 12
Amit
  • 5,924
  • 7
  • 46
  • 94
  • So you have a file similar to [this](https://sketchfab.com/3d-models/ankit-avatar-rigged-with-expression-shape-key-787c30f613a740f2b5063ba2064b1788) for example, right? Can you share your file, please? – blunova Apr 19 '23 at 14:08
  • Thanks @blunova, I added a download link – Amit Apr 20 '23 at 08:58
  • 1
    Well, I tried but unfortunately I failed. The following code does not return any error `mesh.graph["mixamorig:LeftUpLeg"] = transforms.transformations.rotation_matrix(45, [10, -50, 0], [0, 0, 0])`, however when I export the mesh nothing changes. If I reload the mesh, the transformation matrix is actually updated, but for whatever reason the character is unchanged. – blunova Apr 20 '23 at 23:58

1 Answers1

0

Try using the graph.update method like so.

    node = s.graph.nodes_geometry[0]
    # apply the transform to the node
    scene.graph.update(node, matrix=matrix)

https://github.com/mikedh/trimesh/blob/bad28b4f4d2d6eb9857b3a970293d00ae4bdbb79/examples/viewcallback.py#L33C1-L36C1

freakTheMighty
  • 1,172
  • 1
  • 12
  • 27