Three.Js Ray Intersect Fails by Adding Div

THREE.js Ray Intersect fails by adding div

The short answer is you have to take into consideration the offset of the canvas.

The long answer depends on how your code is written, so I'll give you two answers, which should cover the bases.

There are a lot of possible combinations, so you may have to experiment. Also, different browsers may act differently.

Assume your HTML is something like this:

#canvas {
width: 200px;
height: 200px;
margin: 100px;
padding: 0px;
position: static; /* fixed or static */
top: 100px;
left: 100px;
}

<body>
<div id="canvas">
</body>

Your JS is something like this:

var CANVAS_WIDTH = 200,
CANVAS_HEIGHT = 200;

var container = document.getElementById( 'canvas' );
document.body.appendChild( container );

renderer = new THREE.WebGLRenderer();
renderer.setSize( CANVAS_WIDTH, CANVAS_HEIGHT );
container.appendChild( renderer.domElement );

Method 1 For the following method to work correctly, set the canvas position static; margin > 0 and padding > 0 are OK

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

Method 2 For this alternate method, set the canvas position fixed; set top > 0, set left > 0; padding must be 0; margin > 0 is OK

mouse.x = ( ( event.clientX - container.offsetLeft ) / container.clientWidth ) * 2 - 1;
mouse.y = - ( ( event.clientY - container.offsetTop ) / container.clientHeight ) * 2 + 1;

Here is a Fiddle if you want to experiment: http://jsfiddle.net/cn7ecoaa/

EDIT: Fiddle updated to three.js r.84

Three.js Inaccurate Raycaster

Your CSS will affect your raycasting calculations. One thing you can do is set

body {
margin: 0px;
}

For more information, see THREE.js Ray Intersect fails by adding div.

You also have to handle window resizing correctly. The typical pattern looks like this:

function onWindowResize() {

var aspect = window.innerWidth / window.innerHeight;

camera.left = - frustumSize * aspect / 2;
camera.right = frustumSize * aspect / 2;
camera.top = frustumSize / 2;
camera.bottom = - frustumSize / 2;

camera.updateProjectionMatrix();

renderer.setSize( window.innerWidth, window.innerHeight );

}

Study the three.js examples. In particular, see http://threejs.org/examples/webgl_interactive_cubes_ortho.html.

Also, read this answer, which describes how to properly instantiate an orthographic camera.

three.js r.80

ThreeJS Raycaster doesn't find intersected objects if canvas isn't full screen

If your flow is broken (your container is floated or manually positioned), then clientX/clientY will report "bad" values (relative to the page, rather than to the container like you might expect). The properties offsetX/offsetY account for this by reporting values relative to the container on which the event was fired.

According to MDN, support is limited, but my testing just now (01/22/2018) showed the latest versions of Chrome, Firefox, Edge, and IE all reported the correct values*. Just note that some browsers report integer values, while others may report double values.

*This may not hold true for Safari or mobile browsers. YMMV.

Threejs / Raycast doesn't compute intersection with my cube

It seems your code works by using a latest version of three.js. I've just refactored/simplified it a bit.

let camera, scene, renderer;

let mesh;

let raycaster, pointer = new THREE.Vector2();

init();
animate();

function init() {

camera = new THREE.PerspectiveCamera(35, window.innerWidth / window.innerHeight, 1, 1000);
camera.position.z = 40;

scene = new THREE.Scene();

const geometry = new THREE.BoxGeometry();
const material = new THREE.MeshBasicMaterial({
color: "red"
});

mesh = new THREE.Mesh(geometry, material);
mesh.position.set(0, 10, 0);
scene.add(mesh);

renderer = new THREE.WebGLRenderer({antialias: true});
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);

raycaster = new THREE.Raycaster();

renderer.domElement.addEventListener('pointerdown', raycast);

}

function raycast(e) {

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

raycaster.setFromCamera(pointer, camera);
const intersects = raycaster.intersectObject(scene);

for (let i = 0; i < intersects.length; i++) {
console.log(intersects[i]);
}
}

function animate() {

requestAnimationFrame(animate);

mesh.rotation.x += 0.01;
mesh.rotation.y += 0.02;

renderer.render(scene, camera);

}
body {
margin: 0;
}
<script src="https://cdn.jsdelivr.net/npm/three@0.140.2/build/three.min.js"></script>


Related Topics



Leave a reply



Submit