simvx.graphics.renderer.velocity_pass

How it works

A dedicated RG16F render target (with its own depth) is re-drawn from the same opaque instances the forward pass submitted. velocity.vert reads two parallel model-matrix SSBOs keyed by gl_InstanceIndex (current + previous frame) and, together with the UNJITTERED current/previous view-projection (from PostProcessPass.taa_cur_vp / taa_prev_vp), emits NDC-space motion vectors.

Previous-frame transforms are kept on the CPU side: each frame the renderer hands this pass the column-major model matrices it already computed for the main transform SSBO. We upload them as “current”, and roll last frame’s into “previous”. On the first frame – or whenever the scene tree structure changes (instance row indices may shift) – prev is forced equal to current, yielding zero velocity (no spike), mirroring the camera-VP first-frame guard in update_taa_matrices.

Background / sky pixels keep the render pass’s clear sentinel (-2, -2) (outside any legitimate NDC-delta range) so the resolve can fall back to depth-based camera reprojection there.

SCOPE: opaque mesh instances only. Skinned meshes and GPU particles have no prev-joint / prev-particle state at this boundary and are intentionally NOT drawn here – they keep the resolve’s camera-only depth-reproject behaviour (mild self-motion ghosting, no regression). Per-object velocity for those is a flagged follow-up.

Per-object motion-vector (velocity) pass for TAA (desktop Vulkan).

Foundation stage for per-object TAA: produces a per-pixel velocity buffer for opaque MESH INSTANCES so a moving mesh stops ghosting once the resolve samples it (the resolve hookup is a separate stage). Purely additive and gated on taa_enabled: nothing here is allocated, uploaded, or recorded when TAA is off, so the no-TAA frame stays byte-identical.

Module Contents

Classes

VelocityPass

Re-draws opaque mesh instances into an RG16F per-object velocity target.

Data

API

simvx.graphics.renderer.velocity_pass.__all__

[‘VelocityPass’]

simvx.graphics.renderer.velocity_pass.log

‘getLogger(…)’

class simvx.graphics.renderer.velocity_pass.VelocityPass(engine: Any, max_objects: int)[source]

Re-draws opaque mesh instances into an RG16F per-object velocity target.

Initialization

property velocity_view: Any[source]

RG16F colour view the resolve samples (SHADER_READ_ONLY after the pass).

property ready: bool[source]
setup(width: int, height: int) None[source]

Allocate the velocity target, prev/cur model SSBOs, UBO, descriptors, pipelines.

Called lazily by the renderer only when TAA is first enabled, so the no-TAA path never touches any of this.

set_frame_matrices(cur_vp: numpy.ndarray, prev_vp: numpy.ndarray) None[source]

Stash the UNJITTERED current + previous view-projection for this frame.

upload_models(models_col_major: numpy.ndarray, structure_changed: bool) None[source]

Upload current model matrices and roll the previous-frame copy.

models_col_major is the (N, 4, 4) column-major (GLSL-ready) model matrices the renderer already computed for the main transform SSBO – the same row order, so gl_InstanceIndex pairs current<->previous correctly.

On the first frame (no cached prior models) or after a tree-structure change (row indices may have shifted -> a stale prev would spike), prev is set equal to current so velocity is zero that frame.

render(cmd: Any, scene_renderer: Any) None[source]

Re-draw opaque instances into the velocity target. No-op when not ready.

Reuses the scene content renderer’s opaque draw path with this pass’s pipeline/layout/descriptor overrides, so culling + grouping + the indirect batch are shared with the forward pass (no second Python draw loop).

property pipeline: Any[source]
property pipeline_double: Any[source]
property pipeline_layout: Any[source]
property desc_set: Any[source]
resize(width: int, height: int) None[source]
cleanup() None[source]