bevyengine / bevy

A refreshingly simple data-driven game engine built in Rust
https://bevyengine.org
Apache License 2.0
35.2k stars 3.47k forks source link

Transparency improvements #2223

Open mtsr opened 3 years ago

mtsr commented 3 years ago

What problem does this solve or what need does it fill?

Currently transparency is handled by splitting entities into two groups and rendering them in sorted order:

Unfortunately this is not enough to handle the general case. One of the simplest problem cases is when rendering a transparent sphere with another transparent inside. Since the sorting happens by entity transform, the object inside will be incorrectly rendered first if it's behind the origin of the sphere. And it will be incorrectly rendered last if it's in front of the origin of the sphere. To render this situation correctly the back of the sphere needs to be rendered first, then the object inside and then the front of the sphere. This cannot be done by sorting entities.

A reasonable introduction to the problem and evaluation of some solutions can be read in this presentation by nvidia. This slide captures the problem in a nutshell:

image

What solution would you like?

I think we need to evaluate the costs/benefits of a few different solutions and maybe even implement more than one of them.

Order Independent Transparency seems the most general solution, but the performance cost can be significant. It seems like Weighted Blended Order Independent Transparency has the best trade-off of the common implementations.

What alternative(s) have you considered?

There's a number of different possible solutions:

Additional context

This demo shows 7 different algorithms for OIT implemented using Vulkan.

This video discusses how FrostBite uses OIT for rendering hair.

mtsr commented 3 years ago

After some discussion in #rendering it seems that WBOIT indeed makes the best trade-offs for general use of the current solutions. So I'd like to suggest that as the first one to implement. The 7 vulkan implementations includes a WBOIT implementation that can be used as a reference, see the fragment shader, for example: https://github.com/nvpro-samples/vk_order_independent_transparency/blob/master/oitWeighted.frag.glsl

cart commented 3 years ago

I'm only familiar with this topic in that I know order independent transparency can be expensive and is an active area of research. Unless WBOIT is approximately a drop-in replacement for "traditional transparency" performance-wise, I think it should probably be opt-in / not default. If that is the case, we should pick an algorithm that can be selectively enabled for specific cases that need it.

But yeah, this is definitely something we need to do. Thanks for collecting material for it!

CptPotato commented 3 years ago

Weight blended OIT sounded like the most promising while discussing on discord. To me it stands out because it seems to be the easiest to implement and most robust (it's basically a weighted sum over all transparent surfaces - no sorting, no limits to how many transparent layers are possible, etc.). Performance wise I don't see it having much of an impact. The other techniques seem much more elaborate here as they actually perform sorting or some separation of layers. The main downside is that WBOIT is incorrect but it still produces a "plausible" looking result.

Unless I'm missing something, compared to traditional transparency it requires one additional fullscreen rendertarget where everything transparent renders to (additively) and one additional compositing pass to resolve the transparency buffer and blend it with the opaque buffer (post process).

I also thought about it in terms of playing nice with the rest of the rendering and didn't come up with any blockers. Even from the MSAA perspective it should work very well (the compositing step will also resolve MSAA in this case).

mtsr commented 3 years ago

'Traditional' transparency already breaks down for the transparent sphere, though. So it quickly requires extra effort from the user to make it work. Let alone what happens with more complex meshes.

cart commented 3 years ago

'Traditional' transparency already breaks down for the transparent sphere, though. So it quickly requires extra effort from the user to make it work. Let alone what happens with more complex meshes.

But if order-independent transparency is too expensive, some common cases like "drawing lots of grass on the ground" might be very slow by default (although "traditional transparency" also isn't ideal for that use case afaik). The only thing that I currently know performs well enough to be a default is "traditional transparency". But we should implement as many options as we can, compare them, then make a call. This is a case where giving people lots of options is a good idea anyway, so it wouldn't be wasted effort.

aevyrie commented 3 years ago

I think this bug in sponza might be caused by entity transform ordering: image

The column is visible behind the vegetation, but the banner is not. It could be an outright sorting bug though, the banner doesn't have any transparency and should be visible.

This is how it renders in windows 3d viewer: image

I can open an issue if this is unrelated.

alice-i-cecile commented 2 years ago

Closely related to #64.

superdump commented 2 years ago

Noting two things:

mtsr commented 11 months ago

This isn't relevant to me right now and it doesn't seem like it's something bevy needs right now either.

alice-i-cecile commented 11 months ago

Order-independent-transparency would still be a welcome addition. We can track that separately when that comes up though.

superdump commented 11 months ago

I don’t think this should be closed. And I know @IceSentry has been working on OIT.

IceSentry commented 11 months ago

Yep, I'm planning on upstreaming my work during the 0.13 dev cycle