Skip to content

ForwardDecal: Allow custom alpha mode and fix using with OIT#21909

Open
beicause wants to merge 13 commits intobevyengine:mainfrom
beicause:fix-forward-decal-with-oit
Open

ForwardDecal: Allow custom alpha mode and fix using with OIT#21909
beicause wants to merge 13 commits intobevyengine:mainfrom
beicause:fix-forward-decal-with-oit

Conversation

@beicause
Copy link
Copy Markdown
Contributor

@beicause beicause commented Nov 22, 2025

Objective

Forward decal is not transparent unless I set the alpha mode of base material (StandardMaterial) to Blend. This is because the MaterialExtension::alpha_mode doesn't override standard material flags, which is still follow the StandardMaterial::alpha_mode and is opaque and discards alpha by default.

And ForwardDecalMaterialExt overrides alpha mode so it can only do alpha blending, which is an unnecessary restriction in my opinion. I think it makes sense to allow use alpha modes other than Blend for forward decals.

There is also an issue that if OIT enabled, forward decal will be wrongly culled by opaque objects.

Solution

Makes forward decal doesn't override alpha mode, and doesn't enter the code path of OIT_ENABLED so it can do alpha blending. Add material::enable_oit to opt out OIT so forward decals can use regular alpha blending.

Disables prepass for forward decal so it still works if alpha mode is Opaque or Mask (thought the depth fade factor won't have effect).

Disables shadow for forward decal as it generally shouldn't cast shadows.

Testing

Run the decal example:

屏幕截图_20251122_104851

With alpha mode Add:
屏幕截图_20251122_104822

With alpha mode Opaque:
屏幕截图_20251213_172021

blend = None;
// TODO tail blending would need to return color in shader to do alpha blending
// Alpha blending is also needed by forward decals.
blend = Some(BlendState::ALPHA_BLENDING);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I'm a bit confused. This is only relevant when using forward decal with OIT right? But in pbr.wgsl you added a comment saying forward decal is incompatible with OIT.

Also, do we have a way to check here if this is for a forward decal or just a standard mesh?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Forward decal is just a quad mesh and has no specific mesh key, so we can't check it here.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

OK, I added enable_oit to material as a way to opt out OIT. Let me known if you prefer that.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I still don't understand why the blend mode of the OIT_ENABLED pipeline needs to change.

@dloukadakis dloukadakis added the A-Rendering Drawing game state to the screen label Nov 22, 2025
@dloukadakis dloukadakis added S-Needs-Review Needs reviewer attention (from anyone!) to move forward D-Shaders This code uses GPU shader languages labels Nov 22, 2025
@github-actions
Copy link
Copy Markdown
Contributor

Your PR caused a change in the graphical output of an example or rendering test. This might be intentional, but it could also mean that something broke!
You can review it at https://pixel-eagle.com/project/B04F67C0-C054-4A6F-92EC-F599FEC2FD1D?filter=PR-21909

If it's expected, please add the M-Deliberate-Rendering-Change label.

If this change seems unrelated to your PR, you can consider updating your PR to target the latest main branch, either by rebasing or merging main into it.

@beicause beicause marked this pull request as draft December 13, 2025 10:21
@beicause beicause marked this pull request as ready for review December 13, 2025 10:45
@beicause beicause force-pushed the fix-forward-decal-with-oit branch from f85f5ee to dc89206 Compare December 14, 2025 17:32
const MOTION_VECTOR_PREPASS = 1 << 3;
const DEFERRED_PREPASS = 1 << 4;
const OIT_ENABLED = 1 << 5;
const OIT_VIEW = 1 << 5;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I don't really understand what OIT_VIEW means here and why it isn't just OIT_ENABLED?

Copy link
Copy Markdown
Contributor Author

@beicause beicause Dec 15, 2025

Choose a reason for hiding this comment

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

It is used for mesh view binding when OIT is enabled on the camera, otherwise the shader bind groups will not match.

These bindings seem to be distinguished by camera, but not by material.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I'd like to revert this change as I'm not convinced it's necessary or stable enough. IMO the rendering pipeline should just respect alpha_mode=blend for now, if OIT needs a separate alpha mode we can make changes in the future,.

@JMS55 JMS55 added this to the 0.19 milestone Dec 30, 2025
@beicause beicause force-pushed the fix-forward-decal-with-oit branch from c07dfe7 to d11acc0 Compare January 9, 2026 04:49
@cart cart added this to Rendering Feb 12, 2026
@github-project-automation github-project-automation bot moved this to Needs SME Triage in Rendering Feb 12, 2026
@cart cart removed this from Rendering Feb 12, 2026
fn alpha_mode() -> Option<AlphaMode> {
Some(AlphaMode::Blend)
fn enable_prepass() -> bool {
false // This is needed if alpha mode is `Opaque`.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I understand not forcing the use of alpha blending, but I don't get why setting enable_prepass to false is necessary.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Forward decal requires the prepass depth of other opaque objects, while its own depth should not be included in the prepass.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-Rendering Drawing game state to the screen D-Shaders This code uses GPU shader languages S-Needs-Review Needs reviewer attention (from anyone!) to move forward

Projects

No open projects
Status: No status

Development

Successfully merging this pull request may close these issues.

5 participants