I am trying to section my 3D models using three.js in a way similar to how Unity can:
I have been playing around with the camera controls and of course I can adjust the near / far fields to clip in the direction of the camera, but what if I wanted to just clip in the X or Y plane? I looked at potentially adding a large transparent block that could slide on that axis and then use binary operations to merge / subtract where it intersects the object, but the tools end up creating a new mesh along the new plane rather than actually removing everything along that axis.
Do I need to be working with multiple viewports, or is there a simpler way?
Clipping can be easily done in the shader. Using some calculations you could even have a for example sphere like clipping area. Clipping at a plane orthogonal to the coordinate system is the easiest. In the vertex shader calculate the world position of the pixel:
worldPosition = modelMatrix * vec4( position, 1.0 );
In the fragment shader discard the drawing of the pixel if it is beyond your clipping limit:
if ( worldPosition.x > clippingLimitX ) {
discard;
}
This will however leave the mesh open at the clipping edge. To close it use a stencil buffer. Decrement the stencil with a scene showing the backfaces. Then increment the stencil with a scene showing the clipped front faces. The materials used in these scenes should not be visible so disable their color and depth write:
new THREE.ShaderMaterial( { colorWrite: false, depthWrite: false, ... } );
Use the stencil to render a plane that is located at the clipping planes position. After disabling the stencil render the clipped front faces.
renderer.autoClear = false;
renderer.clear();
var gl = renderer.context;
renderer.state.setStencilTest( true );
renderer.state.setStencilFunc( gl.ALWAYS, 1, 0xff );
renderer.state.setStencilOp( gl.KEEP, gl.KEEP, gl.INCR );
renderer.render( backStencilScene, camera );
renderer.state.setStencilFunc( gl.ALWAYS, 1, 0xff );
renderer.state.setStencilOp( gl.KEEP, gl.KEEP, gl.DECR );
renderer.render( frontStencilScene, camera );
renderer.state.setStencilFunc( gl.EQUAL, 1, 0xff );
renderer.state.setStencilOp( gl.KEEP, gl.KEEP, gl.KEEP );
renderer.render( capsScene, camera );
renderer.state.setStencilTest( false );
renderer.render( scene, camera );
I made a demo showing how to clip at more than one plane at once:
http://daign.github.io/clipping-with-caps/
I didn't use the build-in three.js clipping planes because for this demo to work I have to render the stencil using a shader that determines whether a clipping plane is facing away from the camera or not, and only clip at those planes facing the camera.
Clipping is now supported.
Here is the pattern to follow. Adapt it according to your use case.
var localPlane = new THREE.Plane( new THREE.Vector3( 0, - 1, 0 ), 1 );
var globalPlane = new THREE.Plane( new THREE.Vector3( 1, 0, 0 ), 1 );
renderer.clippingPlanes = [ globalPlane ];
renderer.localClippingEnabled = true;
var material = new THREE.MeshPhongMaterial( {
clippingPlanes: [ localPlane ],
clipShadows: true
} );
See these three.js examples:
https://threejs.org/examples/webgl_clipping.html https://threejs.org/examples/webgl_clipping_advanced.html
three.js r.85
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With