I am new to Three.js. I have loaded a collada (.dae) file having multiple objects.
Now I want to translate each object on its z axis while on mouse over and restore its position when mouse left that object.
I am using "Raycaster" for this purpose.
document.addEventListener( 'mousemove', onDocumentMouseMove, false );
raycaster = new THREE.Raycaster(camera.position, vector.sub( camera.position ).normalize());
mouse = new THREE.Vector2();
and the function is
function onDocumentMouseMove ( event ) {
event.preventDefault();
mouse.x = ( event.clientX / renderer.domElement.clientWidth ) * 2 - 1;
mouse.y = - ( event.clientY / renderer.domElement.clientHeight ) * 2 + 1;
raycaster.setFromCamera( mouse, camera );
// console.log(scene);
var intersect = raycaster.intersectObjects( scene.children[2].children);
// console.log(intersect);
if ( intersect.length > 0 )
{
}
else
{
}
}
I have the object where my mouse is intersecting but I'm not sure how to translate the object and restore it on mouse out so it looks smooth.
Edited
You need to move your intersect check out of your onDocumentMouseMove and check on your loop. onDocumentMouseMove will be called only when your moves moves, but the check will be called every frame.
Your loop should look contain the following:
raycaster.setFromCamera( mouse, camera );
var intersect = raycaster.intersectObjects(scene.children);
if ( intersect.length > 0 ) {
intersect[0].object.translateZ(1);
} else {
// For all of your objects:
cube.position.z = 0;
}
Here's a CodePen.
Related
Trying to rotate camera after mousedown on raycaster with slerp. But after the animation when i turn the control back on, the camera jumps back to its previous rotation. Updating controls seems not to solve this. What i'm missing here?
function mousedown( event ) {
mouse.x = ( event.clientX / windowWidth ) * 2 - 1;
mouse.y = - ( event.clientY / windowHeight ) * 2 + 1;
raycaster.setFromCamera( mouse, camera );
intersects = raycaster.intersectObjects( targets );
if ( intersects.length > 0 ) {
// stop controls
controls.enabled = false;
var targetOrientation = intersects[0].object.quaternion.normalize();
gsap.to({}, 1, {
onUpdate: function() {
controls.update();
//camera.lookAt( intersects[0].object.position );
camera.quaternion.slerp( targetOrientation , this.progress() );
},
onComplete: function() {
controls.update();
//camera.lookAt(new THREE.Vector3( 0, 0, 0 ) );
// restart controls
controls.enabled = true;
}
});
}
}
https://jsfiddle.net/pixeldino/s30pbzj7/152/
FirstPersonControls maintains an internal state of the camera's orientation. By using camera.quaternion.slerp() this state gets out of sync.
You can solve this by using FirstPersonControls.lookAt() at the end of your animation. In this way, the internal state will be updated by forcing the controls to look at the destination point.
https://jsfiddle.net/fnw8643a/
I am new to three.js, I am try to create a click event for a mesh I have created :
const geometry = new THREE.BoxBufferGeometry(size,size*0.5,size);
const material = new THREE.MeshStandardMaterial({color:0x00aa00 });
var option1 = new THREE.Mesh(geometry, material);
option1.position.set( 6, 5, 1)
// option1.callback = objectClickHandler;
// option1.on('click', function(ev) {
// console.log(ev)
// });
console.log(option1)
scene.add(option1)
But this is not working. onclick I will hide and show the object I have imported. But not able to do so as click event is not triggering.Help would be much appreciated.
everything happens in three.js is only in this one DOM that is the canvas.
to detect a click on a mesh, what you do is:
add a click event listener on the canvas.
check if mouse is on the mesh when clicked.
and to check if mouse is on mesh, you use RayCaster.
it should be something like this:
var raycaster = new THREE.Raycaster();
var mouse = new THREE.Vector2();
var targetMesh
function onMouseClick( event ) {
raycaster.setFromCamera( mouse, camera );
var isIntersected = raycaster.intersectObject( targetMesh );
if (isIntersected) {
console.log('Mesh clicked!')
}
}
function onMouseMove( event ) {
mouse.x = ( event.clientX / window.innerWidth ) * 2 - 1;
mouse.y = - ( event.clientY / window.innerHeight ) * 2 + 1;
}
window.addEventListener( 'mouseclick', onMouseClick, false );
window.addEventListener( 'mousemove', onMouseMove, false );
documents: https://threejs.org/docs/#api/en/core/Raycaster
I wish to detect when an object has been clicked. I am generating a page from the three.js editor. It is a brilliant environment.
Following the advice from this post (https://mandemeskel.wordpress.com/2013/08/19/mouse-events-raycasting-with-three-js/) I ended up with the following code. I have placed a comment where I am having a problem.
function mousedown( event ) {
var scene = this.parent;
var projector = new THREE.Projector();
var mouse_vector = new THREE.Vector3(),
mouse = { x: 0, y: 0, z: 1 },
ray = new THREE.Raycaster( new THREE.Vector3(0,0,0), new THREE.Vector3(0,0,0) ),
intersects = [];
mouse.x = ( event.clientX / window.innerWidth ) * 2 - 1;
mouse.y = - ( event.clientY / window.innerHeight ) * 2 + 1;
mouse_vector.set( mouse.x, mouse.y, mouse.z );
// How do I get the camera?
projector.unprojectVector( mouse_vector, camera );
var direction = mouse_vector.sub( camera.position ).normalize();
ray.set( camera.position, direction );
var object = scene.getObjectByProperty( 'uuid', this.uuid, true );
intersects = ray.intersectObject( object );
if( intersects.length ) {
alert( "hit" );
event.preventDefault();
}
}
I have temporarily fixed the problem by modifying app.js in the published page. By moving the camera variable to be global I got around it, but it is obviously a fudge. Is there any way to access the camera generated by the editor without modifying app.js?
var camera;
var APP = {
Player: function () {
....
The awesome mrdoob has modified the editor to include a getCamera() call
https://github.com/mrdoob/three.js/issues/7510#issuecomment-153059247
The default camera can now be accessed by
var camera = player.getCamera();
i am trying to pick objects in a scene where i use an orthographic camera.
my code fragment already works, but it is not precise.
i already found some answers on stackoverflow, but those are deprecated or won't work anymore at all.
here is my code onMouseDown
function onDocumentMouseUp( event ) {
event.preventDefault();
mouse.x = ( event.clientX / window.innerWidth ) * 2 - 1;
mouse.y = - ( event.clientY / window.innerHeight ) * 2 + 1;
var vector = new THREE.Vector3(mouse.x, mouse.y, 0.5);
var pos = camera.position;
var ray = new THREE.Raycaster(pos, vector.unproject(camera).sub(camera.position).normalize());
var intersects = ray.intersectObjects(objects);
if (intersects.length > 0) {
console.log("touched:" + intersects[0]);
}
else {
console.log("not touched");
}
}
please see http://jsfiddle.net/ujzpe07t/1/
if you click some pixels away left/right/above/below the cube, it still tells me that the object was touched.
i am using three.js r69.
any hints would be very much appreciated.
thanks, cheers!
Here is the pattern to use when raycasting (picking) with either an orthographic camera or a perspective camera:
var raycaster = new THREE.Raycaster(); // create once
var mouse = new THREE.Vector2(); // create once
...
mouse.x = ( event.clientX / renderer.domElement.clientWidth ) * 2 - 1;
mouse.y = - ( event.clientY / renderer.domElement.clientHeight ) * 2 + 1;
raycaster.setFromCamera( mouse, camera );
var intersects = raycaster.intersectObjects( objects, recursiveFlag );
three.js r.84
Is it possible to have a object highlighted while using fly controls? Like this but the boxes highlighting when you click them. What I ultimately want it to do is to click on a object and then it go onto a website. But for the moment I have tried to just highlight a object when it its clicked using:
function onDocumentMouseDown( event ) {
event.preventDefault();
var vector = new THREE.Vector3( ( event.clientX / window.innerWidth ) * 2 - 1, - ( event.clientY / window.innerHeight ) * 2 + 1, 0.5 );
projector.unprojectVector( vector, camera );
var raycaster = new THREE.Raycaster( camera.position, vector.sub( camera.position ).normalize() );
var intersects = raycaster.intersectObjects( mesh );
if ( intersects.length > 0 ) {
intersects[ 0 ].object.material.color.setHex( Math.random() * 0xffffff );
}
/*
// Parse all the faces
for ( var i in intersects ) {
intersects[ i ].face.material[ 0 ].color.setHex( Math.random() * 0xffffff | 0x80000000 );
}
*/
But this does not seem to work when I'm using fly controls is it possible? If not could the object just be highlighted to show some text?
I just tested this with the fly controls, its working fine. Make sure to raycast against an array that contains your meshes or just scene.children in this case.
var raycaster = new THREE.Raycaster();
var mouse = new THREE.Vector2();
function onDocumentMouseDown( event ) {
event.preventDefault();
mouse.x = ( event.clientX / window.innerWidth ) * 2 - 1;
mouse.y = - ( event.clientY / window.innerHeight ) * 2 + 1;
raycaster.setFromCamera( mouse, camera );
// calculate objects intersecting the picking ray
var intersects = raycaster.intersectObjects( scene.children );
if ( intersects.length > 0 ) {
intersects[ 0 ].object.material.color.setHex( Math.random() * 0xffffff );
}
}
container.addEventListener( 'mousedown', onDocumentMouseDown, false );
Three.js r.71
Consider checking out https://github.com/jeromeetienne/threex.domevents to easily add DOM Events like click or mouseover to your meshes.