Giulio Ganci
Giulio Ganci

Reputation: 33

Imprecise raycast with orthographic camera in three.js

I'm developing a 2d viewer of CAD drawings using the three.js library and for this project I need to be able to click the objects in the scene to do some operations.

Using orthographic camera the three.js raycasting is not precise as I expect.

Here the code and a fiddle that shows exactly what I mean 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';
}

If you pass the mouse near the red square you can see that the intersection trigger before hovering the edge.

What am I doing wrong?

Upvotes: 3

Views: 1497

Answers (1)

Rabbid76
Rabbid76

Reputation: 210908

The intersection detection of lines depends on the .linePrecision property of the Raycaster.

e.g.

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

The parameter has to be set dependent on the scale of the scene. The value of 0.1 is an empirical value, which gives good results for your example. Sadly there is not further information provided in the documentation (perhaps I've overlooked something, but I didn't find one).

Upvotes: 3

Related Questions