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)