Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for setting blending mode #337

Merged
merged 7 commits into from
Jun 25, 2024

Conversation

Soulghost
Copy link
Contributor

@Soulghost Soulghost commented May 29, 2024

This commit adds a with_blending_mode, which can be used to set the blending mode for the particle renderer. In addition to alpha blend mode, premultiply and additive mode has been added.

The additive blending mode is useful for glow effects, the picture below makes a comparison.

Additive Blending

image

Alpha Blending

image

Sample Code

//! Example of additive blend mode.
//!
//! This example demonstrate how to change the blend mode for the particle renderer.

use bevy::{
    core_pipeline::tonemapping::Tonemapping,
    log::LogPlugin,
    prelude::*,
    render::{
        camera::Projection, render_resource::WgpuFeatures, settings::WgpuSettings, RenderPlugin,
    },
};
#[cfg(feature = "examples_world_inspector")]
use bevy_inspector_egui::quick::WorldInspectorPlugin;

use bevy_hanabi::prelude::*;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let mut wgpu_settings = WgpuSettings::default();
    wgpu_settings
        .features
        .set(WgpuFeatures::VERTEX_WRITABLE_STORAGE, true);

    let mut app = App::default();
    app.insert_resource(ClearColor(Color::DARK_GRAY))
        .add_plugins(
            DefaultPlugins
                .set(LogPlugin {
                    level: bevy::log::Level::WARN,
                    filter: "bevy_hanabi=warn,additive=trace".to_string(),
                    update_subscriber: None,
                })
                .set(RenderPlugin {
                    render_creation: wgpu_settings.into(),
                    synchronous_pipeline_compilation: false,
                })
                .set(WindowPlugin {
                    primary_window: Some(Window {
                        title: "🎆 Hanabi — additive blending".to_string(),
                        ..default()
                    }),
                    ..default()
                }),
        )
        .add_plugins(HanabiPlugin);

    #[cfg(feature = "examples_world_inspector")]
    app.add_plugins(WorldInspectorPlugin::default());

    app.add_systems(Startup, setup)
        .add_systems(Update, bevy::window::close_on_esc)
        .run();

    Ok(())
}

fn setup(
    asset_server: Res<AssetServer>,
    mut commands: Commands,
    mut effects: ResMut<Assets<EffectAsset>>,
) {
    let camera = Camera3dBundle {
        transform: Transform::from_xyz(0.0, 0.0, 3.0).looking_at(Vec3::ZERO, Vec3::Y),
        projection: Projection::Perspective(PerspectiveProjection {
            fov: 90.0,
            ..Default::default()
        }),
        tonemapping: Tonemapping::None,
        ..Default::default()
    };

    commands.spawn(camera);

    let texture_handle: Handle<Image> = asset_server.load("orange_circle.png");

    let writer = ExprWriter::new();

    let age = writer.lit(0.).expr();
    let init_age = SetAttributeModifier::new(Attribute::AGE, age);

    let lifetime = writer.lit(5.).expr();
    let init_lifetime = SetAttributeModifier::new(Attribute::LIFETIME, lifetime);

    let init_pos = SetPositionCircleModifier {
        center: writer.lit(0.).expr(),
        axis: writer.lit(Vec3::Z).expr(),
        radius: writer.lit(0.2).expr(),
        dimension: ShapeDimension::Volume,
    };

    let init_vel = SetVelocityCircleModifier {
        center: writer.lit(Vec3::ZERO).expr(),
        axis: writer.lit(Vec3::Z).expr(),
        speed: (writer.lit(0.2) + writer.lit(0.2) * writer.rand(ScalarType::Float)).expr(),
    };

    // Use the F32_0 attribute as a per-particle rotation value, initialized on
    // spawn and constant after. The rotation angle is in radians, here randomly
    // selected in [0:2*PI].
    let rotation = (writer.rand(ScalarType::Float) * writer.lit(std::f32::consts::TAU)).expr();
    let init_rotation = SetAttributeModifier::new(Attribute::F32_0, rotation);

    let size = Vec2::splat(0.8);
    let effect = effects.add(
        EffectAsset::new(vec![32768], Spawner::rate(5.0.into()), writer.finish())
            .with_name("additive")
            .with_alpha_mode(bevy_hanabi::AlphaMode::Add)
            .init(init_pos)
            .init(init_vel)
            .init(init_age)
            .init(init_lifetime)
            .init(init_rotation)
            .render(ParticleTextureModifier {
                texture: texture_handle,
                sample_mapping: ImageSampleMapping::Modulate,
            })
            .render(SetSizeModifier { size: size.into() }),
    );

    commands
        .spawn(ParticleEffectBundle::new(effect))
        .insert(Name::new("effect"));
}

Add this image to the assets/orange_circle.png

orange_circle

@SludgePhD
Copy link
Contributor

Neat, this would fix #227

src/asset.rs Outdated Show resolved Hide resolved
examples/additive.rs Outdated Show resolved Hide resolved
src/render/mod.rs Show resolved Hide resolved
@Soulghost Soulghost requested a review from SludgePhD June 4, 2024 15:04
@Soulghost
Copy link
Contributor Author

Hi @djeedai , Please help me review this PR, thanks!

Copy link
Owner

@djeedai djeedai left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi- Thanks for the PR! I'm OK in principle I think but there's a few things I'm not convinced about:

  1. we do a lot of duplication here, see other comments.
  2. this probably doesn't justify the overhead of maintaining a full separate example just for this, and especially adding new assets (which are shipped with the crate and increase its size, even if just for examples)

src/render/mod.rs Outdated Show resolved Hide resolved
src/render/mod.rs Outdated Show resolved Hide resolved
@Soulghost Soulghost force-pushed the feature/blending_mode branch from 104e5f0 to 256b83e Compare June 9, 2024 02:23
@Soulghost Soulghost requested a review from djeedai June 9, 2024 02:24
@djeedai
Copy link
Owner

djeedai commented Jun 22, 2024

@Soulghost would you mind please merge latest main to get the clippy fixes for the CI breaks ("Check format" action)? Ignore the "run-examples" failure, this is an upstream bug in wgpu it can't be fixed for now (it's fixed in Bevy 0.14).

@Soulghost Soulghost force-pushed the feature/blending_mode branch from 256b83e to de74719 Compare June 23, 2024 03:39
@Soulghost
Copy link
Contributor Author

Soulghost commented Jun 23, 2024

Hi @djeedai , I have rebased my feature branch based on the latest main branch, please review my code again, thank you very much.

@Soulghost
Copy link
Contributor Author

Hi @djeedai , it appears that the failure of run-examples and coverage/coveralls are preventing the merge process.

@djeedai
Copy link
Owner

djeedai commented Jun 25, 2024

@Soulghost don't mind those. There's no auto-merge, I make the call on whether to merge. In that case coverage drop is minimal so all fine, and the failing examples is a bug upstream we can't do anything about for now. So all good. I'll have a final look later and merge.

@Soulghost
Copy link
Contributor Author

@Soulghost don't mind those. There's no auto-merge, I make the call on whether to merge. In that case coverage drop is minimal so all fine, and the failing examples is a bug upstream we can't do anything about for now. So all good. I'll have a final look later and merge.

Got it, thank you very much.

@djeedai djeedai merged commit 8a20894 into djeedai:main Jun 25, 2024
11 of 13 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants