Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/three.js/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript Three.js:“;选择工具";如何检测二维正方形与三维对象的交点_Javascript_Three.js_Intersection_Raycasting - Fatal编程技术网

Javascript Three.js:“;选择工具";如何检测二维正方形与三维对象的交点

Javascript Three.js:“;选择工具";如何检测二维正方形与三维对象的交点,javascript,three.js,intersection,raycasting,Javascript,Three.js,Intersection,Raycasting,基本上,我想创建: 我有一个带有对象的3D地图,我想在屏幕上选择2D框x1、y1到x2、y2中的所有对象 我不知道该怎么做,因为我不知道该怎么开始 提前谢谢 prevX和prevY是鼠标按下的坐标: function onDocumentMouseUp(event) { event.preventDefault(); var x = (event.clientX / window.innerWidth) * 2 - 1; var y = -(event.clientY / wind

基本上,我想创建:

我有一个带有对象的3D地图,我想在屏幕上选择2D框x1、y1到x2、y2中的所有对象

我不知道该怎么做,因为我不知道该怎么开始

提前谢谢

prevX
prevY
是鼠标按下的坐标:

function onDocumentMouseUp(event) {
  event.preventDefault();

  var x = (event.clientX / window.innerWidth) * 2 - 1;
  var y = -(event.clientY / window.innerHeight) * 2 + 1;

  var width = (x - prevX); //* window.innerWidth;
  var height = (y - prevY); //* window.innerHeight;
  var dx = prevX; //* window.innerWidth;
  var dy = prevY; //* window.innerHeight;

  console.log(
    dx + ',' + 
    dy + "," + 
    (dx + width) + "," + 
    (dy + height) + 
    ", width=" + width + 
    ", height=" + height
  );
  var topLeftCorner3D = new THREE.Vector3(dx, dy, 1).unproject(
    camera);
  var topRightCorner3D = new THREE.Vector3(dx + width, dy, 1)
    .unproject(camera);
  var bottomLeftCorner3D = new THREE.Vector3(dx, dy + height,
    1).unproject(camera);
  var bottomRightCorner3D = new THREE.Vector3(dx + width, dy +
    height, 1).unproject(camera);

  var topPlane = new THREE.Plane();
  var rightPlane = new THREE.Plane();
  var bottomPlane = new THREE.Plane();
  var leftPlane = new THREE.Plane();

  topPlane.setFromCoplanarPoints(camera.position,
    topLeftCorner3D, topRightCorner3D);
  rightPlane.setFromCoplanarPoints(camera.position,
    topRightCorner3D, bottomRightCorner3D);
  bottomPlane.setFromCoplanarPoints(camera.position,
    bottomRightCorner3D, bottomLeftCorner3D);
  leftPlane.setFromCoplanarPoints(camera.position,
    bottomLeftCorner3D, topLeftCorner3D);

  //var frustum = new THREE.Frustum( topPlane, bottomPlane, leftPlane, rightPlane, nearPlane, farPlane);

  function isObjectInFrustum(object3D) {
    var sphere = object3D.geometry.boundingSphere;
    var center = sphere.center;
    var negRadius = -sphere.radius;

    if (topPlane.distanceToPoint(center) < negRadius) { return false; }
    if (bottomPlane.distanceToPoint(center) < negRadius) { return false; }
    if (rightPlane.distanceToPoint(center) < negRadius) { return false; }
    if (leftPlane.distanceToPoint(center) < negRadius) { return false; }

    return true;
  }
  var matches = [];
  for (var i = 0; i < window.objects.length; i++) {

    if (isObjectInFrustum(window.objects[i])) {
      window.objects[i].material = window.selectedMaterial;
    }
  }
}
函数onDocumentMouseUp(事件){
event.preventDefault();
var x=(event.clientX/window.innerWidth)*2-1;
变量y=-(event.clientY/window.innerHeight)*2+1;
变量宽度=(x-prevX);//*window.innerWidth;
变量高度=(y-上一个);//*window.innerHeight;
var dx=prevX;//*window.innerWidth;
var dy=prevY;//*window.innerHeight;
console.log(
dx+','+
dy+“,”+
(dx+宽度)+“,”+
(dy+高度)+
“,width=“+width+
“,height=“+height
);
var topLeftCorner3D=新的三个向量3(dx,dy,1)。取消投影(
摄像机);
var topRightCorner3D=新的三个矢量3(dx+宽度,dy,1)
.未投影(摄像机);
var bottomLeftCorner3D=新的三个矢量3(dx,dy+高度,
1) .未投影(摄像机);
var bottomRightCorner3D=新的三个矢量3(dx+宽度,dy+
高度,1)。未投影(摄像机);
var topPlane=新的三个平面();
var rightPlane=new THREE.Plane();
var bottomPlane=新的三个平面();
var leftPlane=new THREE.Plane();
topPlane.setFromCoplanarPoints(camera.position,
topLeftCorner3D、topRightCorner3D);
右平面。从共面点(camera.position,
topRightCorner3D,bottomRightCorner3D);
底部平面。从共面点(camera.position,
bottomRightCorner3D、bottomLeftCorner3D);
leftPlane.setFromCoplanarPoints(camera.position,
底部LeftCorner3D、顶部LeftCorner3D);
//var frustum=新的三个截头体(顶平面、底平面、左平面、右平面、近平面、远平面);
函数isObjectInFrustum(object3D){
var sphere=object3D.geometry.boundingSphere;
var center=sphere.center;
var negRadius=-sphere.radius;
if(topPlane.distanceToPoint(center)
您可以使用对象的边界框<代码>三。几何体包含一个
边界框
属性。默认情况下这是
null
,您应该直接调用
computeBoundingBox()
来计算它

scene.traverse( function ( node ) {
    if ( node.geometry )
         node.geometry.computeBoundingBox();
} );
拥有边界框后,边界框二维坐标为(如果“y”是上方向轴):


(但是,如果需要非矩形网格的精确结果,则需要进一步计算)

与屏幕空间中的长方体相交相当于与三维空间中的棱锥体(透视)或立方体(正交视图)相交。我认为你应该根据你的2D框定义一个
THREE.trustum

对于透视摄影机:

  • 将屏幕空间框角坐标转换为3D矢量(从相机位置到给定点的矢量)
  • var topLeftCorner3D=新的三个.Vector3(topLeftCorner2D.x,topLeftCorner2D.y,1)。取消投影( 摄像机)

  • 基于这些点构造4个平面(一个平面对应一个长方体侧面)。平面的第三点是摄影机位置
  • topPlane.setFromCoplanarPoints(camera.position、topLeftCorner3D、topRightCorner3D) rightPlane.setFromCoplanarPoints(camera.position、topRightCorner3D、topRightCorner3D) bottomPlane.setFromCoplanarPoints(摄影机位置、bottomRightCorner3D、bottomLeftCorner3D) leftPlane.setFromCoplanarPoints(camera.position,底部LeftCorner3D,顶部LeftCorner3D)

  • 基于这些平面构造一个平截头体,将摄影机近平面和远平面添加到这些平面
  • var frustum=新的三个截头体(顶平面、底平面、左平面、右平面、近平面、远平面)

  • 将平截头体与对象相交
  • 截锥体.相交框(对象.几何体.边界框)

    平截头体.相交球体(对象.几何体.边界球体)

    使用
    平截头体
    对象本身的替代方法:可以跳过近平面和远平面,只需检查对象是否位于与4个平面相邻的空间中。您可以编写一个类似于
    trustum.intersectSphere()
    方法的函数,该函数只有4个平面:

    function isObjectInFrustum(object3D) {
        var sphere = object3D.geometry.boundingSphere;
        var center = sphere.center;
        var negRadius = - sphere.radius;
    
        if ( topPlane.distanceToPoint( center )< negRadius ) return false;
        if ( bottomPlane.distanceToPoint( center )< negRadius ) return false;
        if ( rightPlane.distanceToPoint( center )< negRadius ) return false;
        if ( leftPlane.distanceToPoint( center )< negRadius ) return false;
    
        return true;  
    }
    
    函数isObjectInFrustum(object3D){
    var sphere=object3D.geometry.boundingSphere;
    var center=sphere.center;
    var negRadius=-sphere.radius;
    if(topPlane.distanceToPoint(center)
    有关比底壳选择更精确的方法,请参阅。它的工作原理是将边界框的8个角投影到屏幕空间,然后与屏幕矩形相交。第三种更快的方法(用ClojureScript编写)将3D边界球体投影到屏幕空间的边界圆上,以及前两种方法的实现。它尝试使用GPU执行屏幕投影和readpixels拾取(我没有研究过这种方法,因为我认为readpixels会使渲染管道过多地暂停,但如果我错了,请告诉我)

    我在上做了一个底壳选择的工作示例,但它太不准确了。重要的部分是:

              var rx1 = ( x1 / window.innerWidth ) * 2 - 1;
              var rx2 = ( x2 / window.innerWidth ) * 2 - 1;
              var ry1 = -( y1 / window.innerHeight ) * 2 + 1;
              var ry2 = -( y2 / window.innerHeight ) * 2 + 1;
    
              var projectionMatrix = new THREE.Matrix4();
              projectionMatrix.makeFrustum( rx1, rx2, ry1, ry2, camera.near, camera.far );
    
              camera.updateMatrixWorld();
              camera.matrixWorldInverse.getInverse( camera.matrixWorld );
    
              var viewProjectionMatrix = new THREE.Matrix4();
              viewProjectionMatrix.multiplyMatrices( projectionMatrix, camera.matrixWorldInverse );
    
              var frustum = new THREE.Frustum();
              frustum.setFromMatrix( viewProjectionMatrix );
    

    谢谢,我明天去看看。然而,我不确定
              var rx1 = ( x1 / window.innerWidth ) * 2 - 1;
              var rx2 = ( x2 / window.innerWidth ) * 2 - 1;
              var ry1 = -( y1 / window.innerHeight ) * 2 + 1;
              var ry2 = -( y2 / window.innerHeight ) * 2 + 1;
    
              var projectionMatrix = new THREE.Matrix4();
              projectionMatrix.makeFrustum( rx1, rx2, ry1, ry2, camera.near, camera.far );
    
              camera.updateMatrixWorld();
              camera.matrixWorldInverse.getInverse( camera.matrixWorld );
    
              var viewProjectionMatrix = new THREE.Matrix4();
              viewProjectionMatrix.multiplyMatrices( projectionMatrix, camera.matrixWorldInverse );
    
              var frustum = new THREE.Frustum();
              frustum.setFromMatrix( viewProjectionMatrix );