javascript - Three.js: "select tool"如何检测2D正方形与3D物体的交集

标签 javascript three.js intersection raycasting

基本上我想创建的是:

我有一个包含对象的 3D map ,我想选择屏幕上 2D 框 x1,y1 到 x2,y2 中的所有对象。

关于如何完成的任何想法,因为我对如何开始一无所知。

提前致谢!

prevXprevY 是鼠标按下的坐标:

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

最佳答案

在屏幕空间中相交一个盒子相当于在 3D 空间中相交一个金字塔(透视图)或一个立方体(正交 View )。我认为您应该根据您的 2D 框定义一个 THREE.Frustum

对于透视相机:

  1. 将屏幕空间框 Angular 坐标转换为 3D 向量(从相机位置到给定点的向量)

var topLeftCorner3D = new THREE.Vector3( topLeftCorner2D.x, topLeftCorner2D.y, 1 ).unproject( camera );

  1. 根据这些点构建 4 个平面(一个平面代表盒子的一侧)。平面的第三个点是相机位置。

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

  1. 基于这些平面构造一个视锥体,将相机近平面和远平面添加到它们。

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

  1. 将平截头体与对象相交

frustum.intersectsBox(object.geometry.boundingBox)

frustum.intersectsSphere(object.geometry.boundingSphere)

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

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

关于javascript - Three.js: "select tool"如何检测2D正方形与3D物体的交集,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27295415/

相关文章:

javascript - 根据当前 URL React 渲染页脚

javascript - 使 javascript-snippet 影响 3 个 div,而不是 1 个

javascript - Three.js顶点着色器: update attributes and how to save a value for the next processing round

javascript - 94个字符一行任务,圆交点

sql - 从两个相同的表中选择并相交

javascript - jQuery 对象序列化

javascript - 如果字符串数量仅为 0,则隐藏另一个元素

javascript - OBJ 文件未出现在浏览器 WebGL Three.js 中

reactjs - 如何设置 OrbitalControls 初始位置?

python - 有没有办法获得多条曲线与另一条曲线的所有交点?