Three.JS对象裁剪?

8
我正在尝试使用three.js对3D模型进行分区,类似于Unity的方式: enter image description here 我一直在调整相机控制器,当然可以调整近/远平面以在相机方向上剪裁,但如果我想在X或Y平面上剪裁怎么办?我考虑添加一个大的透明块,在该轴上滑动,然后使用二进制操作来合并/减去它与对象相交的部分,但工具最终会沿着新平面创建一个新的网格,而不是实际上删除沿着该轴的所有内容。
我需要使用多个视口进行工作吗,还是有更简单的方法?

1
剪裁现在在dev分支r.76dev中得到支持。请参见http://ci.threejs.org/api/pullrequests/8465/examples/webgl_clipping.html。 - WestLangley
太棒了,谢谢West,如果你把它作为答案添加进去,我就可以将其标记为解决方案 :) - Alan
2个回答

26

在着色器中可以轻松进行裁剪。使用一些计算,您甚至可以拥有例如球形的裁剪区域。垂直于坐标系的平面裁剪最简单。在顶点着色器中计算像素的世界位置:

worldPosition = modelMatrix * vec4( position, 1.0 );

在片段着色器中,如果像素超出了裁剪范围,请放弃绘制该像素:

if ( worldPosition.x > clippingLimitX ) {
    discard;
}

然而,这将使剪裁边缘处的网格保持开放状态。要关闭它,请使用模板缓冲区。使用显示背面的场景减量模板。然后使用显示经过剪裁的前面的场景增加模板。 这些场景中使用的材料不应该可见,因此禁用它们的颜色和深度写入:

new THREE.ShaderMaterial( { colorWrite: false, depthWrite: false, ... } );
使用模板将位于剪切平面位置的平面渲染出来。在禁用模板后,渲染被剪裁的正面。
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 );

我做了一个演示,展示了如何同时剪裁多个平面:

http://daign.github.io/clipping-with-caps/

我没有使用内置的 three.js 剪裁平面,因为为了让这个演示工作,我必须使用一个着色器来渲染模板缓冲区,确定剪裁平面是否朝向远离相机的方向,并只在那些朝向相机的平面上进行剪裁。


1
不错。还可以参考这个答案。然而,对于直径远大于高度的开放圆柱体几何体,这两种方法都存在问题。 - WestLangley
5
太好了!你能否提供如何在剪辑位置绘制一条“粗线”的建议。介于开放和闭合网格之间的某种中间状态。谢谢! - Nicolas
@daign非常感谢您!一直在想如何实现这种效果。 - andrevenancio

20

现在支持剪裁。

这是要遵循的模式。根据您的用例进行适应。

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
} );

查看这些three.js示例:

https://threejs.org/examples/webgl_clipping.html https://threejs.org/examples/webgl_clipping_advanced.html

three.js r.85


抱歉我来晚了。@WestLangley,我正在尝试启用剪裁平面,但我不确定你的回答中的本地和全局剪裁平面是什么意思?我应该同时启用两个吗? - Rahul Pillai
2
@RahulPillai 全局剪裁平面是每个渲染器的。本地剪裁平面是每个材质的。请参见 https://threejs.org/docs/index.html#api/en/materials/Material.clippingPlanes。 - WestLangley
1
就我个人而言,我将three.js代码从一个项目移植到另一个项目,并花费了数小时来查找罪魁祸首。最终发现是因为render.localClippingEnabled被设置为false:/ - Jacksonkr

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接