Double Click mouse event shows wrong objects.... raycaster problem?

raycaster

#1

I’m using a scene with various geometries to create a metal building. I’m using many translated and rotated items to form the individual walls and sections of the building. I want to double click on a specific wall or door and then do a function but when I double click on an wall, for example, sometimes it registers correct but many times it registers a totally different part of the building. Here’s my simple double click function:

function onDoubleClick(e) {
e.preventDefault();
raycaster.setFromCamera(mouse, camera);
intersects = raycaster.intersectObjects(building.children);
var clickedItem = intersects[0].object.name;
console.log('You clicked: ' + clickedItem);  }

Anyone know why the wrong meshes are being returned? Is this because my translated meshes are being seen in their original location or something?

Thanks in advance for your input.


#2

Can you reproduce the problem in a fiddle? Otherwise it will be hard to provide non-speculative input.

I don’t think so.


#3

There’s tons of code and I don’t have a clue where the problem lies and therefore how to narrow to a small portion of code to sample on fiddle, so I will provide samples of code that are consistently used for each object such as frontwall, leftroof , leftsoffitbox etc… and a brief Youtube video link so you can see the issue in action.

Please excuse my messy code as I’m learning Three.js. I understand that my code can be optimized in some areas such as using the same material for the walls instead of each having a separate material made individually for each wall. I appreciate and welcome any errors or optimization suggestions you notice. My main concern however is the double click selecting the wrong objects.

First some code, then the video link.

Code Note: I’m using ‘building’ as a group for all the building objects. In the raycaster code I’m referencing ‘building.chidren’ because I was using ‘scene.children’ but when I double clicked the wall it kept showing ‘ground’ object as being clicked. This may be a clue to the problem but I’m too much of a noob to connect the dots yet.

Here’s the left and right wall code:

// left wall
    lwGeo = new THREE.BoxGeometry(0.1, bHeight, bLength);
    lwText = loader.load( 'assets/' + mWallColor + '.jpg' );
    lwText.wrapS = lwText.wrapT = THREE.RepeatWrapping;
    lwText.repeat.set( bLength / 3, 2 );
    lwText.anisotropy = 16;
    lwMat = new THREE.MeshPhongMaterial({ map: lwText});
    leftwall = new THREE.Mesh(lwGeo, lwMat);
    leftwall.name = "Left Wall";
    leftwall.translateX(-(bWidth / 2));
    building.add(leftwall);

    // right wall
    rwGeo = new THREE.BoxGeometry(0.1, bHeight, bLength);
    rwText = loader.load( 'assets/' + mWallColor + '.jpg' );
    rwText.wrapS = rwText.wrapT = THREE.RepeatWrapping;
    rwText.repeat.set( bLength / 3, 2 );
    rwText.anisotropy = 16;
    rwMat = new THREE.MeshPhongMaterial({ map: rwText});
    rightwall = new THREE.Mesh(rwGeo, rwMat);
    rightwall.name = "Right Wall";
    rightwall.translateX((bWidth / 2));
    
    building.add(rightwall);

Elsewhere in the code here is a left roof:

// left roof
lrGeo = new THREE.BoxGeometry(0.1, (modelSlope + 0.1), bAdjustedRoofLength);
lrGeo.translate(0,-(modelSlope/2),0); //moves rotation point to top edge of geometry
lrText = loader.load( 'assets/' + mRoofColor + '.jpg' );
lrText.wrapS = lrText.wrapT = THREE.RepeatWrapping;
lrText.repeat.set( bLength / 3, 2 );
lrText.anisotropy = 16;
lrMat = new THREE.MeshPhongMaterial({ map: lrText});
leftroof = new THREE.Mesh(lrGeo, lrMat);
leftroof.name = 'Left Roof';
var vertTranslate = Math.sqrt(Math.pow(modelSlope,2) - Math.pow(roofRun,2));
var lftAngle = Math.atan(-((bWidth / 2) / vertTranslate ));
leftroof.translateY((bHeight/2) + vertTranslate);
leftroof.rotateZ(lftAngle);

building.add(leftroof);

Double click code: When is detects the correct wall the camera will auto rotate and zoom to the selected wall. You’ll see this happen in the video when the action is correctly detected. (the Double Click code is unfinished until I fix selection issue by the way).

function onDoubleClick(e) {
e.preventDefault();
raycaster.setFromCamera(mouse, camera);
intersects = raycaster.intersectObjects(building.children);


if (intersects.length > 0) {
    
    var newx, newy, newz;
    var clickedItem = intersects[0].object.name;
    console.log('You clicked: ' + clickedItem);
    // front view
    if(clickedItem == 'Front Wall'){
    newx = 0;
    newy = 0;
    newz = frontwall.position.z + (bWidth * .9);
    }else if(clickedItem == 'Back Wall'){
    // back view
    newx = 0;
    newy = 0;
    newz = -(-backwall.position.z + (bWidth * .9));
    }else if (clickedItem == 'Right Wall') {
    // right side view
    newx = rightwall.position.x + (bLength * .9);
    newy = 0;
    newz = 0;
    }else if (clickedItem == 'Left Wall') {
    // left side view      
    newx = -(-leftwall.position.x + (bLength * .9));
    newy = 0;
    newz = 0;      
    }else {
        return;
    }
    cameraFocus(newx, newy, newz);
    controls.enableRotate = false;
    dragging = true;

}
}

HERE IS THE VIDEO SHOWING PROBLEM IN ACTION: https://youtu.be/mNWNg00wlEQ
Notice the console output while double clicking.

I appreciate any insight or thoughts on what could be causing this issue. How is it getting items that are clearly not being clicked? Thanks in advance!


#4

Thoughts anyone?


#5

Hi!
How do you set mouse variable?


#6

Hi prisoner849,

Thanks for responding!

I make the variables like so:

var raycaster = new THREE.Raycaster();
var mouse = new THREE.Vector2();
var intersects;

canvas.addEventListener("mousemove", onMouseMove, false);
canvas.addEventListener("dblclick", onDoubleClick, false);
canvas.addEventListener("mouseup", onMouseUp, false);

var intersects;
function onMouseMove(e) {   
    mouse.set((e.offsetX / window.innerWidth) * 2 - 1, -(e.offsetY / window.innerHeight) * 2 + 1);    
}

#7

Ehm…
So…
If I understand it correctly: you get the offsetX (or offsetY) of your renderer.domElement (canvas, if I’m not wrong) and then divide it with the width of the whole window, whereas you have to divide it with the width (height) of the canvas.


#8

prisoner849
Thanks a ton for taking time to look at the code. I knew it had to be something simple. It appears to be working now. Here’s what I changed:

mouse.set((e.offsetX / canvas.clientWidth) * 2 - 1, -(e.offsetY / canvas.clientHeight) * 2 + 1); 

Thanks again!


#9

You’re welcome :beers: :+1: