komadori / bevy_mod_outline

Apache License 2.0
123 stars 10 forks source link

Compatibility with Bloom #36

Closed stmdhms closed 4 months ago

stmdhms commented 7 months ago

It seems like bevy_mod_outline is not compatible with bloom, even if the entities with outlines don't have any emissive color set.

Here's a sample scene without outlines enabled. The left cube has a red emissive color. The right cube has no emissive color, and has an OutlineBundle with outline.visible set to false. The rendered result is as expected: bloom_no_outline

If outline.visible on the right cube is set to true, the left cube suddenly loses its emissive glow: bloom_with_outline

I'm using bevy 0.13.1 and bevy_mod_outline 0.7.0.

Code to reproduce:

use bevy::{
    core_pipeline::bloom::*,
    prelude::*,
};
use bevy_mod_outline::*;

fn main() {
    App::new()
        .insert_resource(Msaa::Sample4)
        .insert_resource(ClearColor(Color::BLACK))
        .insert_resource(AmbientLight {
            color: Color::WHITE,
            brightness: 1000.0,
        })
        .add_plugins(DefaultPlugins)
        .add_plugins(OutlinePlugin)
        .add_systems(Startup, setup)
        .add_systems(Update, toggle_outline)
        .run();
}

fn setup(
    mut commands: Commands,
    mut meshes: ResMut<Assets<Mesh>>,
    mut materials: ResMut<Assets<StandardMaterial>>,
) {
    commands.spawn((
        Camera3dBundle {
            camera: Camera {
                hdr: true,
                ..default()
            },
            transform: Transform::from_xyz(0.0, 5.0, 5.0).looking_at(Vec3::ZERO, Vec3::Y),
            ..default()
        },
        BloomSettings {
            intensity: 1.0,
            low_frequency_boost: 0.5,
            low_frequency_boost_curvature: 0.5,
            high_pass_frequency: 0.5,
            prefilter_settings: BloomPrefilterSettings {
                threshold: 3.0,
                threshold_softness: 0.6,
            },
            composite_mode: BloomCompositeMode::Additive,
        },
    ));

    let mut cube_mesh = Cuboid::new(1.0, 1.0, 1.0).mesh();
    cube_mesh.generate_outline_normals().unwrap();
    let cube = meshes.add(cube_mesh);
    commands
        .spawn(PbrBundle {
            mesh: cube.clone(),
            material: materials.add(StandardMaterial {
                base_color: Color::WHITE,
                emissive: Color::rgb_linear(2000.0, 0.0, 0.0),
                ..default()
            }),
            transform: Transform::from_xyz(-2.0, 0.0, 0.0),
            ..default()
        });

        commands
        .spawn(PbrBundle {
            mesh: cube.clone(),
            material: materials.add(StandardMaterial {
                base_color: Color::WHITE,
                ..default()
            }),
            transform: Transform::from_xyz(2.0, 0.0, 0.0),
            ..default()
        })
        .insert(OutlineBundle {
            outline: OutlineVolume {
                visible: false,
                colour: Color::rgba(0.0, 1.0, 0.0, 1.0),
                width: 5.0,
            },
            ..default()
        });
}

fn toggle_outline(
    time: Res<Time>,
    mut query: Query<&mut OutlineVolume>
) {
    for mut outline in query.iter_mut() {
        outline.visible = time.elapsed_seconds() % 2.0 < 1.0;
    }
}
komadori commented 4 months ago

As a workaround, you can fix this by disabling MSAA.

The problem is that the OutlineNode renders to the sampled colour attachment. This apparently overwrites the unsampled colour attachment with the sampled one again. However, the later part of the rendering pipeline, including the bloom effect, appears to operate only on the unsampled colour attachment and hence these effects are lost when an outline is rendered.

The distinction between sampled and unsampled colour attachments only exists when MSAA is enabled.

komadori commented 4 months ago

Fixed in 0.7.1.