bevyengine / bevyengine/bevy

Mesh with Material2D sometimes needs a few frames before being drawn

Open
#12,376 0 comments 0 reactions 0 assignees View on GitHub
A-Rendering C-Bug
Dominant language
Rust
Stars
48.2k
Forks
4.8k
Avg merge
3d 22h
Merged PRs (30d)
161

Description

## Bevy version
0.13.0

## Relevant system information

If your bug is rendering-related, copy the adapter info that appears when you run Bevy.

```ignore
`AdapterInfo { name: "AMD Radeon RX 6400", vendor: 4098, device: 29759, device_type: DiscreteGpu, driver: "AMD proprietary driver", driver_info: "23.10.2 (AMD proprietary shader compiler)", backend: Vulkan }`
```

## What you did

I made a terrain renderer that draws textures in loading screen. For this I use a Camera2D per chunk and meshes with a custom `Material2D`. Every frame in this loading state, a number of chunks are rendered.

## What went wrong

The camera renders to images (the clear color gets drawn). But the first 0 - 3 frames, the meshes are not drawn, resulting in a clean textures for those chunks. I provide a minimal example here:

An image asset is created, the handle is saved in a `Resource`. The used Material2D is `ColorMaterial`. The image is used as render target in frame 0, then the used camera and mesh are despawned in frame 1. Frame 2 starts to display the rendered texture on the screen.

Result: Sometimes, the red square exists in the texture, sometimes only the green background is visible. (-> Some reruns of the program necessary)

```rust
use bevy::{prelude::*, render::{camera::ScalingMode, render_resource::{Extent3d, TextureDescriptor, TextureUsages}}};

fn main() {
App::new()
.add_plugins(DefaultPlugins)
.insert_resource(FrameCounter(0))

.add_systems(Update, spawn_cam_mat_mesh.run_if(|first_frame: Res| first_frame.0 == 0))
.add_systems(Update, despawn_render_target_stuff.run_if(|first_frame: Res| first_frame.0 == 1))
.add_systems(Update, spawn_result_display_stuff.run_if(|first_frame: Res| first_frame.0 == 2))
.add_systems(PostUpdate, count_frame)

.run();
}

#[derive(Resource)]
struct FrameCounter(u32);

#[derive(Component)]
struct RenderMarker;

#[derive(Resource)]
struct RenderedTarget(Handle);

fn spawn_cam_mat_mesh(mut commands: Commands, mut meshs: ResMut>, mut materials: ResMut>, mut images: ResMut>) {

// Render target
let render_image_size = Extent3d {
width: 256,
height: 256,
..default()
};

let mut image = Image {
texture_descriptor: TextureDescriptor {
label: None,
size: render_image_size,
mip_level_count: 1,
sample_count: 1,
dimension: bevy::render::render_resource::TextureDimension::D2,
format: bevy::render::render_resource::TextureFormat::Bgra8UnormSrgb,
usage: TextureUsages::TEXTURE_BINDING
| TextureUsages::COPY_DST
| TextureUsages::RENDER_ATTACHMENT,
view_formats: &[],
},
..default()
};
image.resize(render_image_size);

let target = images.add(image);

// Save the target handle for drawing it later.
commands.insert_resource(RenderedTarget(target.clone()));

// Camera with green background.
commands.spawn((
Camera2dBundle {
projection: OrthographicProjection {
near: -1000.,
scaling_mode: ScalingMode::Fixed { width: 1., height: 1. },
..default()
},
camera: Camera {
clear_color: Color::GREEN.into(),
target: bevy::render::camera::RenderTarget::Image(target),
..default()
},
..default()
},
RenderMarker
));

// The 2D-Mesh to be rendered to the texture in red.
commands.spawn((ColorMesh2dBundle {
material: materials.add(ColorMaterial {color: Color::RED, texture: None}),
mesh: meshs.add(Rectangle::from_size(Vec2::new(0.5, 0.5))).into(),
..default()
},
RenderMarker,
));
}

fn count_frame(mut frame_counter: ResMut) {
frame_counter.0 += 1;
}

fn despawn_render_target_stuff(mut commands: Commands, elements: Query>) {
for entity in elements.iter() {
commands.entity(entity).despawn();
}
}

fn spawn_result_display_stuff(mut commands: Commands, rendered_target: Res) {
commands.spawn(Camera2dBundle::default());
commands.spawn(SpriteBundle {
texture: rendered_target.0.clone(),
..default()
});
}
```

## Additional information

I never recognised that any chunk rendering failed, after the first one in the chunk queue succeeded (not index 0, the first of them correctly rendered).

Maybe the created meshes or their materials are sent to the graphics card asynchronously. (I do not know, how the renderer works.)

If what I see is expected behavior: Is there a way to enforce instant availability? Or are there checks to see, whether the meshes are available? Without, I would request the enforcement option as feature, because I need a reliable renderer for images pre-gameworld.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.