How to use multiple clipping masks for groups of objects in Three.js?

Hi everyone!

I’m working on a vanilla Three.js project where I have multiple groups (sections) stacked vertically.
Inside each group, there is a PlaneGeometry with an animated shader as a background, and several animated 3D objects on top.

The idea is that each group should act like a “section” with boundaries - similar to how overflow: hidden works in CSS.
If an object flies outside the visual boundaries of its group, it should be clipped and not rendered outside its section.

Additionally, I have a global group of objects that can move freely across the entire scene without being affected by any clipping masks.

Some more context:

  • I have about 10 such sections/groups, and their heights vary.
  • The camera scrolls vertically (on wheel) to view different sections.
  • At any given time, one to three sections might be visible, depending on their heights.

How can I set up clipping in Three.js so that:

  • Each section has its own independent clipping mask.
  • Objects inside each section are clipped correctly without affecting objects in other sections.
  • The global objects are not clipped at all.

Any ideas on the best way to approach this?

Thanks a lot in advance!

I’d probably use the stencil buffer, or depth buffer, and multipass rendering.

how is the clipping mask defined? is it a texture?

I’m not quite sure I understand the spatial setup that you describe, but local clipping planes look like they could address all three items above altogether. There are some things to pay attention to - the local planes are still defined in global coordinates, the local planes must be added to all objects that must be clipped locally.

I’ll try to explain with an example inspired by the awesome Lusion website.
They have an interactive section where objects are clipped inside a rounded rectangle.

I want to achieve something similar, but with multiple sections like this stacked vertically.
Additionally, I also need to have some global objects that are rendered in front of these sections and are not clipped.

you can nest the renderer canvas inside another element with a border (i think)
or
you can use alpha:true and set the renderer background alpha to 0, so only the objects will be on the page and the bg transparent, and you can use a div behind the renderer canvas with a background image… with whatever shape you want.
or
you can use {alpha:true} on the renderer constructor.. and draw your corner cutouts to the alpha in threejs

there are probably other approaches too.

1 Like

You can set something like this: renderer.domElement.style.borderRadius = "10vh"; (or do the same with CSS). :thinking:

Clipping also works: Tamalék [Catmull-Rom in vertex shader]

.hex{
  /*border-radius: 200px;*/
  -webkit-clip-path: polygon(50% 0%, 95% 25%, 95% 75%, 50% 100%, 5% 75%, 5% 25%);
  clip-path: polygon(50% 0%, 95% 25%, 95% 75%, 50% 100%, 5% 75%, 5% 25%);
}
3 Likes