Open-Source Wikis

/

Bevy

/

Features

/

Rendering pipeline

bevyengine/bevy

Rendering pipeline

How a frame becomes pixels in Bevy. Covers the SubApp boundary, the four render phases, the render graph, phases and items, and where each piece of code lives.

This page brings together bevy_render, bevy_core_pipeline, bevy_pbr, bevy_anti_alias, bevy_post_process, bevy_sprite_render, bevy_ui_render, and bevy_solari.

The four-phase pipeline

graph LR
    Main[Main world] -->|Extract| RW[Render world]
    RW --> Prepare
    Prepare --> Queue
    Queue --> Render
    Render -->|wgpu submit| GPU

Each phase is a system set inside the Render schedule of the RenderApp SubApp. The actual implementation is RenderSet::Extract, RenderSet::Prepare*, RenderSet::Queue*, RenderSet::Render — see crates/bevy_render/src/lib.rs.

Extract

Runs the ExtractSchedule, with the main world available read-only. The job is to copy any data the renderer will need this frame from the main world into the render world. Boilerplate is handled by ExtractComponentPlugin and ExtractResourcePlugin.

After Extract finishes, the main world is unblocked — the next frame's main schedule starts running immediately, in parallel with the rest of the renderer.

Prepare

Runs in the render world. Allocates GPU resources for this frame: per-camera view uniforms, per-light shadow data, per-material bind groups, per-mesh GPU buffers, instance buffers. The pipeline cache is asked to compile any new pipeline specializations.

Queue

Walks the extracted entities for each camera, computes which entities are visible (after frustum culling and RenderLayers), assigns each visible entity a PhaseItem in one of the standard render phases:

  • 3D: Opaque3d, AlphaMask3d, Transparent3d
  • 2D: Opaque2d, AlphaMask2d, Transparent2d
  • Shadow: Shadow
  • UI: TransparentUi
  • Prepass: Opaque3dPrepass, AlphaMask3dPrepass

PhaseItems carry a sort key used in the next step.

Render

Walks the render graph node-by-node. Each node has access to the queued phases for its target view and writes commands into the GPU command buffer. After the graph completes, wgpu::Queue::submit is called and the swapchain presents the result.

The render graph

A RenderGraph is a DAG. Nodes implement bevy_render::render_graph::Node and declare named slots. The standard graph (added by Core3dPlugin) contains:

Node What it does
MainPrepassNode Depth/normal/motion-vector prepass (when enabled).
ShadowPassNode Per-light shadow map rendering.
MainOpaquePass3dNode Opaque + alpha-mask 3D draws.
MainTransparentPass3dNode Transparent draws.
BloomNode Multi-mip bloom.
TonemappingNode Apply tonemap operator (Reinhard, ACES, AgX, …).
CASNode / FXAANode / SMAANode / TAANode Anti-aliasing.
UpscalingNode Render-target upscale.
CameraDriverNode Final blit/present.

Plugins like bevy_pbr::PbrPlugin, bevy_sprite_render::SpriteRenderPlugin, bevy_ui_render::UiRenderPlugin, and bevy_anti_alias::* insert their own nodes around these.

Pipelined rendering

sequenceDiagram
    participant N as Main frame N+1
    participant N0 as Main frame N (just finished)
    participant Ext as Extract
    participant R as Render frame N
    participant GPU
    Note over N0,Ext: only synchronization point
    N0->>Ext: copy data
    Ext->>R: hand off
    par main can advance
        N->>N: compute frame N+1
    and render proceeds
        R->>GPU: prepare/queue/render frame N
    end

pipelined_rendering.rs orchestrates this. The render world owns its own World; the extract step is the only time both worlds are busy at once. After extraction, the renderer runs in parallel with the next frame's main world, doubling effective throughput on render-bound workloads.

Cameras and views

A Camera (with Transform + Projection) defines a view. The camera plugin in bevy_render::camera extracts each camera into a ExtractedCamera plus a per-view uniform buffer (camera matrices, exposure, viewport). RenderLayers filter which entities are extracted per camera.

Multi-camera setups are first-class: multiple cameras can render to the same window with different Viewports, or each can render to its own RenderTarget::Image.

Materials and pipeline specialization

A Material declares a fragment shader, a bind-group layout, and a specialization key. Each (material variant × mesh layout × shader defs) tuple corresponds to one wgpu::RenderPipeline, cached in PipelineCache. Compilation runs asynchronously on a task pool; pipelines that aren't ready yet are simply skipped for the frame and the system retries next frame.

bevy_pbr's StandardMaterial is the canonical implementation. Custom materials are documented in examples/shader/.

Where to start when modifying

Goal Crate / file
Add a render-graph node bevy_renderrender_graph/node.rs
Add a phase item bevy_renderrender_phase/
Custom material bevy_material + bevy_pbr
Post-process effect bevy_post_process or bevy_core_pipeline
Anti-aliasing technique bevy_anti_alias
Custom 2D rendering bevy_sprite_render
Custom UI rendering bevy_ui_render
Ray tracing bevy_solari

See also

Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.

Rendering pipeline – Bevy wiki | Factory