Does anyone know a good way or examples of 3D model clipping function on react-three-fiber in next.js app?

Hi, I’d like to implement the clipping function like the following sample on react-three-fiber in next.js app. I tried to find an example, but it hard to find.
https://threejs.org/examples/#webgl_clipping

Please let me know if someone know a good way or examples.

The following code will be work.
*You may need to set canvas size when run this.

{/* r3f */}
import Head from 'next/head';
import React, { Suspense, useState, useRef } from 'react';
import { Color,  Plane, Vector3, MeshStandardMaterial} from 'three';
import { Canvas, useThree, useLoader } from '@react-three/fiber';
import { OrbitControls, Html } from '@react-three/drei'
import { OBJLoader } from 'three-stdlib'

export default function modelViewer() {

  function Environment() {
    const { scene } = useThree();
    scene.background = new Color('rgb(220, 220, 220)');
    return <></>;
  }

  function Model() {
    const obj = useLoader(OBJLoader, '/model/bunny.obj');
    return (
      <>
        {obj && (
          <mesh position={[0, 0, 0]}>
            <primitive object={obj} scale={1.0}/>
          </mesh>
        )}
      </>
    );
  };

  function ClippingPlane() {
    const { gl } = useThree();
    let plane = new Plane( new Vector3( 0, - 1, 0 ), 0.8 );
    gl.clippingPlanes = [plane];
    gl.localClippingEnabled = true;
    return <></>;
  }

  return (
    <Head>
      <title>test</title>
    </Head>
    <Canvas>
      <Suspense fallback={<Html center>Loading...</Html>}>
        <ClippingPlane />
        <Environment />
        <Model />
        <directionalLight color="#999999" intensity={1} position={[-1, 2, 4]} />
        <directionalLight color="#999999" intensity={1} position={[1, -2, -4]} />
      </Suspense>
      <OrbitControls/>
    </Canvas>
  );
}

here’s one for stencil clipping masks r3f-torus-gag (forked) - CodeSandbox

ps. i would suggest you use Canvas onCreated for one-time gl specific configuration:

<Canvas onCreated={({ gl }) => {
  const plane = new Plane(new Vector3(0, -1, 0), 0.8)
  gl.clippingPlanes = [plane]
  gl.localClippingEnabled = true
}>

making this a component as you did above is not wrong but then it should be a side effect (useEffect) and have a cleanup because if you unmount the component it should go back to default:

function ClippingPlane() {
  const { gl } = useThree()
  useEffect(() => {
    // Save previous defaults 
    const { clippingPlanes, localClippingEnabled } = gl
    const plane = new Plane(new Vector3(0, -1, 0), 0.8)
    gl.clippingPlanes = [plane]
    gl.localClippingEnabled = true
    // Go back to defaults on unmount
    return () => Object.assign(gl, { clippingPlanes, localClippingEnabled})
  }, [])
  return null
}

and now you have a re-usable component that’s safe to mount/unmount without causing left-overs.

@drcmda
Thanks for the advice! That’s totally better than my code!

great answer from @drcmda

I wonder:
h1. ow could I render caps on the clipped mesh?
2. how could I move the position of the clipping plane?

it is possible with stencils, i found it once on stackoverflow but deleted the sandbox i made. search for clipping, cap, stencil.

1 Like

thanks @drcmda
I found this sandbox that was very helpful