I have been digging into the documentation, tutorials, stackoverflow questions literally all day and cannot find the solution to this problem. Please please take pity on me and help me!
I have a watering can that I put an event listener on, but on mousedown, objects near and to the left get selected ie. the tree trunk or a leaf (code not included) and then I am able to drag and drop that object around until I put it down and it is out of range of the watering can. If I drop it near the watering can, it will get selected again when I click. This is NOT the intended behavior, I want the actual watering can I clicked to be selected and then proceed to get dragged and dropped etc. There is kind of a lot of code here but I am not sure where the problem lies anymore so I am including almost all of it. It's like the watering can thinks it is elsewhere or the ray thinks it is shooting elsewhere. PLEASE TELL ME IF I CAN CLARIFY ANYTHING OR SEND MORE CODE. I just started learning three.js yesterday so there are definitely things I don't understand but I am pretty clear on what is supposed to be happening here... and this is not it :D
const WateringCan = function() {
this.mesh = new THREE.Object3D();
const mat = new THREE.MeshStandardMaterial({ metalness: 0.8, color: 0xadb2bd });
// Create the can
const geomCan = new THREE.CylinderGeometry(15, 15, 25, 10, 10);
geomCan.applyMatrix( new THREE.Matrix4().makeScale(1.1, 1.0, 0.6));
geomCan.computeBoundingBox();
geomCan.computeFaceNormals();
const can = new THREE.Mesh(geomCan, mat);
can.castShadow = true;
can.receiveShadow = true;
this.mesh.add(can);
// Create the handle
const geomHandle = new THREE.TorusGeometry( 10, 2, 8, 6, Math.PI);
geomHandle.applyMatrix( new THREE.Matrix4().makeScale(0.9, 1.1, 1.0));
const handle = new THREE.Mesh(geomHandle, mat);
handle.rotation.z = 4.5;
handle.position.x = 13.5;
handle.castShadow = true;
handle.receiveShadow = true;
this.mesh.add(handle);
// Create spout
const geomSpout = new THREE.CylinderGeometry(1, 3, 20, 5, 5);
const spout = new THREE.Mesh(geomSpout, mat);
spout.rotation.z = 1;
spout.position.x = -22;
spout.position.y = 10;
spout.position.z = 3;
spout.castShadow = true;
spout.receiveShadow = true;
this.mesh.add(spout);
const domEvents = new THREEx.DomEvents(camera, renderer.domElement);
domEvents.addEventListener(can, 'mousedown', (e) => onWateringCanMouseDown(e));
};
let wateringCan;
function createWateringCan() {
wateringCan = new WateringCan();
wateringCan.name = "wateringCan";
wateringCan.mesh.position.x = 120;
wateringCan.mesh.position.y = -30;
wateringCan.mesh.position.z = -10;
scene.add(wateringCan.mesh);
objects.push(wateringCan.mesh);
}
let plane;
function createPlane() {
plane = new THREE.Mesh(new THREE.PlaneBufferGeometry(WIDTH, HEIGHT, 8, 8), new THREE.MeshBasicMaterial({ color: 0xffffff, alphaTest: 0, visible: false }));
scene.add(plane);
}
let selection;
function onWateringCanMouseDown(e) {
const mouseX = (e.clientX / WIDTH) * 2 - 1;
const mouseY = -(e.clientY / HEIGHT) * 2 + 1;
const mouse3D = new THREE.Vector3(mouseX, mouseY, 0.5);
mouse3D.unproject(camera);
raycaster.set(camera.position, mouse3D.sub(camera.position).normalize());
const intersectedObjects = raycaster.intersectObjects(objects, true);
if (intersectedObjects.length > 0) {
selection = intersectedObjects[0].object;
const intersectPlane = raycaster.intersectObject(plane);
offset.z = selection.position.z;
offset.copy(intersectPlane[0].point).sub(plane.position);
}
}
function onDocumentMouseMove(e) {
const mouseX = (e.clientX / WIDTH) * 2 - 1;
const mouseY = -(e.clientY / HEIGHT) * 2 + 1;
const mouse3D = new THREE.Vector3(mouseX, mouseY, 0.5);
mouse3D.unproject(camera);
raycaster.set(camera.position, mouse3D.sub(camera.position).normalize());
raycaster.setFromCamera( mouse3D.clone(), camera);
if (selection) {
offset.z = selection.position.z;
const intersectPlane = raycaster.intersectObject(plane);
selection.position.copy(intersectPlane[0].point.sub(offset));
} else {
const intersectedObjects = raycaster.intersectObjects(objects);
if (intersectedObjects.length > 0) {
plane.position.copy(intersectedObjects[0].object.position);
plane.lookAt(camera.position);
}
}
}
function onDocumentMouseUp(e) {
selection = null;
}
Things I have already tried: computeBoundingBox() on everything I have applyMatrix on, refactoring mouse3D/raycaster around in slightly different ways, moving the can far away (then nothing gets selected). I also had the event listener set on the document for a while and I did not have this problem, but the watering can pieces did not stick to each other, the individual spout/can/handle would get dragged and dropped. But at least it knew then that I was clicking on them! Also having the ability to drag and drop literally everything on the page was fun but also not the point, like I don't need all the leaves on my tree to move around.
Please please help me if you can!! I have been messing around with this all day and it is killing my soul. :D
Okay, so. I did not find out what the reason behind this strange behavior was so I decided to kind of restructure what I was doing and I am no longer having this problem.
What I did is:
removed the event listener from the watering can and put it back on the document
removed all objects but the watering can from my objects array that gets looked through on raycaster.intersectObjects so now nothing but that can be dragged and dropped
things are mostly fine now