Detection with raycaster not completely accurate when the width of div is reduced, three.js(v72)
Asked Answered
P

4

11

here is my code for calculating the intersection:

var wallWidth = 1200;
var wallHeight = 500;
var containerWidth=1200,containerHeight=700; //div 
//camera
camera = new THREE.PerspectiveCamera(60, containerWidth/containerHeight, 1, 10000);
camera.position.set(0, -wallHeight / 2 + 10, wallWidth);

here is my function which intersect with object on mouse move

function onDocumentMouseMove(event) {

        mouse.x = ( event.clientX / containerWidth ) * 2 - 1;
        mouse.y = -( event.clientY / containerHeight ) * 2 + 1;

        var deltaX = event.clientX - mouseX;
        var deltaY = event.clientY - mouseY;

        raycaster.setFromCamera(mouse, camera);
        var intersects = raycaster.intersectObjects(interactiveObj, true);

        if (intersects.length > 0) {
            //interaction with object
        }

        render();
    }

It is working correctly, i.e i am getting the value in intersects object when the width of the div is 100%, but when i reduce the div size to 80% then the object is not picking up correctly, i.e it pick the object when the mouse is quite far from object.

Pock answered 20/1, 2016 at 5:39 Comment(0)
R
18

use below code for chnage your mouse vector

function onDocumentMouseMove(event) {

    mouse.x = ( (event.clientX -renderer.domElement.offsetLeft) / renderer.domElement.width ) * 2 - 1;
    mouse.y = -( (event.clientY - renderer.domElement.offsetTop) / renderer.domElement.height ) * 2 + 1;

    var deltaX = event.clientX - mouseX;
    var deltaY = event.clientY - mouseY;

    raycaster.setFromCamera(mouse, camera);
    var intersects = raycaster.intersectObjects(interactiveObj, true);

}

Reluctance answered 20/1, 2016 at 6:22 Comment(2)
Instead of using event.clientX - renderer.domElement.offsetLeft you can just use event.offsetX developer.mozilla.org/en-US/docs/Web/API/MouseEvent/offsetXVexation
Your solution fixed also my raycasting issue; I guess doing it on mousemove instead of rendre makes sure that the scene is up to date ? If someone has some additionnal information about why it works better this way than in Three.js's exemple threejs.org/docs/#api/en/core/Raycaster ?Stitching
G
5

Instead of using event.clientX - renderer.domElement.offsetLeft you can just use event.offsetX

I was having the same problem and Brakebein's answer worked best for what I needed.

Gallinaceous answered 20/7, 2016 at 11:26 Comment(1)
Solved my issue after 2 days of tryingKosher
S
3

The following way of getting the relative mouse position seems to be more accurate.

var rect = renderer.domElement.getBoundingClientRect();
mouse.x = ( ( event.clientX - rect.left ) / rect.width ) * 2 - 1;
mouse.y = - ( ( event.clientY - rect.top ) / rect.height ) * 2 + 1;
Stickpin answered 19/5, 2017 at 1:5 Comment(0)
P
0

After long searching this variant using React help me to enhance raycaster precision (maybe it help someone):

class Scene extends React.Component {

 componentDidMount() {
  const width = 400;
  const height = 400;

  const scene = new THREE.Scene();
  const camera = new THREE.PerspectiveCamera(95, width / height, 1, 1000);
  const renderer = new THREE.WebGLRenderer({ antialias: true });
  var controls = new OrbitControls(camera);



  const geometry = new THREE.SphereGeometry(2, 100, 100);

  .....

  const material = new THREE.MeshBasicMaterial({
    color: "#00bfff",
    map: canvasTexture
});
  const sphere = new THREE.Mesh(geometry, material);

  camera.position.z = 3;
  scene.add(sphere);
  renderer.setClearColor("#FFF");
  renderer.setSize(width, height);

  this.scene = scene;
  this.camera = camera;
  this.renderer = renderer;
  this.material = material;
  this.sphere = sphere;
  this.geometry = geometry;
  this.mouse = new THREE.Vector2();
  this.raycaster = new THREE.Raycaster();
 }

 ...

 clickHandler = event => {

  const mainEl = document.getElementById("mainBlock");
  const rect = mainEl.getBoundingClientRect();

  this.mouse.x = (event.clientX - rect.left) / mainEl.clientWidth * 2 - 1;
  this.mouse.y = -((event.clientY - rect.top) / mainEl.clientHeight) * 2 + 1; 

  this.raycaster.setFromCamera(this.mouse, this.camera);
  const intersects = this.raycaster.intersectObject(this.sphere);


  if (intersects.length !== 0) {
    ...
  }
};

render() {
  <div
    id="mainBlock"
    style={{ width: "400px", height: "400px" }}
    ref={mount => {
      this.mount = mount;
    }}
    onClick={this.clickHandler}
  >
     ...
  </div>
}

}
Presser answered 27/4, 2018 at 14:30 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.