# Clipping plane stencil capping

**URL:** <https://discourse.threejs.org/t/clipping-plane-stencil-capping/74018>\
**Category:** Questions\
**Tags:** clipping-planes, stencil\
**Created:** [November 14, 2024, 11:28am UTC](https://discourse.threejs.org/t/clipping-plane-stencil-capping/74018 "2024-11-14T11:28:41Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![CoralReef](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/coralreef/32/50068_2.png) [@CoralReef](https://discourse.threejs.org/u/CoralReef)\
**Post date:** [November 14, 2024, 11:28am UTC](https://discourse.threejs.org/t/clipping-plane-stencil-capping/74018/1 "2024-11-14T11:28:41Z")

</div>

Hi  
After upgrading from v160 to v170 the capping of the clipping planes no longer works for me.

Specifically: I’ve created a capping plane (with PlaneGeometry). And the stencils no longer seem to be working - the plane is visible everywhere (not only where the stencils would allow). Some code details:

1. I create a cross section material (to cap the clipped surfaces) like this:

```javascript
const crossSectionMat = new THREE.MeshBasicMaterial({
        color: hex,
        stencilWrite: true,
        stencilRef: 0,
        stencilFunc: THREE.NotEqualStencilFunc,
        stencilFail: THREE.ReplaceStencilOp,
        stencilZFail: THREE.ReplaceStencilOp,
        stencilZPass: THREE.ReplaceStencilOp,
    });

```

1. I’ve set the cross section ‘onAfterRender’ function like this:

```javascript
crossSection.onAfterRender = function (renderer) {
        renderer.clearStencil();
    };

```

1. I’ve created two stencils (front and back) with the following materials:

```javascript
const stencilBack = () => {
    const clippingPlane = CrossSection.getClippingPlane();
    const stencilBackMat = new THREE.MeshBasicMaterial();
    stencilBackMat.side = THREE.BackSide;

    stencilBackMat.depthWrite = false;
    stencilBackMat.depthTest = false;
    stencilBackMat.colorWrite = false;
    stencilBackMat.stencilWrite = true;
    stencilBackMat.stencilFunc = THREE.AlwaysStencilFunc;

    stencilBackMat.clippingPlanes = [clippingPlane];
    stencilBackMat.stencilFail = THREE.IncrementWrapStencilOp;
    stencilBackMat.stencilZFail = THREE.IncrementWrapStencilOp;
    stencilBackMat.stencilZPass = THREE.IncrementWrapStencilOp;

    return stencilBackMat;
};

const stencilFront = () => {
    const clippingPlane = CrossSection.getClippingPlane();
    const stencilFrontMat = new THREE.MeshBasicMaterial();
    stencilFrontMat.side = THREE.FrontSide;

    stencilFrontMat.depthWrite = false;
    stencilFrontMat.depthTest = false;
    stencilFrontMat.colorWrite = false;
    stencilFrontMat.stencilWrite = true;
    stencilFrontMat.stencilFunc = THREE.AlwaysStencilFunc;

    stencilFrontMat.clippingPlanes = [clippingPlane];
    stencilFrontMat.stencilFail = THREE.DecrementWrapStencilOp;
    stencilFrontMat.stencilZFail = THREE.DecrementWrapStencilOp;
    stencilFrontMat.stencilZPass = THREE.DecrementWrapStencilOp;

    return stencilFrontMat;
};

```

1. I’ve created the stencils based off an objects geometry like this:

```javascript
const createStencil = (obj) => {
    if (!obj.geometry) return;
    const geometry = obj.geometry;
    const stencil = new THREE.Group();
    stencil.name = "stencilGroup";

    // back faces
    const mat0 = Material.stencilBack();
    const mesh0 = new THREE.Mesh(geometry, mat0);
    mesh0.name = "stencilMesh0";
    stencil.add(mesh0);

    // front faces
    const mat1 = Material.stencilFront();
    const mesh1 = new THREE.Mesh(geometry, mat1);
    mesh1.name = "stencilMesh1";
    stencil.add(mesh1);

    obj.add(stencil);
};

```

1. When a button is clicked to apply the stencils I do the following:

```javascript
renderer.stencil = true;
renderer.localClippingEnabled = true;
crossSection.visible = true;

```

I’ve gone over this example a number of times and can’t work out what’s different: [three.js examples](https://threejs.org/examples/?q=stencil#webgl_clipping_stencil)

Any help - hugely appreciated!!

---

<div class="post-metadata">

**Author:** ![Lukasz\_Mestales](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/lukasz_mestales/32/65638_2.png) [@Lukasz\_Mestales](https://discourse.threejs.org/u/Lukasz_Mestales)\
**Post date:** [November 14, 2024, 2:35pm UTC](https://discourse.threejs.org/t/clipping-plane-stencil-capping/74018/2 "2024-11-14T14:35:36Z")

</div>

From **r163** _…`stencil` context attribute of `WebGLRenderer` is now `false` by default for performance reasons…_

You need to enable the stencil buffer.

```javascript
const renderer = new THREE.WebGLRenderer({
   // antialias: true,
    stencil: true
});

```

More [HERE](https://github.com/mrdoob/three.js/wiki/Migration-Guide#162--r163)

---

<div class="post-metadata">

**Author:** ![CoralReef](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/coralreef/32/50068_2.png) [@CoralReef](https://discourse.threejs.org/u/CoralReef)\
**Post date:** [November 14, 2024, 2:49pm UTC](https://discourse.threejs.org/t/clipping-plane-stencil-capping/74018/3 "2024-11-14T14:49:50Z")

</div>

That did it! many thanks. I had done it this way: renderer.stencil = true; which didn’t work

---

<div class="post-metadata">

**Author:** ![dubois](https://avatars.discourse-cdn.com/v4/letter/d/e9c0ed/32.png) [@dubois](https://discourse.threejs.org/u/dubois)\
**Post date:** [November 15, 2024, 12:54am UTC](https://discourse.threejs.org/t/clipping-plane-stencil-capping/74018/4 "2024-11-15T00:54:09Z")

</div>

Yeah, I think all those params need to be provided at construction time.

---

<div class="post-metadata">

**Author:** ![aaaidan](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/aaaidan/32/38946_2.png) [@aaaidan](https://discourse.threejs.org/u/aaaidan)\
**Post date:** [April 29, 2025, 10:52pm UTC](https://discourse.threejs.org/t/clipping-plane-stencil-capping/74018/5 "2025-04-29T22:52:08Z")

</div>

Can anyone speak to the performance impact of `stencil`? If it was removed for performance, it would be nice to know how heavy it is. Is it a framerate slowdown? A memory thing?

---

<div class="post-metadata">

**Author:** ![dubois](https://avatars.discourse-cdn.com/v4/letter/d/e9c0ed/32.png) [@dubois](https://discourse.threejs.org/u/dubois)\
**Post date:** [April 29, 2025, 10:57pm UTC](https://discourse.threejs.org/t/clipping-plane-stencil-capping/74018/6 "2025-04-29T22:57:20Z")

</div>

It has not been removed for performance, just disabled by default. I can’t speak to the performance of it. It’s possibly 8 bits per pixel that wont be used. Most applications dont do stencil testing, so im not sure what savings are to be gained there. Ie. if it was never turned on, and no testing ever happened, nothing is to be gained.

---

<div class="post-metadata">

**Author:** ![aaaidan](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/aaaidan/32/38946_2.png) [@aaaidan](https://discourse.threejs.org/u/aaaidan)\
**Post date:** [June 23, 2025, 1:19am UTC](https://discourse.threejs.org/t/clipping-plane-stencil-capping/74018/7 "2025-06-23T01:19:45Z")

</div>

The release notes, [which state](https://github.com/mrdoob/three.js/wiki/Migration-Guide#162--r163) it was removed specifically for performance reasons.

I guess a 2000 x 1000 canvas at DPR 2, that’s 8 million pixels. At 8 bits per pixel, that’s 61 megabytes. Perhaps 4x MSAA multiplies this to 244 MB.

Not nothing, I guess. Would be interesting to know what fraction of a typical scene render’s memory use this is…
