Animated 3D Models#

Script for loading animated 3D models (glTF 2.0 / GLB)

This script turns a keyframe-animated glTF 2.0 or GLB file into ordinary RadarSimPy target dictionaries. Each animated node of the model becomes its own target carrying per-timestamp location/speed/rotation/ rotation_rate arrays sampled at radar.time_prop["timestamp"], so a spinning rotor, a turning wheel or a keyframed flight path is simulated with the motion authored in the 3D file rather than re-derived by hand.

Only rigid node animation is supported. Skinning, morph targets and animated scale would require per-timestep vertex geometry, which the ray tracer does not model; those inputs raise a descriptive error.

██████╗  █████╗ ██████╗  █████╗ ██████╗ ███████╗██╗███╗   ███╗██╗  ██╗
██╔══██╗██╔══██╗██╔══██╗██╔══██╗██╔══██╗██╔════╝██║████╗ ████║╚██╗██╔╝
██████╔╝███████║██║  ██║███████║██████╔╝███████╗██║██╔████╔██║ ╚███╔╝
██╔══██╗██╔══██║██║  ██║██╔══██║██╔══██╗╚════██║██║██║╚██╔╝██║ ██╔██╗
██║  ██║██║  ██║██████╔╝██║  ██║██║  ██║███████║██║██║ ╚═╝ ██║██╔╝ ██╗
╚═╝  ╚═╝╚═╝  ╚═╝╚═════╝ ╚═╝  ╚═╝╚═╝  ╚═╝╚══════╝╚═╝╚═╝     ╚═╝╚═╝  ╚═╝
radarsimpy.animation_kit.import_gltf_module()[source]#

Import the glTF parsing module used to read animated models

Returns:

The pygltflib module object

Return type:

object

Raises:

ImportError – If pygltflib is not installed

radarsimpy.animation_kit.load_animated_model(filename, *, animation=None, unit='m', up_axis='y', merge_static=True)[source]#

Load an animated glTF 2.0 / GLB model and split it into rigid parts

Geometry is grouped by the nearest animated ancestor node, so each returned part moves as one rigid body. Parts are expressed in their own node frame, which is the frame their sampled pose applies to.

Parameters:
  • filename (str) – Path to a .gltf or .glb file

  • animation (str | int | None) – Animation name or index to read. Default: the first one.

  • unit (str) – Unit the file is authored in ('m', 'cm', 'mm'). Default: 'm', which is what the glTF specification mandates.

  • up_axis (str) – Up axis of the file, 'y' (glTF default) or 'z'. Geometry and motion are rotated into RadarSimPy’s Z-up frame.

  • merge_static (bool) – Merge all non-animated geometry into a single part. Default: True.

Returns:

Dictionary containing:

  • parts (list): One entry per rigid part, each a dict with name, points, cells, node and animated.

  • animation (str or None): Name of the selected animation.

  • animations (list): Names of every animation in the file.

  • duration (float): Length of the selected animation in seconds.

  • start_time (float): Time of its first keyframe in seconds.

Return type:

dict

Raises:

NotImplementedError – For skinning, morph targets, animated scale, non-uniform scale on an animated node, or non-triangle primitives.

radarsimpy.animation_kit.load_animated_targets(filename, radar=None, *, at_time=None, animation=None, time_offset=0.0, time_scale=1.0, loop=True, location=(0, 0, 0), speed=(0, 0, 0), rotation=(0, 0, 0), rotation_rate=(0, 0, 0), unit='m', up_axis='y', merge_static=True, **target_kwargs)[source]#

Build RadarSimPy target dictionaries from an animated glTF 2.0 / GLB model

Each animated node of the model becomes one target whose location, speed, rotation and rotation_rate are arrays sampled at radar.time_prop["timestamp"], so the motion authored in the file drives both the geometry and the Doppler. Non-animated geometry becomes a single static target.

The returned list is passed straight to radarsimpy.sim_radar():

>>> targets = load_animated_targets("turbine.glb", radar, location=(50, 0, 0))
>>> data = sim_radar(radar, targets)

Only rigid node animation is supported. Skinned meshes, morph targets and animated scale raise NotImplementedError, because the ray tracer transforms each target rigidly and cannot move individual vertices.

Note

Every animated part allocates twelve float32 arrays the size of radar.time_prop["timestamp"]. Models with many independently moving parts, simulated over long time records, use a correspondingly large amount of memory. Merge parts that do not move independently to reduce it.

Parameters:
  • filename (str | Dict[str, Any]) – Path to a .gltf/.glb file, or a model already returned by load_animated_model().

  • radar (Any) – radarsimpy.Radar whose timestamps the animation is sampled at. Required unless at_time is given.

  • at_time (float | None) – Sample a single instant instead, returning static targets. Use this for radarsimpy.sim_rcs() and radarsimpy.sim_lidar(), which do not accept time-varying motion.

  • animation (str | int | None) – Animation name or index. Default: the first one.

  • time_offset (float) – Animation time at simulation time zero (s).

  • time_scale (float) – Playback rate; 2.0 plays twice as fast.

  • loop (bool) – Wrap the animation when the simulation outlasts the clip. When False the first and last poses are held. Default: True.

  • location (Sequence[float]) – Position of the whole model in the global frame [x, y, z] (m).

  • speed (Sequence[float]) – Velocity of the whole model [vx, vy, vz] (m/s).

  • rotation (Sequence[float]) – Orientation of the whole model [yaw, pitch, roll] (deg).

  • rotation_rate (Sequence[float]) – Rotation rate of the whole model [yaw rate, pitch rate, roll rate] (deg/s).

  • unit (str) – Unit the file is authored in. Default: 'm'.

  • up_axis (str) – Up axis of the file, 'y' or 'z'. Default: 'y'.

  • merge_static (bool) – Merge all non-animated geometry into one target.

  • target_kwargs (Any) – Extra keys copied into every target dictionary, such as permittivity, permeability, skip_diffusion, density and environment.

Returns:

Target dictionaries ready for radarsimpy.sim_radar()

Return type:

list

Raises:

ValueError – If neither radar nor at_time is provided