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.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…