bevyengine / bevyengine/bevy

AlphaMode::Blend produces non-opague shape when defined as opague when used with fog

Open
#25,462 1 comment 0 reactions 0 assignees View on GitHub
A-Rendering C-Bug D-Complex S-Needs-Design
Dominant language
Rust
Stars
48.2k
Forks
4.8k
Avg merge
3d 16h
Merged PRs (30d)
171

Description

## Bevy version and features
0.19.0
0.19.1
and main

## What you did

I have a scene with a cuboid with an opague blend material and I noticed something is wrong with the depth when the cuboid is between my fog god ray and the camera causing it to render transparent.

## What went wrong

Its suppose to be opague its rendering transparent

## Additional information

Image

minimized repro
```rs
use bevy::{
asset::RenderAssetUsages,
camera::Exposure,
camera_controller::free_camera::{FreeCamera, FreeCameraPlugin},
core_pipeline::{prepass::DepthPrepass, tonemapping::Tonemapping},
light::{FogVolume, VolumetricFog, VolumetricLight},
post_process::bloom::Bloom,
prelude::*,
render::render_resource::{Extent3d, TextureDimension, TextureFormat},
};

const SURFACE_Y: f32 = 0.0;
const BOTTOM_Y: f32 = SURFACE_Y - 45.0;
const GOD_RAY_LIGHT_HEIGHT: f32 = 20.0;
const GOD_RAY_RANGE: f32 = 200.0;
const COLLAR_INNER_RADIUS: f32 = 2.5;
const COLLAR_HEIGHT: f32 = 0.8;
const GOD_RAY_FOG_WIDTH: f32 = 12.0;
const GOD_RAY_BRIGHTNESS: f32 = 3_000_000.0;
const PLAYER_CUBOID_SIZE: Vec3 = Vec3::new(0.5, 1.5, 0.5);
const PLAYER_POSITION: Vec3 = Vec3::new(6.5, -5.0, 0.0);
const EXPOSURE_EV100: f32 = 5.5;

fn main() {
App::new()
.add_plugins((DefaultPlugins, FreeCameraPlugin))
.insert_resource(ClearColor(Color::BLACK))
.add_systems(Startup, (setup_camera, setup_god_ray, setup_player))
.run();
}

fn setup_camera(mut commands: Commands) {
commands.spawn((
Camera3d::default(),
Transform::from_xyz(11.5, -4.6, 0.0).looking_at(Vec3::new(0.0, -6.0, 0.0), Vec3::Y),
FreeCamera::default(),
DepthPrepass,
Msaa::Off,
Exposure {
ev100: EXPOSURE_EV100,
},
Tonemapping::AcesFitted,
Bloom::NATURAL,
AmbientLight {
brightness: 0.0,
..default()
},
VolumetricFog {
ambient_intensity: 0.0,
..default()
},
));
}

fn setup_god_ray(mut commands: Commands, mut images: ResMut>) {
let outer_angle = (COLLAR_INNER_RADIUS / GOD_RAY_LIGHT_HEIGHT).atan();
commands.spawn((
SpotLight {
color: Color::WHITE,
intensity: GOD_RAY_BRIGHTNESS,
range: GOD_RAY_RANGE,
shadow_maps_enabled: true,
inner_angle: outer_angle * 0.7,
outer_angle,
..default()
},
VolumetricLight,
Transform::from_xyz(0.0, SURFACE_Y + GOD_RAY_LIGHT_HEIGHT, 0.0)
.looking_at(Vec3::new(0.0, BOTTOM_Y, 0.0), Vec3::Z),
));
let fog_top = SURFACE_Y + COLLAR_HEIGHT;
commands.spawn((
FogVolume {
density_factor: 0.04,
absorption: 0.05,
scattering: 0.5,
light_intensity: 8.0,
density_texture: Some(images.add(god_ray_density_image())),
..default()
},
Transform::from_xyz(0.0, (BOTTOM_Y + fog_top) / 2.0, 0.0).with_scale(Vec3::new(
GOD_RAY_FOG_WIDTH,
fog_top - BOTTOM_Y,
GOD_RAY_FOG_WIDTH,
)),
));
}

fn setup_player(
mut commands: Commands,
mut meshes: ResMut>,
mut materials: ResMut>,
) {
let mesh = meshes.add(Cuboid::from_size(PLAYER_CUBOID_SIZE));
commands.spawn((
Mesh3d(mesh.clone()),
MeshMaterial3d(materials.add(StandardMaterial {
base_color: Color::srgb(0.8, 0.3, 0.3),
..default()
})),
Transform::from_translation(PLAYER_POSITION + Vec3::new(0.0, 0.0, -0.6)),
));
commands.spawn((
Mesh3d(mesh),
MeshMaterial3d(materials.add(StandardMaterial {
base_color: Color::srgba(0.8, 0.3, 0.3, 1.0),
alpha_mode: AlphaMode::Blend,
..default()
})),
Transform::from_translation(PLAYER_POSITION + Vec3::new(0.0, 0.0, 0.6)),
));
commands.spawn((
PointLight {
color: Color::srgb(1.0, 0.85, 0.6),
intensity: 300_000.0,
range: 40.0,
shadow_maps_enabled: false,
..default()
},
Transform::from_translation(PLAYER_POSITION + Vec3::new(4.0, 2.0, 2.5)),
));
}

fn god_ray_density_image() -> Image {
const N: usize = 32;
let mut data = vec![0u8; N * N * N];
for z in 0..N {
for y in 0..N {
for x in 0..N {
let dx = x as f32 / (N - 1) as f32 * 2.0 - 1.0;
let dz = z as f32 / (N - 1) as f32 * 2.0 - 1.0;
let r = (dx * dx + dz * dz).sqrt();
let t = ((1.0 - r) / 0.3).clamp(0.0, 1.0);
let d = t * t * (3.0 - 2.0 * t);
data[(z * N + y) * N + x] = (d * 255.0) as u8;
}
}
}
Image::new(
Extent3d {
width: N as u32,
height: N as u32,
depth_or_array_layers: N as u32,
},
TextureDimension::D3,
data,
TextureFormat::R8Unorm,
RenderAssetUsages::RENDER_WORLD,
)
}
```

Contributor guide

Open the contributing guide

Research direction

Run the minimized Rust reproduction and compare the two cuboids created in setup_player while tracing the camera and volumetric fog configured in setup_camera and setup_god_ray. Identify why the AlphaMode::Blend cuboid becomes transparent through fog, and consider the issue done when it remains opaque as expected in the reported setup.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
computer-graphics, game-dev
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
55/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.