Three.JS Обрезка объектов?
Я пытаюсь разделить свои 3D-модели с помощью three.js так, как это делает Unity:
Я играл с элементами управления камерой и, конечно, я могу отрегулировать поля ближнего / дальнего поля, чтобы обрезать в направлении камеры, но что, если я хочу просто обрезать в плоскости X или Y? Я рассмотрел возможность добавления большого прозрачного блока, который мог бы скользить по этой оси, а затем использовать двоичные операции для слияния / вычитания там, где он пересекается с объектом, но в итоге инструменты создали новую сетку вдоль новой плоскости, а не фактически удалили все вдоль нее. ось.
Нужно ли работать с несколькими областями просмотра или есть более простой способ?
2 ответа
Отсечение теперь поддерживается.
Вот образец для подражания. Адаптируйте его в соответствии с вашим вариантом использования.
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
Отсечение может быть легко сделано в шейдере. Используя некоторые расчеты, вы можете даже получить, например, сферу, как область отсечения. Отсечение в плоскости, ортогональной системе координат, является самым простым. В вершинном шейдере вычисляем мировую позицию пикселя:
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, потому что для работы этой демонстрации мне нужно отрисовать трафарет с помощью шейдера, который определяет, направлена ли плоскость отсечения в сторону от камеры или нет, и только обрезать эти плоскости лицом к камере.