Description
Bevy version
The problem occurs in both 0.16
release and current main
. I did not test older versions.
System/Adapter Info:
SystemInfo { os: "Windows 11 Pro", kernel: "26100", cpu: "Intel(R) Core(TM) i7-8700K CPU @ 3.70GHz", core_count: "6", memory: "15.9 GiB" }
AdapterInfo { name: "NVIDIA GeForce GTX 1080 Ti", vendor: 4318, device: 6918, device_type: DiscreteGpu, driver: "NVIDIA", driver_info: "576.02", backend: Vulkan }
What you did
Spawn more than one gltf model with dithering enabled (via inserting a VisibilityRange component).
What went wrong
Only the first model receives dithering.
Additional information
Interestingly, if you spawn a bunch of models very quickly, all that started spawning before the first one finished spawning will have working dithering, and all after that will not.
Video
Code Example
I put together a reduced version of examples/3d/visibility_range.rs
to demonstrate the problem.
It differs from the original example in that it will only spawn the gltf model when you press the F key.
Press F to spawn the first model, then wait until its visible and press F again to spawn a second copy. Only the first will receive dithering.
Restart the app and then press F key several times very quickly. All those models will receive dithering, but any more you spawn after they are finished will not.
visibility_range.rs
use std::f32::consts::PI;
use bevy::prelude::*;
use bevy_render::view::VisibilityRange;
const CAMERA_FOCAL_POINT: Vec3 = vec3(0.0, 0.3, 0.0);
const CAMERA_KEYBOARD_ZOOM_SPEED: f32 = 0.05;
const CAMERA_KEYBOARD_PAN_SPEED: f32 = 0.01;
const MIN_ZOOM_DISTANCE: f32 = 0.5;
static VISIBILITY_RANGE: VisibilityRange = VisibilityRange {
start_margin: 0.0..0.0,
end_margin: 0.5..4.0,
use_aabb: false,
};
#[derive(Component, Clone, Copy)]
struct ModelRoot;
fn main() {
App::new()
.add_plugins(DefaultPlugins)
.add_systems(Startup, setup)
.add_systems(
Update,
(move_camera, spawn_new_instance, set_visibility_ranges),
)
.run();
}
fn setup(
mut commands: Commands,
mut meshes: ResMut<Assets<Mesh>>,
mut materials: ResMut<Assets<StandardMaterial>>,
) {
// Spawn a plane.
commands.spawn((
Mesh3d(meshes.add(Plane3d::default().mesh().size(50.0, 50.0))),
MeshMaterial3d(materials.add(Color::srgb(0.1, 0.2, 0.1))),
));
// Spawn a light.
commands.spawn((
DirectionalLight::default(),
Transform::from_rotation(Quat::from_euler(EulerRot::ZYX, 0.0, PI * -0.15, PI * -0.15)),
));
// Spawn a camera.
commands.spawn((
Camera3d::default(),
Transform::from_xyz(0.7, 0.7, 1.0).looking_at(CAMERA_FOCAL_POINT, Vec3::Y),
));
}
fn move_camera(
keyboard_input: Res<ButtonInput<KeyCode>>,
cameras: Query<&mut Transform, With<Camera3d>>,
) {
let (mut zoom_delta, mut theta_delta) = (0.0, 0.0);
if keyboard_input.pressed(KeyCode::KeyW) {
zoom_delta -= CAMERA_KEYBOARD_ZOOM_SPEED;
} else if keyboard_input.pressed(KeyCode::KeyS) {
zoom_delta += CAMERA_KEYBOARD_ZOOM_SPEED;
}
if keyboard_input.pressed(KeyCode::KeyA) {
theta_delta -= CAMERA_KEYBOARD_PAN_SPEED;
} else if keyboard_input.pressed(KeyCode::KeyD) {
theta_delta += CAMERA_KEYBOARD_PAN_SPEED;
}
// Update the camera transform.
for transform in cameras {
let transform = transform.into_inner();
let direction = transform.translation.normalize_or_zero();
let magnitude = transform.translation.length();
let new_direction = Mat3::from_rotation_y(theta_delta) * direction;
let new_magnitude = (magnitude + zoom_delta).max(MIN_ZOOM_DISTANCE);
transform.translation = new_direction * new_magnitude;
transform.look_at(CAMERA_FOCAL_POINT, Vec3::Y);
}
}
fn spawn_new_instance(
mut commands: Commands,
keyboard_input: Res<ButtonInput<KeyCode>>,
asset_server: Res<AssetServer>,
mut offset: Local<f32>,
) {
if keyboard_input.just_pressed(KeyCode::KeyF) {
commands.spawn((
SceneRoot(asset_server.load(
GltfAssetLabel::Scene(0).from_asset("models/FlightHelmet/FlightHelmet.gltf"),
)),
ModelRoot,
Transform::from_translation(vec3(*offset, 0.0, 0.0)),
));
*offset += 0.5;
}
}
// We need to add the `VisibilityRange` components manually, as glTF currently
// has no way to specify visibility ranges. This system watches for new meshes,
// determines which `Scene` they're under, and adds the `VisibilityRange`
// component as appropriate.
fn set_visibility_ranges(
mut commands: Commands,
meshes: Query<Entity, Added<Mesh3d>>,
roots: Query<&ModelRoot>,
children: Query<&ChildOf>,
) {
for mesh in meshes {
for ancestor in children.iter_ancestors(mesh) {
if roots.contains(ancestor) {
info!("Adding visibility range to mesh: {mesh}");
commands.entity(mesh).insert(VISIBILITY_RANGE.clone());
break;
}
}
}
}