Source code for simvx.core.nodes_3d.mesh

"""MeshInstance3D -- visible 3D mesh node."""

from __future__ import annotations

import numpy as np

from ..descriptors import Property
from ..helpers import mat4_from_trs
from .node3d import Node3D


[docs] class MeshInstance3D(Node3D): """Visible 3D object. Holds a Mesh and Material for the renderer. Set ``skin`` to a :class:`~simvx.core.skeleton.Skeleton` node to enable skeletal animation. The renderer reads ``skin.joint_matrices`` each frame to upload bone transforms for vertex skinning. Usage: from simvx.core.graphics.mesh import Mesh from simvx.core.graphics.material import Material mi = MeshInstance3D(mesh=Mesh.cube(), material=Material(colour=(1, 0, 0))) # Skeletal mesh: mi.skin = skeleton_node """ lod_bias = Property(0.0, range=(-10.0, 10.0), hint="LOD distance bias (positive = prefer coarser)") def __init__(self, mesh=None, material=None, skin=None, **kwargs): super().__init__(**kwargs) self.mesh = mesh self.material = material # defaults to white in renderer if None self._skin = None if skin is not None: self.skin = skin @property def skin(self): """Skeleton node providing joint matrices for vertex skinning. Accepts a :class:`~simvx.core.skeleton.Skeleton` instance (or ``None`` to disable skinning). Assigning a skeleton does *not* reparent it; the skeleton should already be part of the scene tree. """ return self._skin @skin.setter def skin(self, value): from ..skeleton import Skeleton if value is not None and not isinstance(value, Skeleton): raise TypeError(f"skin must be a Skeleton node or None, got {type(value).__name__}") self._skin = value @property def model_matrix(self) -> np.ndarray: """Model transform matrix from global position/rotation/scale.""" return mat4_from_trs(self.world_position, self.world_rotation, self.world_scale)