three.js
three.js copied to clipboard
Add Shadows for Transparent Objects
A first pass at shadows for transparent objects as discussed in #10600.
I've modified an example here on another branch so you can see how the shadows are affected and the artifacts associated with this technique:
As I mentioned before the artifacts are pretty apparent but can be hidden a bit by setting the shadow radius to a good value. There may be some other shadow sampling techniques that can better hide the dither pattern.
I just resolved the conflicts and made a few updates including using an 8x8 dither pattern as Babylon used. The example on another branch from the original post has been updated, as well, with a larger shadow map (2048 x 2048). Right now shadow transparency is universally toggled with renderer.shadow.dithering
(like you mentioned in https://github.com/mrdoob/three.js/issues/10600#issuecomment-473140467) but it could be set per light -- perhaps that's a better place for it? It would be nice to move most / all shadowmap flags to the lights if possible I think.
And cc @donmccurdy -- you've mentioned an interest in introducing alpha hashing previously and this may be a start. The approach used here for shadows is just a 2d pattern seeded by screen space position so it's consistent but there could be other options in the future. For shadows, at least, using an alpha hash approach like you mention here might be noisier (even if it doesn't change per frame thought it might not be so noticeable) but would allow shadows of overlapping objects with the same alpha to to get darker:
For alpha hash we'd probably want texture-space or object-space coordinates, but no matter here. I do see pretty noticeable banding though, viewed from an angle.
... and I'm wondering if a small blue noise texture would do better? We can figure out how to embed it in the source code as a Uint8Array or Data URI if it gives good results.
For alpha hash we'd probably want texture-space or object-space coordinates, but no matter here
Yeah I've taken a look at that presentation -- it is a slightly different technique but we could provide options to use various clipping approaches for transparency. Alpha hashing does look really noisy, though. Is it often used without some kind of temporal accumulation like TRAA?
Regarding the banding, though, I'm not sure if there's a great way to avoid a pattern here -- here's what the shadows would look like with blue noise (I've written a blue noise generator here):
https://raw.githack.com/gkjohnson/threejs-sandbox/bluenoise-shadows/screendoor-transparency/index.html
And here's the same demo with a 4x4 bayer pattern:
https://raw.githack.com/gkjohnson/threejs-sandbox/master/screendoor-transparency/index.html
I'm not sure if I feel it's a lot better.
Alpha hashing does look really noisy, though. Is it often used without some kind of temporal accumulation like TRAA?
I don't think it needs to be (example: https://twitter.com/thespite/status/1221532206562258945), but, yeah there's certainly a grain. For alpha hashing (or even just starting with alpha dither, no per-object hash) I think I'd prefer a noise pattern to a screen grid. But for the shadows, agreed, the Bayer pattern appears to be working better. Tweaking the shadow radius seems to hide the banding, depending on the angle etc., that could work for now. 👍
"mrdoob modified the milestones: r123, r124 23 minutes ago" :( Why ?
@LinoPhil The milestone modification happens automatically when the assigned milestone is released and the PR is still open.
@Mugen87 ok, but the feature itself, you are not satisfied with the quality or is it breaking something? The demos look promising to me and im looking forward to use it in our viewer.
@LinoPhil Sorry, there was just no opportunity to deeply review this PR so far. There are so many of them (with different priorities and complexities) and time is unfortunately limited.
Just want to give a push. Maybe after 3 years (initial ticket 10600) its time to finish?
@gkjohnson I'd also be interested in this PR; seems only blocker was "review time" - happy to test drive this as well in case you find time to rebase it on latest dev.
happy to test drive this as well in case you find time to rebase it on latest dev.
I appreciate it but unfortunately I've lost interest in this PR. I made it, rebased it, and resolved conflicts three times at the request of the project to review but have gotten no real feedback or direction on how to get it merged. If I'm asked to make changes or update a PR I think it's reasonable to read that as interest in the PR and for feedback to come. I understand there are a lot of PRs and issues that come through three.js but I'd just like to express that it is frustrating to be asked to do work and spend time on a problem with no follow up.
If someone is interested in picking this PR up and updating it to move it forward then by please do! I'm just preoccupied with other projects right now.
Thanks! I fully understand the frustration 🙃
Maybe @donmccurdy can chime in if/how this PR relates to the recent draft of
- #24271
Maybe @donmccurdy can chime in if/how this PR relates to the recent draft of
- https://github.com/mrdoob/three.js/pull/24271
My opinions here - I think alpha hashing is great but there is no one perfect solution for these things with transparency, shadows, anything. It's all hacks and the right solution depends on the desired result. Alpha hashing looks great when you can temporally resolve but otherwise it's extremely noisy as the camera or object moves.
Games like Mario Odyssey use a variety of patterns stylistically for different kinds of transparency including a comic-book-like dot matrix pattern for the main character. And most new high profile games like Assassins Creed Odyssey use a typical bayer pattern dither for transparency which is consistent in screen space and therefore less noticeable than a noisy hash jitter.
In terms of reducing shadow artifacts - it seems that Babylon.js has employed exponential variance shadow maps (EVSM reference) which seems to be useful when trying to blur out the artifacts.
Perhaps something like node materials will make this kind of subjectivity in handling material dither a simpler task 🤞
Yeah, I think these are complementary. Perhaps we'd want to use the same dither patterns at some point but I am not too concerned about that now.
I'm not sure how useful Alpha Hashing will be for large, highly-visible transparent surfaces. As @gkjohnson mentions, the noise requires temporal resolution. However I do find myself wishing I could use Alpha Hashing when trying to do things like:
- subtly fade out an opaque object, without tons of alpha blending problems
- fading between two opaque objects (e.g. LODs)
- fading out the edges of an object (e.g. e.g. blades of grass fading into the ground)
These cases are less sensitive to noise grain.
I don't think there's another good issue to post this in but it's relevant to the discussion here - Cesium (at least in Unreal) is using screenspace consistent dither patterns to fade between LoDs. Screen space consistency is particularly important here since the different swapping LoDs fade using inverted dither masks. So as the new model fades in a dither pattern - the old one fades out using the pixels that the new model is not rendering to yet.
https://cesium.com/blog/2022/10/20/smoother-lod-transitions-in-cesium-for-unreal/
Looks like this feature has been added into react-three-fiber's Drei based on this PR. It was also added into Babylon (also based on my original sandbox example 😅) and Playcanvas, as well.
Yes, we should rebase and merge the PR!
we have same issue when rendering hair(transparent texturing) shadow, looking forward to get this feature in next release, thanks for the good work.