// Sensors
Sensor performance and troubleshooting
How sensor count, resolution and passes change render time, GPU memory and cloud price; the limits; and the rig errors you can hit, with their fixes.
Render time#
A 3D render draws every camera at every one of its frames, so its time grows with the number of cameras x pixels x frames, plus a fixed cost to load the map. Lidar and radar add ray casts and a review video each. Measured on an RTX 5080 with the three example rigs on easterbrook-discovery-school, a 10 second scenario:
| Rig | Preset | Frames written | Render time | Of which drawing | Output on disk |
|---|---|---|---|---|---|
| Front camera, 1280x720 | showcase | 200 x 4 passes | 15.3 s | 9.1 s | 0.9 GB |
| Seven cameras, 1280x720 | training | 1400 x 4 passes | 36.0 s | 23.8 s | 6.3 GB |
| Camera, lidar and radar | showcase | 200 x 4 passes, 200 scans, 200 radar frames | 25.6 s | 14.8 s | 1.8 GB |
Peak GPU memory stayed under 2.5 GiB for all three, with full textures. Most of the rest of the time is encoding the videos (10.9 s for the seven cameras) and loading the map and actors (about 3 s). A single simforge preview frame took 9 s.
To render faster: use --preset training, lower width and height, render a part of the scenario with the rig's clip, ask only for the passes you need (--passes rgb), and skip videos you do not need (--video off). Check a mount with simforge preview frame before a full render.
GPU memory#
GPU memory depends far more on the map and the texture tier than on the cameras. On san-ramon-phase-1 with full textures, one 1280x720 camera peaks at 11.3 GiB and six 1920x1080 cameras at 11.9 GiB; with 512 px textures (--textures bc7-512), 3.8 and 4.5 GiB. The full table per map is in Preview and render. A render that does not fit fails with native_gpu_out_of_memory: use --textures bc7-512, fewer or smaller cameras, or --cloud.
Cloud price#
A cloud render's price does not depend on the rig: more cameras, lidar or radar do not change it, and 2D renders are free. --dry-run shows the price before anything runs, and --max-cost caps it (Run in the cloud). A cloud render returns each sensor's video, render.json and results.json; render locally for the per-frame images, depth and point clouds.
Limits#
| What | Limit |
|---|---|
| Sources in a rig | 1 to 64 |
| Camera size | 64 to 8192 pixels in the file; the renderer draws at most 4096x4096 |
| Camera frame rate | above 0, up to 240 fps |
| Pinhole field of view | above 0, up to 180 degrees |
| Lidar | 1 to 256 channels, range up to 1000 m, up to 240 revolutions per second, symmetric vertical field |
| Radar | fields up to 180 degrees, range up to 1000 m, at least one ray per frame |
| Rotation | yaw and roll -pi to pi, pitch -pi/2 to pi/2, in radians |
Rig errors and fixes#
simforge rig validate prints one JSON error and exits 2. These are its real messages:
Message (render_rig_invalid) | Fix |
|---|---|
sources[0].attributes: unknown field fx, expected one of width, height, fps, horizontalFovDeg, nearM, farM, cameraModel | The rig has no fx/fy/cx/cy: give horizontalFovDeg = 2 x atan(width / (2 x fx)) in degrees |
sources[0]: a camera declares exactly one of horizontalFovDeg and cameraModel | Keep the field of view or the lens, not both and not neither |
sources[0]: camera size 10000x720 is outside 64..8192 | Lower width or height (the renderer draws at most 4096) |
sources[0]: fps 0 is outside (0, 240] | Give a frame rate above 0 |
sources[0]: nearM must be positive and farM greater than nearM | Use nearM 0.05 and farM 1000 unless you need others |
sources[6]: transform.rotation is outside yaw/roll [-pi, pi], pitch [-pi/2, pi/2] | A rear camera is yaw 3.14159, not 3.1416; a downward camera is pitch -1.5708 |
duplicate source outputName "cam-front" | Give every source its own outputName |
sources[0]: outputName "front cam" must match ^[A-Za-z0-9][A-Za-z0-9_-]{0,63}$ | Use letters, digits, - and _, no spaces |
sources[0].modality "thermal" (rgb|depth|semantic|instance|lidar|radar) | Thermal is not supported; use rgb, lidar or radar |
rig schema "simforge.render-rig/v2" (expected simforge.render-rig/v1) | Set schema to simforge.render-rig/v1 |
A render then checks what the renderer supports; its errors are listed in the rig file reference. The most common:
| Error | Fix |
|---|---|
native_modality_unsupported | A depth, semantic or instance source: make it rgb and choose passes with --passes |
native_lidar_asymmetric_fov_unsupported | Make the lidar's field symmetric: upperFovDeg = -lowerFovDeg |
render_schedule_invalid (a radar) | Add video to the rig; its fps is the radar's sample rate |
native_camera_size_unsupported | Keep cameras at 4096x4096 or smaller |
render_ego_missing | The scenario has no ego: simforge scenario apply s.json set-ego --role-id <actor> |
preview_camera_unknown | --camera takes a camera's outputName; the error lists the rig's cameras |
out_not_empty | --out must be a new or empty folder; a failed render can leave <out>.input behind: remove it too |
FAQ#
My images are mirrored left to right, or a side camera shows the wrong side. The frame is x forward, y up, z left, and yaw is positive to the left. A calibration in a right-handed frame needs converting. simforge rig show names each sensor's facing.
Can I give fx, fy, cx and cy? Not yet. A pinhole camera is square-pixelled with the principal point at the centre: set horizontalFovDeg = 2 x atan(width / (2 x fx)). For a lens with distortion, fit an f-theta polynomial.
Which distortion models are supported? The f-theta polynomial only. Brown-Conrady (OpenCV), Kannala-Brandt and equidistant fisheye are not supported yet.
Do I need one rig per scenario? No. A rig names no scenario: pass the same file to every render. Every source is mounted on the scenario's ego.
Do I need one rig per vehicle? Positions are absolute metres, so a car rig on a truck keeps the car's mount heights. Write one rig per vehicle class, or start from simforge rig init --preset <preset> --class <class>.
Can Studio use my rig file? Not yet: Studio offers the built-in rigs and the rig a scenario last rendered with. Render your rig with the CLI, locally or with --cloud.
Why does my cloud render have no PNGs or point clouds? A cloud 3D render returns the videos, render.json and results.json. Render locally for the per-frame files.
Every radar detection is a few centimetres away. The radar is inside the vehicle's body and sees only the body. Move it just outside: the example's front radar sits 0.2 m ahead of the box's front edge.
My lidar wrote more scans than it made revolutions. It writes one full scan per rendered frame, at the camera rate, not one per revolution. See lidar files.
Are IMU or GNSS supported? Not as sensors. The ego's exact pose at every frame is in observed-frames.jsonl.