Crates.io | bevy_blackout |
lib.rs | bevy_blackout |
version | 0.1.0 |
source | src |
created_at | 2023-12-12 04:56:56.600101 |
updated_at | 2023-12-12 04:56:56.600101 |
description | A plugin for the Bevy game engine that adds third-person visibility casting |
homepage | |
repository | https://github.com/jnhyatt/bevy_blackout |
max_upload_size | |
id | 1065902 |
size | 871,304 |
bevy_blackout
bevy_blackout
is a small shader tweak I added for a game I wanted to make, but to my surprise it turned out very modular, so I decided to publish it as a crate. The idea is that I want to discard all fragments not visible to a third-person character. This is modeled by placing a point light at your character's eye point with shadow casting enabled, then discarding all fragments that end up in "shadow" from that light's perspective. The effect supports multiple "eye-points", in which case fragments are only discarded if no lights can see them. This allows you to, for example, have multiple characters in the scene, and show fragments either of them can see.
To keep the effect from interfering with any of your other lights, the secret code to turn a light into a visibility marker is to set its color to black. This ensures that the marker will not affect lighting as its color will always be black at any distance, and none of your other lights will be erroneously treated as visibility markers. Only objects with BlackoutMaterial
will be affected by the visibility culling. I also recommend enabling backface culling as otherwise you will see a lot of backfaces when meshes are between the camera and the visibility marker. Note that this is on by default for StandardMaterial
, but if you load your meshes from a .gltf/.glb
for example, culling may or may not be automatically enabled.
Add BlackoutPlugin
to your App
:
use bevy_blackout::BlackoutPlugin;
...
app.add_plugins(BlackoutPlugin);
Add the material to scene objects that should be occluded:
use bevy_blackout::BlackoutMaterial;
fn setup(
mut blackout_materials: ResMut<Assets<BlackoutMaterial>>,
mut commands: Commands,
) {
...
let player = commands.spawn(MaterialMeshBundle {
mesh,
material: blackout_materials.add(BlackoutMaterial {
base: StandardMaterial {
// Backface culling is not *necessary* but likely what you want
cull_mode: Some(Face::Back),
..default()
},
extension: default(),
}),
..default()
}).id();
}
Add a visibility marker, which is just a PointLight
with a color
of black:
let viz_marker = commands.spawn(PointLightBundle {
point_light: PointLight {
color: Color::BLACK, // This light is a marker
range: 20.0, // Most light parameters work like you'd expect
shadows_enabled: true, // Must cast shadows or effect won't work
..default()
},
transform: Transform::from_xyz(0.0, 0.5, 0.0), // Player eye point
..default()
}).id();
// Add the marker to player so visibility moves around with it
commands.entity(player).add_child(viz_marker);
VoilĂ :
(The full code for this scene is the simple
example)
Note that you will likely also want to enable backface culling for your material or else objects between the camera and the character will have their front faces discarded, and the camera will be left staring into the inverted husks of your meshes.
StandardMaterial
for now. It's a very simple effect and you can simply copy the relevant lines into your custom shader. A more permanent solution would be Bevy's core pipeline adding some kind of shader pipeline that lets you extend it at different stages, e.g. insert custom WGSL between input material params and lighting calculationssimple
The visibility caster is attached to the player. Move the character around with WASD.
bevy | bevy_blackout |
---|---|
0.12 | 0.1 |
PRs welcome. To be honest, I don't see this going anywhere until Bevy has a bit more robust of a render engine, but if you see a need or have a wishlist feature, feel free to implement it.