Do something like aero glass


So, I’m working on a webapp running three.js.
It’s a a 3D world explorer, where I use multiple passes:
The first one is on a scene with a perspective camera on PointerLockControls
The second one is on a scene with an orthogonal camera that I use as an interface.

Now on the interface, what I want is something like Aero glass on Windows. I think iOS does that too nowadays.
Basically everything behind a specific material would appear blurred out.

I know how to blur stuff, you average the neighbor pixels.
But how do I get the neighbor pixels in the rendering color buffer?
Is there a specific variable?
Do I need an extension?
Is there any example anywhere?

If not possible, do I need to do a full pass?
Or do I need to do render to texture the world in perspective and pass it to the material.
Both these solutions seem more ressource hungry.

Any hint is welcome.

You can render the objects to be blurred to a render target as a mask, then combine it with the scene also rendered to one and blur where it it’s masked.

1 Like

There is even an example that illustrates this approach:

Ok, thank you both.

I was able to but something together:

It’s not a blur, but a zoom shader. But the idea is the same.
I’ll play a bit more with it latter to make it look supa keoool.

So this is the only way to do that? Passes with masking? Isn’t that heavy, for a mobile target for example?


Not really, but depends on the hardware and everything else you are doing/rendering. For some devices performance can heavily improved by upscaling a lower resolution. Especially those with higher dpi.

I had thought this would be possible just using CSS… but it looks like we’ll have to wait a few years for support.

Even if CSS backdrop-filter worked without bugs (Chrome still has issues), the CSS backdrop-filter won’t magically blur WebGL content while also being partially occluded by other WebGL content. In other words, the CSS effect lives outside of WebGL space.

Making CSS backdrop-filter useful in a WebGL scene would be tricky. It would involve having three layers (two canvas elements and a div in between them):

  • The furthest back bottom layer would render any WebGL content that is behind the element that has backdrop-filter (f.e. blurr effect). This layer would know the dimensions of the DOM element, and would use an equivalently-sized plane Geometry to use as a mask, and thus render only the part of the scene that is behind any pixels of the Plane. (This underlying WebGL layer does not apply the filter effect.) The border radius of the DOM element would also need to be taken into account when making the plane geometry.
  • The middle layer would contain the element, which is oriented in the same 3D space as the WebGL content (f.e. with CSS3DRenderer) plus have the backdrop-filter applied to it. The backdrop-filter will apply to any content in the underneath canvas (in this case, WebGL content)
  • The top layer would render all content as normal, except that it would not render any pixels that are behind the DOM element. It would also use a plane geometry for this purpose.

So far I have only implemented the middle and top layers over at (work in progress, the docs and examples are too ugly, for now!). If you check out the “Buttons with shadow” example, it uses the same technique in order to give the HTML <button> elements lighting and shadow (however the implementation of that is abstracted away as part of the library, and the author of the scene does not need to think much about that). The <button> elements live in the “middle layer” which is underneath the top WebGL layer that contains the lighting and shadow. Right-click and inspect element on the <button>s.

It would be neat to add the bottom WebGL layer. I really can’t wait to see this backdrop-filter working in a simple abstracted way.

It may get more complicated if there are more than one element that have backdrop-filter in the same 3D space. The two layer approach works fine when the DOM elements are 100% opaque. The complexity arrises when there are transparent-like elements (as with backdrop-filter).

This demo shows the two-layer system without abstraction:

@horsetopus u can add a css layer to achieve this

.your-layer {
width: 100vw;
height: 100vh;
backgroud-color: rgba(0, 0, 0, 0);
backdrop-filter: blur(4px)

this is built into three now: new THREE.MeshPhysicalMaterial({ transmission: 1, thickness: 1, roughness: 0.65 })