Skip to content

Camera: 3D rotation with a shared perspective, and camera motion blur #362

Closed as not planned

Description

@LeadcodeDev

Context

Two reels in this batch film their scenes with a moving camera: the whole shot (room, mockup, text, tiles) orbits together, and fast camera moves blur the entire frame. The per-node tools can't do either for a whole scene.

1. rotate_x, rotate_y and perspective on camera

Camera keyframes accept only x, y, zoom, rotation, origin.x, origin.y, focus and aperture:

unknown camera keyframe property 'rotate_x'

Parallax through style.depth knows translation and zoom only. To tilt a whole shot, you copy the same rotate_x/rotate_y keyframes onto every group. Each group then has its own vanishing point, and near planes don't swing more than far ones.

"camera": {
  "perspective": 1600,
  "keyframes": [
    { "property": "rotate_y", "values": [{ "time": 0, "value": -8 }, { "time": 2, "value": 6 }], "easing": "ease_in_out" }
  ]
}

The rotation applies to each direct child of the scene according to its style.depth, the same rule the parallax and the camera.focus blur already use.

2. Camera motion blur

Dives and whip moves in the references drag the whole image. camera.keyframes moves the camera without blur, motion_blur works per element, and transitions only act at a cut.

"camera": { "motion_blur": { "samples": 8, "shutter": 0.5 } }

This would accumulate sub-frame renders along the camera's motion within the shutter window, only where the camera actually moves.

Found in: reel 4 (3D camera), reel 7 (camera motion blur)

Activity

  1. LeadcodeDev commented on Sep 27, 2026

    @LeadcodeDev
    OwnerAuthor

    Part 1 landed in #400: camera.rotate_x, rotate_y and perspective, applied once about the camera's origin and scaled by each plane's style.depth. Keyframes work on all three.

    Part 2 — camera motion blur — is still open, and this is why it was split rather than bundled.

    It means rendering each frame several times with the camera at sub-frame positions inside the shutter window and accumulating them. That is not a paint-pass change: it belongs in the encode loop, where render_frame_task_scaled produces one buffer per frame. It brings its own cost model — k× render time on every frame the camera moves — and its own question of where the sampling happens so the audio and frame accounting stay consistent.

    Bundling it into #400 would have made one PR that was really two, with the cheap half hostage to the expensive one.

  2. LeadcodeDev commented on Sep 29, 2026

    @LeadcodeDev
    OwnerAuthor

    Closing. Part 1 shipped in #400: camera.rotate_x, rotate_y and perspective,
    applied once about the camera's origin and scaled by each plane's style.depth.
    All three animate through keyframes, and rules/camera-3d.md documents it.

    Part 2 — camera motion blur — is dropped rather than parked. It means rendering
    each frame k times at sub-frame camera positions and accumulating them: a k×
    cost on every frame the camera moves, in the encode loop rather than the paint
    pass. That is a cost decision, and nothing is asking for it.

    Reopen with a target k and an acceptable per-frame budget if it becomes wanted.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions