SMPL
SMPLBody and SmplPoseDeformation in witwin.radar.smpl, for posing an SMPL human mesh and moving it through a Radar scene.
witwin.radar.smpl wraps the SMPL body model. It needs the smpl extra (smplpytorch and OpenCV), imported at first use, and the SMPL model files, which you download from the SMPL authors. See Simulate SMPL humans.
from witwin.radar.smpl import SMPLBody, SmplPoseDeformationSMPLBody#
class SMPLBody(pose, shape, *, position=(0.0, 0.0, 0.0), gender='male', model_root=None, rotation=None, device=None)An SMPL body as a witwin.core geometry (kind == "smpl") with a position and rotation. A requires_grad pose or shape reaches the vertices it publishes.
Axis-angle rotation of 24 joints, 3 values each, rad.
Shape coefficients.
(0.0, 0.0, 0.0)World position, m.
'male'Which model file to load from model_root, for example "male", "female" or "neutral".
NoneFolder that holds the SMPL model files. None points to a models/smpl_models folder next to the installed witwin package, which a pip install does not have, so pass it explicitly.
NoneBody rotation. None is no rotation.
NoneDevice for the posing function.
Raises ImportError naming smplpytorch or OpenCV at first use if the smpl extra is missing.
SMPLBody.to_mesh#
SMPLBody.to_mesh(segments=16, *, device=None) -> tuple[torch.Tensor, torch.Tensor]The posed mesh as (vertices, faces), with position and rotation applied. SMPL has 6890 vertices. segments is part of the Core geometry interface.
SMPLBody.updated#
SMPLBody.updated(**changes) -> SMPLBodyA new body with some fields changed. Accepts pose, shape, position, gender, model_root, rotation and device.
Raises TypeError for any other keyword.
import torch
body = SMPLBody(pose=torch.zeros(72), shape=torch.zeros(10), gender="neutral",
model_root="path/to/smpl_models", position=(0.0, 0.0, -4.0), device="cuda")
vertices, faces = body.updated(pose=new_pose).to_mesh()SmplPoseDeformation#
class SmplPoseDeformation(body, *, pose_rate, reference_time_s=0.0, device=None)A posed SMPL body as a witwin.core.dynamics deformation over a fixed rest mesh. Face indexing and material assignment stay fixed and only the vertices move, so Radar can replay a frozen path topology against the moving body. The pose changes linearly in time: pose(t) = body.pose + pose_rate · (t - reference_time_s).
The body at reference_time_s.
Pose derivative, rad/s, in the same joint layout as the pose. It is a direction, not a leaf, so it must not carry a gradient.
0.0Time at which the pose equals body.pose, s.
NoneDevice. None uses the body's device.
Raises
TypeErrorifbodyis not anSMPLBody.ValueErrorifpose_ratehas a different number of entries than the pose.RuntimeErrorif the body's pose or shape, orpose_rate, carries a gradient or a forward tangent. Derivatives do not cross the Core/Channel compile boundary through this route.
| Member | Returns |
|---|---|
pose_rate | The pose rate tensor. |
pose_at(time_s) | Pose at time_s. |
vertices_at(time_s) | Posed vertices at time_s. |
velocity_at(time_s) | Exact vertex velocity d(vertices)/dt, from forward-mode differentiation of the skinning, one row per vertex. |
at(time_s) | The witwin.core deformation state at time_s. |
rest_mesh(**mesh_kwargs) | The rest Mesh for a Structure, built with recenter=False and with the body's position and rotation applied. Raises RuntimeError if the position or rotation carries a gradient. |
from witwin.core.dynamics import DynamicScene
deformation = SmplPoseDeformation(body, pose_rate=pose_rate)
scene = Scene(structures=(Structure(geometry=deformation.rest_mesh(), material=skin, structure_id=7,
material_id=1, assignment_id=1, surface_id=1),), endpoints=[])
world = DynamicScene(scene, structure_deformations={7: deformation})The mesh reflects and occludes but adds no scatterers. To make the body return energy, place PointTargets on its surface as in Simulate SMPL humans.