I would like to create a dashboard on which a certain number of "THREE.Meshes" appear. When I click on one of them with the mouse, I want to call a function that recognizes what I clicked on.
My problem: I always get the ID:8 back from the "callFromTitleWithId" function. It doesn´t matter which one I selected with the mouseclick.
Maybe someone can help, I could not find the error :(
Here is the complete Example:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>TEST</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<style>
body { margin: 0;
background: black; }
canvas { width: 100%; height: 100% }
</style>
</head>
<body>
<!-- Bibs -->
<script src="../extlib/webthree/build/three.js"></script>
<script>
document.addEventListener('mousedown', onDocumentMouseDown, false);
var arrayTiles = [];
//[SCREEN]
var SCREEN_WIDTH = window.innerWidth - 5;
var SCREEN_HEIGHT = window.innerHeight - 5;
screenOrientationValue=0;
//RayCaster für Objekte
var raycaster2 = new THREE.Raycaster(new THREE.Vector3(0,0,35),new THREE.Vector3(0,0,1));
var mouse2 = new THREE.Vector2();
var renderer = new THREE.WebGLRenderer();
renderer.setSize( SCREEN_WIDTH, SCREEN_HEIGHT );
document.body.appendChild( renderer.domElement );
var sceneWorld = new THREE.Scene();
sceneWorld.add( new THREE.AxesHelper(50) );
createTiles(sceneWorld);
var camera= new THREE.PerspectiveCamera( 75, window.innerWidth/window.innerHeight, 0.1, 1000 );
camera.position.set(0,0,35);
var light2 = new THREE.AmbientLight( 0x20202A, 20, 100 );
light2.position.set( 30, -10, 30 );
sceneWorld.add( light2 );
var animate = function () {
requestAnimationFrame( animate );
renderer.render( sceneWorld, camera);
sceneUpdate();
};
animate();
function sceneUpdate()
{
//Update
}
function callFromTitleWithId(titleId)
{
console.log("ID:"+titleId);
}
function onDocumentMouseDown(event)
{
event.preventDefault();
mouse2.x = (event.clientX / renderer.domElement.clientWidth) * 2 - 1;
mouse2.y = - (event.clientY / renderer.domElement.clientHeight) * 2 + 1;
raycaster2.setFromCamera(mouse2, camera);
var intersects2 = raycaster2.intersectObjects(arrayTiles,true);
if (intersects2.length > 0) {
console.log('Maus: X:'+mouse2.x+' Y:'+mouse2.y);
console.log("intersects:" + intersects2[0].object);
console.log("distance:" + intersects2[0].distance);
console.log("face:" + intersects2[0].face);
console.log("faceIndex:" + intersects2[0].faceIndex);
console.log("faceIndex y:" + intersects2[0].point.y);
console.log("faceIndex x:" + intersects2[0].point.x);
intersects2[0].object.callback();
}
}
function createTiles(sceneWorld)
{
var material = new THREE.MeshBasicMaterial( {color: 0x00ff00} );
var materialSide = new THREE.MeshBasicMaterial( {color: 0xffff00} );
var materialsTiles = [materialSide, // Left side
materialSide, // Right side
materialSide, // Top side ---> THIS IS THE FRONT
materialSide, // Bottom side --> THIS IS THE BACK
material, // Front side
materialSide // Back side
];
var maxTileSizeWidth=11;
var maxTileSizeHeight=8;
var distanceBetween=2;
var distanceBorderLeft=-1;
var countInColumns=2;
var countInRow = 4;
var startCoordinatesX = ((((countInColumns * maxTileSizeWidth)+(countInColumns-6.5)*distanceBetween)/2))*-1;
var startCoordinatesY = 20;
var actualCoordinatesX = startCoordinatesX;
var actualCoordinatesY = startCoordinatesY;
//id for test
var idNumberForTest=0;
let r;
for(r=1; r<=countInRow; r++ )
{
let i;
for(i=1; i<=countInColumns; i++ )
{
var geometry = new THREE.BoxGeometry(maxTileSizeWidth, maxTileSizeHeight, 1 );
var tileX = new THREE.Mesh( geometry, materialsTiles );
tileX.position.set(actualCoordinatesX,actualCoordinatesY,0);
//Change actualCoordinates X
actualCoordinatesX = actualCoordinatesX + maxTileSizeWidth + distanceBetween;
idNumberForTest=idNumberForTest + 1;
tileX.callback = function(){callFromTitleWithId(idNumberForTest+'')};
arrayTiles.push(tileX);
sceneWorld.add( tileX );
}
actualCoordinatesY = actualCoordinatesY - (maxTileSizeHeight+1);
actualCoordinatesX = startCoordinatesX;
}
}
</script>
</body>
</html>
`
The problem is that idNumberForTest
is equal for all objects. The callback functions always refer to the same variable. Instead of using a callback function, you can store the ID for the clicked mesh like so:
tileX.userData.id = idNumberForTest;
In this way, the correct ID is assigned to the respective object. Check out the following live example to see this approach in action.
document.addEventListener('mousedown', onDocumentMouseDown, false);
var arrayTiles = [];
//[SCREEN]
var SCREEN_WIDTH = window.innerWidth - 5;
var SCREEN_HEIGHT = window.innerHeight - 5;
screenOrientationValue=0;
//RayCaster für Objekte
var raycaster2 = new THREE.Raycaster(new THREE.Vector3(0,0,35),new THREE.Vector3(0,0,1));
var mouse2 = new THREE.Vector2();
var renderer = new THREE.WebGLRenderer();
renderer.setSize( SCREEN_WIDTH, SCREEN_HEIGHT );
document.body.appendChild( renderer.domElement );
var sceneWorld = new THREE.Scene();
sceneWorld.add( new THREE.AxesHelper(50) );
createTiles(sceneWorld);
var camera= new THREE.PerspectiveCamera( 75, window.innerWidth/window.innerHeight, 0.1, 1000 );
camera.position.set(0,0,35);
var light2 = new THREE.AmbientLight( 0x20202A, 20, 100 );
light2.position.set( 30, -10, 30 );
sceneWorld.add( light2 );
var animate = function () {
requestAnimationFrame( animate );
renderer.render( sceneWorld, camera);
sceneUpdate();
};
animate();
function sceneUpdate()
{
//Update
}
function callFromTitleWithId(titleId)
{
console.log("ID:"+titleId);
}
function onDocumentMouseDown(event)
{
event.preventDefault();
mouse2.x = (event.clientX / renderer.domElement.clientWidth) * 2 - 1;
mouse2.y = - (event.clientY / renderer.domElement.clientHeight) * 2 + 1;
raycaster2.setFromCamera(mouse2, camera);
console.log( arrayTiles );
var intersects2 = raycaster2.intersectObjects(arrayTiles,true);
if (intersects2.length > 0) {
console.log('Maus: X:'+mouse2.x+' Y:'+mouse2.y);
console.log("intersects:" + intersects2[0].object);
console.log("distance:" + intersects2[0].distance);
console.log("face:" + intersects2[0].face);
console.log("faceIndex:" + intersects2[0].faceIndex);
console.log("faceIndex y:" + intersects2[0].point.y);
console.log("faceIndex x:" + intersects2[0].point.x);
console.log("ID:", intersects2[0].object.userData.id);
}
}
function createTiles(sceneWorld)
{
var material = new THREE.MeshBasicMaterial( {color: 0x00ff00} );
var materialSide = new THREE.MeshBasicMaterial( {color: 0xffff00} );
var materialsTiles = [materialSide, // Left side
materialSide, // Right side
materialSide, // Top side ---> THIS IS THE FRONT
materialSide, // Bottom side --> THIS IS THE BACK
material, // Front side
materialSide // Back side
];
var maxTileSizeWidth=11;
var maxTileSizeHeight=8;
var distanceBetween=2;
var distanceBorderLeft=-1;
var countInColumns=2;
var countInRow = 4;
var startCoordinatesX = ((((countInColumns * maxTileSizeWidth)+(countInColumns-6.5)*distanceBetween)/2))*-1;
var startCoordinatesY = 20;
var actualCoordinatesX = startCoordinatesX;
var actualCoordinatesY = startCoordinatesY;
//id for test
var idNumberForTest=0;
let r;
for(r=1; r<=countInRow; r++ )
{
let i;
for(i=1; i<=countInColumns; i++ )
{
var geometry = new THREE.BoxGeometry(maxTileSizeWidth, maxTileSizeHeight, 1 );
var tileX = new THREE.Mesh( geometry, materialsTiles );
tileX.position.set(actualCoordinatesX,actualCoordinatesY,0);
//Change actualCoordinates X
actualCoordinatesX = actualCoordinatesX + maxTileSizeWidth + distanceBetween;
idNumberForTest=idNumberForTest + 1;
arrayTiles.push(tileX);
tileX.userData.id = idNumberForTest;
sceneWorld.add( tileX );
}
actualCoordinatesY = actualCoordinatesY - (maxTileSizeHeight+1);
actualCoordinatesX = startCoordinatesX;
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/110/three.min.js"></script>