在three.js中使用正交相机进行不精确的光线投射

Posted

技术标签:

【中文标题】在three.js中使用正交相机进行不精确的光线投射【英文标题】:Imprecise raycast with orthographic camera in three.js 【发布时间】:2019-10-14 09:20:03 【问题描述】:

我正在使用 three.js 库开发 CAD 绘图的 2d 查看器,对于这个项目,我需要能够单击场景中的对象来执行一些操作。

使用正交相机,three.js 光线投射并不像我预期的那样精确。

这里的代码和一个小提琴,正是我的意思 https://jsfiddle.net/toriphes/a0o7td1u/

var camera, scene, renderer, square, raycaster;
init();
animate();

function init() 

  output = document.getElementById('output');

  raycaster = new THREE.Raycaster();
  // Renderer.
  renderer = new THREE.WebGLRenderer();
  //renderer.setPixelRatio(window.devicePixelRatio);
  renderer.setSize(window.innerWidth, window.innerHeight);
  // Add renderer to page
  document.body.appendChild(renderer.domElement);

  // Create camera.
  var aspect = window.innerWidth / window.innerHeight;
  var d = 20;
  camera = new THREE.OrthographicCamera(-window.innerWidth / 2, window.innerWidth / 2, window.innerHeight / 2, -window.innerHeight / 2, 1, 1000);
  camera.position.z = 10;
  camera.position.x = 25;
  camera.position.y = 25;
  camera.zoom = 10
  camera.updateProjectionMatrix()

  controls = new THREE.OrbitControls(camera, renderer.domElement);
  controls.enableRotate = false
  controls.target.x = camera.position.x;
  controls.target.y = camera.position.y;

  controls.update();


  // Create scene.
  scene = new THREE.Scene();

  var points = [
    new THREE.Vector2(10, 10),
    new THREE.Vector2(40, 10),
    new THREE.Vector2(40, 40),
    new THREE.Vector2(10, 40),
    new THREE.Vector2(10, 10)
  ]

  var shape = new THREE.Shape(points);

  var geometry = new THREE.Geometry().setFromPoints(points);

  var square = new THREE.Line(geometry, new THREE.LineBasicMaterial(
    color: 0xFF0000
  ));
  scene.add(square)

  document.addEventListener('mousemove', findIntersections, false);


function animate() 
  requestAnimationFrame(animate);
  renderer.render(scene, camera);


function updateMousePosition(event) 
  return new THREE.Vector3(
    (event.clientX - renderer.domElement.offsetLeft) /
    renderer.domElement.clientWidth *
    2 -
    1,
    -(
      (event.clientY - renderer.domElement.offsetTop) /
      renderer.domElement.clientHeight
    ) *
    2 +
    1,
    0
  );


function findIntersections(e) 
  var mouseposition = updateMousePosition(e);
  raycaster.setFromCamera(mouseposition, camera);
  const intersects = raycaster.intersectObjects(scene.children);
  output.innerhtml = intersects.length > 0 ?
    'Intersect: TRUE' :
    'Intersect: FALSE';

如果你在红色方块附近通过鼠标,你可以看到交叉点在悬停边缘之前触发。

我做错了什么?

【问题讨论】:

【参考方案1】:

线的交点检测取决于Raycaster.linePrecision属性。

例如

raycaster.linePrecision = 0.1;
const intersects = raycaster.intersectObjects(scene.children);

必须根据场景的比例设置参数。 0.1 的值是一个经验值,它为您的示例提供了良好的结果。遗憾的是,文档中没有提供更多信息(也许我忽略了一些东西,但我没有找到)。

【讨论】:

linePrecision = 0.1 似乎适用于我的项目。有更多关于它的文档会很有用。 很棒的提示。我使用值 0.01,这给了我想要的准确性。但大概这意味着光线投射器必须比使用值 0.1 时多做 10x10=100 倍的工作。 |是的,offical docs 中没有提到 linePrecision 属性。但是提到了params 对象,其中threshold 是光线投射器在与各种对象相交时的精度,以世界单位为单位。它解释了为什么当线对象的默认阈值为 1 时有时很难选择网格对象。

以上是关于在three.js中使用正交相机进行不精确的光线投射的主要内容,如果未能解决你的问题,请参考以下文章

three.js 正交相机对象拾取

three.js正交投影照相机

Three.js - 将光线从物体发送到相机

针对其中的盒子几何形状进行光线投射(three.js)

使用正交相机从鼠标位置获取 Three.js 世界坐标

Three.js用相机选择对象,没有鼠标