Capping clipped planes using stencil on a BufferGeometry()

Hi. I am a bit of a novice when it comes to coding on three.js so I wanted some help on this:

I am working on a project that requires clipping planes on a geometry and then capping up the cut portion. I saw many examples and questions and found this to be the closest to what I need: https://threejs.org/examples/?q=stenc#webgl_clipping_stencil . However I tried repeating the same for my project using the code below (but it does not create the cap) . Am I missing something ?

  this.partGroup = new THREE.Group();
  var object = new THREE.Group();
  var poGroup = new THREE.Group();
  this.renderer.localClippingEnabled = true;
for(var i = 0; i < parts.length; i++){
       var geometry = new THREE.BufferGeometry();
        
        geometry.setIndex(new THREE.BufferAttribute(indices, 1));
        geometry.setAttribute('position', new THREE.BufferAttribute(positions, 3));
        geometry.setAttribute('normal', new THREE.BufferAttribute(normals, 3, true));
        geometry.setAttribute('color', new THREE.BufferAttribute(colors, 3, true));


        var planes = [
            new THREE.Plane(new THREE.Vector3(1, 0, 0), -10),
            new THREE.Plane(new THREE.Vector3(0, 1, 0), -1)
        ];

        var plane = planes[0];
        var stencilGroup = this.createPlaneStencilGroup(geometry, plane, 1);

        var planeMat =
            new THREE.MeshStandardMaterial({
                color: 0xE91E63,
                metalness: 0.1,
                roughness: 0.75,
                clippingPlanes: planes.filter(p => p !== plane),

                stencilWrite: true,
                stencilRef: 0,
                stencilFunc: THREE.NotEqualStencilFunc,
                stencilFail: THREE.ReplaceStencilOp,
                stencilZFail: THREE.ReplaceStencilOp,
                stencilZPass: THREE.ReplaceStencilOp,

            });
        var planeGeom = new THREE.PlaneBufferGeometry(40, 40);
        var po = new THREE.Mesh(planeGeom, planeMat);
        po.onAfterRender = function (renderer) {

            renderer.clearStencil();

        };
        poGroup.add(po);
        object.add(stencilGroup);

        var material = new THREE.MeshPhongMaterial({
            vertexColors: THREE.VertexColors,
            side: THREE.DoubleSide,
            transparent: transparent,
            opacity: opacity,
            shininess: 30,
            reflectivity: 0.5,
            clippingPlanes: planes,
            clipIntersection: false
        });
        var mesh = new THREE.Mesh(geometry, material);
        mesh.partID = part.id;
        mesh.faces = faceList;
        mesh.color = (!randomColors ? null : color.getHex());
        mesh.visible = false;

     this.partGroup.add(mesh);
}
    this.scene.add(object);
    this.scene.add(poGroup);
    this.scene.add(this.partGroup);
    this.updateGL();

I followed the exact code from the examples (except the creation of my original mesh is done using BufferGeometry(). I still end up getting the part without any cap (however the cutting planes cut through fine). I’d really appreciate if I could get help on this. Note that the createPlaneStencilGroup() function is unchanged from the examples:

@Mugen87 . Your expertise would be highly appreciated :slight_smile:

Sorry, I’m afraid I’m not a big help here since this a very specific part of the library I’m not familiar with. I personally think the material stencil API and the respective example is a bit complicated. I’m not surprised that devs struggle with it.

Maybe it’s easier to investigate this issue if you share a link to your application. Or maybe a reduced test case demonstrating the issue.

2 Likes

The idea is to be able to cap a cut 3-D geometry. In the case of the cylinder I’d expect to have the cut plane to be filled similar to the way that the example fills the TorusKnot. The only major difference between my project and the example is that mine is a BufferGeometry created using vertex positions and vertex colors while the example uses the TorusKnotBufferGeometry.

@rahul.pillai93

If you provide a jsfiddle I can try to update it to properly clip your geometry.

@Mugen87

I personally think the material stencil API and the respective example is a bit complicated.

I think stencil operations are pretty complicated in general because they’re very abstract and order dependent – I see people struggle to understand them in other contexts, as well. I’m curious what improvements you would suggest. I do agree that the stencil example could be simplified a bit to be more clear. I do have a PR in for that but it depends on updates to the group render order. Possibly there should be an extra simplified example that just demonstrates how to clip using one plane, as well.

1 Like

I think we need an API that completely hides the stencil interface from the user. I have not something ready to share but it should be something that covers the most common masking use cases.

3 Likes

This is my first three.js fiddle. I hope it works :slight_smile::
https://jsfiddle.net/0n56pjm2/

Note that I need the cylinder to be capped entirely by the cutting plane so it looks as if it is solid (and not hollow). For simple geometries the API might be useful but I am working with BufferGeometries that are more complex and are created using points , normals and vertex colors for the material. I cannot recreate this as I use a huge database of points so in the example above I’ve just created a simple cylinderGeometry and cut it using a cuttingPlane on the material.

Hey rahul.
I’ve been researching for months on this topic and thought I’d save you some time and toss some links I found on my searches your way re: capping clipped planes…(which I think should be incorporated together succinctly)…

1st, this incredibly satisfying example:
http://daign.github.io/clipping-with-caps/

And etc…

And probably one of the most valuable scenarios…
More easily described:

1 Like

@rahul.pillai93 I’ve gone ahead and updated your fiddle to clip the cylinder with caps – hopefully this is what you’re looking for:

https://jsfiddle.net/dokev2hy/1/

4 Likes

Thanks so much @gkjohnson and @GlifTek . These should work great for my use. I found the stencil example good but couldn’t simplify things from it.

Also @gkjohnson. Any reason why when I run the updated fiddle, it still shows up as hollow ? :

Looks like I’d posted an outdated version of the fiddle. I updated my post above but here’s the updated link, as well:

https://jsfiddle.net/dokev2hy/1/

Sorry about that!

1 Like

Thanks so much for this fiddle. Sorry for the late reply, I’ve been busy with some stuff. Just a quick question on your fiddle -
Is there anyway for the geometry to highlight boundaries between different parts being cut by the same plane ?

For instance check out this updated fiddle from the code that you sent me (note I have commented out line 74 to hide the stencil plane):https://jsfiddle.net/u2ax3p7e/
If the plane is added then there is no way to tell that there is a smaller cylinder in the geometry. Is there any way to add boundary lines to show the difference ? Something like the image below (please note the image is just edited on MS paint):
Untitled

Once again thanks so much for the fiddle! It really helped me get through my project. Some other the cool stuff I’d like to do in the future is to be able to highlight different stencil colors based on different parts cut (as in the example above).

1 Like

I don’t have any simple ways off the top of my head but I’m sure it’s doable – it would likely take custom effects and shaders to make it, though, without making clipping the geometry itself.

Glad the fiddle was helpful!

2 Likes

Possibly make TWO clipping planes, each terminating at the inner edge, where the second inner cylinder (cavity?) Is?