Skip to content

Conversation

@rlneumiller
Copy link
Contributor

Objective

Enable per-entity participation control for Bevy’s primary render passes, so an entity can be excluded from main camera rendering (opaque/alpha-mask/transparent/transmissive) and/or shadow rendering without requiring material/shader workarounds.

This is Part 1 of “per-entity render pass exclusion”: focuses on MainPass + Shadow participation (and introduces prepass-related bits followed up in another branch as Part_2.

Solution

Added a new public, component-driven API:

  • RenderPassMask bitflags (main pass bits, prepass bits, and SHADOW)
  • RenderPasses(RenderPassMask) component (defaults to RenderPassMask::ALL)
  • Extracted RenderPasses into the render world so queueing systems can read it.
  • Updated render queueing to respect the mask:
  • Main pass material mesh queueing skips entities missing the relevant main-pass bit.
  • Shadow queueing skips entities missing RenderPassMask::SHADOW.
  • Prepass queueing respects RenderPassMask::PREPASS as an umbrella (output-specific prepass behavior is intended for a Part_2 PR).
  • Wireframe queueing skips entities excluded from RenderPassMask::MAIN.
  • Added example demonstrating the new behavior:
    only_shadow_caster.rs

Testing

Tested on Debian 13 with discreet Nvidia GPU and Nvidia driver version: 590.48.01
I did not test Windows/macOS

cargo test -p bevy_render --lib
cargo test -p bevy_pbr --lib

Run the new example:

cargo run --example only_shadow_caster

Verify that “shadow-only” entities still cast shadows while being invisible in the main camera.

## Showcase

<img width="1276" height="756" alt="Screenshot From 2025-12-30 14-30-01" src="https://github.com/user-attachments/assets/5cdf9109-7300-4aaa-b219-be3ee8dd4ca9" />


```rust
use bevy::prelude::*;
use bevy::render::{RenderPassMask, RenderPasses};

fn setup(mut commands: Commands, mut meshes: ResMut<Assets<Mesh>>, mut materials: ResMut<Assets<StandardMaterial>>) {
    // Shadow-only: invisible to main camera passes, still rendered into shadow maps.
    commands.spawn((
        Mesh3d(meshes.add(Sphere::new(0.5))),
        MeshMaterial3d(materials.add(StandardMaterial::default())),
        Transform::from_xyz(0.0, 0.5, 0.0),
        RenderPasses(RenderPassMask::SHADOW),
    ));

    // Main-pass-only: visible, but won’t cast shadows.
    commands.spawn((
        Mesh3d(meshes.add(Cuboid::new(1.0, 1.0, 1.0))),
        MeshMaterial3d(materials.add(StandardMaterial::default())),
        Transform::from_xyz(2.0, 0.5, 0.0),
        RenderPasses(RenderPassMask::MAIN),
    ));
}

@rlneumiller
Copy link
Contributor Author

@github-actions
Copy link
Contributor

The generated examples/README.md is out of sync with the example metadata in Cargo.toml or the example readme template. Please run cargo run -p build-templated-pages -- update examples to update it, and commit the file change.

@rlneumiller rlneumiller force-pushed the Per_Entity_Render_Pass_Exclusion_Part_1 branch from d67cca6 to cbadeaa Compare December 30, 2025 18:55
@IceSentry
Copy link
Contributor

Couldn't you use render layers to achieve the same or very similar result?

@IceSentry
Copy link
Contributor

Also, that's adding a lot more branches in the hot path. Can you benchmark this to confirm this isn't a regression.

@tychedelia
Copy link
Member

Couldn't you use render layers to achieve the same or very similar result?

This is my immediate question too

@rlneumiller
Copy link
Contributor Author

rlneumiller commented Dec 31, 2025

Couldn't you use render layers to achieve the same or very similar result?

RenderLayers can approximate some cases, but it’s “which views see this entity”. This PR is “which render passes does this entity participate in (main/shadow/…)” even within the same view. For shadow-only, layers usually require coordinating layers across all shadow-casting lights, which is why I leaned toward a pass mask.

Can you benchmark this to confirm this isn't a regression.

Done (30 second warm-up then 30 second runs of many_cubes with and without --shadows):
No significant difference

BENCHMARK_RESULTS.md

nvidia-smi
Wed Dec 31 12:10:45 2025
+-----------------------------------------------------------------------------------------+
| NVIDIA-SMI 590.48.01 Driver Version: 590.48.01 CUDA Version: 13.1 |
+-----------------------------------------+------------------------+----------------------+
| GPU Name Persistence-M | Bus-Id Disp.A | Volatile Uncorr. ECC |
| Fan Temp Perf Pwr:Usage/Cap | Memory-Usage | GPU-Util Compute M. |
| | | MIG M. |
|=========================================+========================+======================|
| 0 NVIDIA GeForce RTX 4070 ... On | 00000000:01:00.0 Off | N/A |
| 0% 32C P8 2W / 220W | 13MiB / 12282MiB | 0% Default |
| | | N/A |
+-----------------------------------------+------------------------+----------------------+

+-----------------------------------------------------------------------------------------+
| Processes: |
| GPU GI CI PID Type Process name GPU Memory |
| ID ID Usage |
|=========================================================================================|
| 0 N/A N/A 2746 G /usr/bin/gnome-shell 3MiB |
+-----------------------------------------------------------------------------------------+

@alice-i-cecile alice-i-cecile added C-Feature A new feature, making something new possible A-Rendering Drawing game state to the screen X-Contentious There are nontrivial implications that should be thought through S-Needs-Review Needs reviewer attention (from anyone!) to move forward labels Dec 31, 2025
@alice-i-cecile alice-i-cecile added X-Controversial There is active debate or serious implications around merging this PR and removed X-Contentious There are nontrivial implications that should be thought through labels Dec 31, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-Rendering Drawing game state to the screen C-Feature A new feature, making something new possible S-Needs-Review Needs reviewer attention (from anyone!) to move forward X-Controversial There is active debate or serious implications around merging this PR

4 participants