从场景中拾取几何体并将几何体及其线框一起移除

pick geometry from the scene and remove geometry and its wireframe together

我想添加和删除一个几何图形及其线框。我可以使用 raycaster 从场景中选取 object,但很难选取线框。

我能想到的一种方法是创建一组 object 及其线框,当光线投射器与 object 相交时(例如 obj.geometry.type == "BoxGeometry" ), 找到它的 parent 并删除 parent。但是,线框必须是一些可以添加为 child 的几何体。我正在使用 Boxhelper 为立方体创建线框,它应该直接添加到场景中,而不是作为 child 添加到任何 object。什么是解决这个问题的好方法?

谢谢。

我不确定我是否理解您的确切意图,但也许您可以创建对象的克隆,并将其渲染为线框。然后可以将克隆线框对象作为子对象添加到原始对象。所以当原始物体被拾取时,您可以将其从场景中移除,然后线框物体也会被移除。

克隆您的对象并将其 material 更改为线框:

var wireframe = cube.clone();
wireframe.material = new THREE.MeshBasicMaterial({color: 0xff0000, wireframe: true});
cube.add( wireframe ); // adding wireframe as child to the cube

拾取对象时:检查它是否是立方体几何体(如果您只希望它与立方体一起使用)并检查其 material 是否是线框(如果您不想删除线框也没有移除立方体)

if (pickedObject.geometry.type == "BoxGeometry" && 
   !pickedObject.material["wireframe"]){
  pickedObject.parent.remove(pickedObject); //this will remove object from
                                            // scene if it has no parents
}

工作示例:

var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera( 75, window.innerWidth/window.innerHeight, 0.1, 1000 );

var renderer = new THREE.WebGLRenderer();
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );

var geometry = new THREE.BoxGeometry( 1, 1, 1 );
var material = new THREE.MeshBasicMaterial( { color: 0x00ff00 } );
var cube = new THREE.Mesh( geometry, material );
scene.add( cube );

var wireframe = cube.clone();
wireframe.material = new THREE.MeshBasicMaterial({color: 0xff0000, wireframe: true});
    
cube.add( wireframe );

//picking stuff
var raycaster = new THREE.Raycaster();
var mouse = new THREE.Vector2();

function onMouseClick( event ) {

 // calculate mouse position in normalized device coordinates
 // (-1 to +1) for both components

 mouse.x = ( event.clientX / window.innerWidth ) * 2 - 1;
 mouse.y = - ( event.clientY / window.innerHeight ) * 2 + 1;  
  
  // update the picking ray with the camera and mouse position 
 raycaster.setFromCamera( mouse, camera ); 

 // calculate objects intersecting the picking ray
 var intersects = raycaster.intersectObjects( scene.children );

 for ( var i = 0; i < intersects.length; i++ ) {

    if (intersects[ i ].object.geometry.type == "BoxGeometry" && 
       !intersects[ i ].object.material["wireframe"]){
   intersects[ i ].object.parent.remove(intersects[ i ].object);
  }
 }

}

camera.position.z = 5;

var render = function () {
  requestAnimationFrame( render );

  cube.rotation.x += 0.1;
  cube.rotation.y += 0.1;

  renderer.render(scene, camera);
};
window.addEventListener( 'mouseup', onMouseClick, false );
render();
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r71/three.min.js"></script>

还有一种方法可以使用 Three.EdgesHelper 而不是克隆来完成您需要的操作,如 this fiddle 中所示。这显示了没有对角线的线框。

即使您不想使用 Three.EdgesHelper,我注意到在实施上面的克隆解决方案时,它并没有完全显示线框,因为它被稍微隐藏了。

为了避免这种隐藏,我在 material 的构造函数中添加了以下代码,它稍微偏移了原始形状,以便可以完全看到线框:

var material = new THREE.MeshLambertMaterial({ polygonOffset: true, polygonOffsetFactor: 1, polygonOffsetUnits: 1 })

我希望这在某种程度上有用。