I have written a function by which i want to stop rotation of three.js object on mouse hover.
function onDocumentMouseUp( event ) {
event.preventDefault();
mouse.x = ( event.clientX / window.innerWidth ) * 2 - 1;
mouse.y = - ( event.clientY / window.innerHeight ) * 2 + 1;
raycaster.setFromCamera( mouse, camera );
var intersects = raycaster.intersectObjects( scene.group );
if ( intersects.length > 0 ) {
if ( INTERSECTED != intersects[ 0 ].object ) {
if (controls.AutoRotate) {
controls.autoRotate = false;
} }
}
}
Don't know why but the function is not working neither it is giving any error in the console.Can anybody tell whats the problem over here or suggest the possible solution to this problem. Its not working maybe because i am embedding DOM elements inside three.js and using css renderer.
controls.AutoRotate does not exist so it will never be equal to true.
Related
So I am looking for a way to rotate around an object in Threejs but without holding the mouse button. I've got an example website here: http://www.dilladimension.com/ which uses Threejs. Been looking through forums and on the Threejs documentation but I can't figure out how to rotate around an object without holding down the mouse.
Any help is greatly appreciated!
If you are trying to get that kind of mouse interaction as shown here, you can :
//Listen to mouse mouve events
function onDocumentMouseMove( event ) {
mouseX = ( event.clientX - windowHalfX );
mouseY = ( event.clientY - windowHalfY );
}
//Update your camera position
function render() {
camera.position.x += ( mouseX - camera.position.x ) * .05;
camera.position.y += ( - mouseY - camera.position.y ) * .05;
camera.lookAt( scene.position );
renderer.render( scene, camera );
}
Hope this helps.
Trying to pick some objects on click, and I'm trying to use the standard code used in every example:
function onMouseDown(evt) {
evt.preventDefault();
canvasAbsoluteHeight = $('canvas').height();
canvasAbsoluteWidth = $('canvas').width();
mouseDown = true;
mouseX = evt.offsetX == undefined ? evt.layerX : evt.offsetX;
mouseY = evt.offsetY == undefined ? evt.layerY : evt.offsetY;
var mouse = new THREE.Vector3();
mouse.x = ( evt.clientX / canvasAbsoluteWidth ) * 2 - 1;
mouse.y = 1 - ( evt.clientY / canvasAbsoluteHeight ) * 2;
mouse.z = 0;
ray = new THREE.Raycaster( mouse, camera );
var intersects = ray.intersectObjects( objects);
console.log('intersects', intersects);
if ( intersects.length > 0 ) {
console.log('intersects', intersects);
}
}
objects is an array of THREE.Object3D which should be able to be picked.
I think it may be something connected with the camera. My camera is a child of THREE.Object3D for easier manipulation, and the parent object is not set at origin.
Other thing is that canvas is not fullscreen, which may have something with mouse position? (it is inside a div with some offset from the edges of the page).
Check this fiddle. There is Picker class that you can use. First of all you have to init this class with camera and domelement
Picker.init(camera,domelement)
and then you have to attach mesh
Picker.attach(mesh)
and after that you have to specify what do you want to do after mosedown/mouseup in Picker methods.
I'm using the transformControls to translate, rotate and scale my objects. I want to be able to click on the different objects in my scene and transform them whenever I want: and it works !
The only problem is that geometries have their clickable zone half moved up:
That is to say that I can't select my object on clicking in the lower zone, but if I click above it will be selected.
And for the collada files it is even worse.
I think it should be somewhere here:
function onDocumentTouchStart(event){
event.preventDefault();
event.clientX = event.touches[0].clientX;
event.clientY = event.touches[0].clientY;
onDocumentMouseDown(event);
}
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);
var intersects = raycaster.intersectObjects(objects);
if(intersects.length > 0){
SELECTED = intersects[ 0 ].object;
scene.add(control);
control.attach(SELECTED);
} else{
scene.remove(control);
}
}
EDIT :
OMG... The problem was some margins which were here...
But now, my beginner problem is that I don't really know how to attach transformControls to my object. With the transformControls, I still have the problem. But when I change the material color on click, it works perfectly. Have the transformControls some kind of margins ? I did this :
if(intersects.length > 0){
SELECTED = intersects[ 0 ].object;
scene.add(control);
control.attach(SELECTED);
} else{
scene.remove(control);
}
The answer was obvious... :
if(intersects.length > 0){
SELECTED = intersects[ 0 ].object;
control.attach(SELECTED);
scene.add(control);
} else{
control.detach(SELECTED);
scene.remove(control);
}
I forget to detach the controls
The answer by sRcBh is basically correct, but the code contains a mistake. The detach method of TransformControls does not take any arguments.
if (intersects.length > 0) {
SELECTED = intersects[ 0 ].object;
control.attach(SELECTED);
scene.add(control);
} else {
control.detach(); // <- THIS IS CORRECT
scene.remove(control);
}
(See https://threejs.org/docs/#examples/en/controls/TransformControls)
Im currently working on an small web-application which is using threejs. I ran into the following issue:
I build a prototype which contains my threejs content and everything works well here (The canvas is in the prototype window.innerWidth and window.innerHeight => so has the same size as my Browser window. Selecting works well but I want to use the canvas on my web page application and picking of 3d surfaces needs to work as well there.
I discovered as soon as I change the margin or top via CSS of the canvas it doesn't work anymore. The web-application is based on a scroll page and the threejs canvas is inside a div container which can only be seen by scrolling through the page.
For picking I use the following logic/code -> this one works well in the "fullscreen prototype" but not in the web application page
self.renderer.domElement.addEventListener( 'click', function(event){
event.preventDefault();
//CONVERT MOUSE POSITION TO CORRECT VECTOR
var vector = new THREE.Vector3( ( event.clientX / window.innerWidth ) * 2 - 1, - ( event.clientY / window.innerHeight ) * 2 + 1, 0.5 );
//TRANSLATES A 2D POINT FROM Normalized Device Coordinates TO RAYCASTER THAT CAN BE USED FOR PICKING
self.projector.unprojectVector( vector, self.camera );
//RAYCASTER IS NEEDED TO DETECT INTERACTION WITH CUBE SURFACE
var raycaster = new THREE.Raycaster( self.camera.position, vector.sub( self.camera.position ).normalize() );
var intersects = raycaster.intersectObjects( self.scene.children );
//CHANGE COLOR BASED ON INTERSECTION WITH ELEMENT
if ( intersects.length > 0 ) {
//SELECTED OBJECT
}
}, false );
I think that the calculation is wrong for the var vector but I just can't figure it out how to do it correctly.
Any help would be appreciated
Thank you
best reards
200% way
var x = event.offsetX == undefined ? event.layerX : event.offsetX;
var y = event.offsetY == undefined ? event.layerY : event.offsetY;
var vector = new THREE.Vector3();
vector.set( ( x / renderer.domElement.width ) * 2 - 1, - ( y / renderer.domElement.height ) * 2 + 1, 0.5 );
projector.unprojectVector( vector, camera );
Or see this example. Look at messages in the console.
<script src="js/controls/EventsControls.js"></script>
EventsControls = new EventsControls( camera, renderer.domElement );
EventsControls.draggable = false;
EventsControls.onclick = function() {
console.log( this.focused.name );
}
var mesh = new THREE.Mesh( geometry, material );
scene.add( mesh );
EventsControls.attach( mesh );
//
function render() {
EventsControls.update();
controls.update();
renderer.render(scene, camera);
}
If you want to use it in your webpage, you probably need to calculate the vector with the width and height from your canvas element instead of the window which is your whole browser window.
I'm trying to use THREE.js and been looking at some examples, Voxel Painter exmaple
I'm trying to get it so that every time you click to create a new cube the roll over mesh will always move on top of the cube just pasted rather than being at the point of intersecting of the current mouse position...
All of the source code can be viewed from the link but I believe what I'm trying to do has something to do with this...
You click the mouse to add a Voxel, when onMouseDown() function is active it will check if current mouse position is intersecting with the plane and if CTRL button has been pressed for either a new cube or delete a cube.
function onDocumentMouseDown( event ) {
event.preventDefault();
var intersects = raycaster.intersectObjects( scene.children );
if ( intersects.length > 0 ) {
intersector = getRealIntersector( intersects );
// delete cube
if ( isCtrlDown ) {
if ( intersector.object != plane ) {
scene.remove( intersector.object );
}
}
// create cube
else {
intersector = getRealIntersector( intersects);
setVoxelPosition( intersector );
var voxel = new THREE.Mesh( cubeGeo, cubeMaterial );
voxel.position.copy( voxelPosition );
voxel.matrixAutoUpdate = false;
voxel.updateMatrix();
scene.add( voxel );
}
}
}
When creating a new cube I believe THREE.js grabs the current point where the mouse intersects intersector = getRealIntersector( intersects); and then sets the new Voxel position with the function setVoxelPosition( intersector ); with the intersect point being passed in.
This is the setVoxelPosition function
function setVoxelPosition( intersector ) {
normalMatrix.getNormalMatrix( intersector.object.matrixWorld );
tmpVec.copy( intersector.face.normal );
tmpVec.applyMatrix3( normalMatrix ).normalize();
voxelPosition.addVectors( intersector.point, tmpVec );
voxelPosition.x = Math.floor( voxelPosition.x / 50 ) * 50 + 25;
voxelPosition.y = Math.floor( voxelPosition.y / 50 ) * 50 + 25;
voxelPosition.z = Math.floor( voxelPosition.z / 50 ) * 50 + 25;
}
and the render loop
function render() {
if ( isShiftDown )
theta += mouse2D.x * 1.5;
raycaster = projector.pickingRay( mouse2D.clone(), camera )
var intersects = raycaster.intersectObjects( scene.children );
if ( intersects.length > 0 ) {
intersector = getRealIntersector( intersects );
if ( intersector ) {
setVoxelPosition( intersector );
rollOverMesh.position = voxelPosition;
}
}
camera.position.x = 1400 * Math.sin( THREE.Math.degToRad( theta ) );
camera.position.z = 1400 * Math.cos( THREE.Math.degToRad( theta ) );
camera.lookAt( scene.position );
renderer.render( scene, camera );
}
I have tried to pass in different values into setVoxelPosition( intersector ) but I can't seem to get it right..
Could someone please point me in the right direction?
Thanks.
There are several ways of doing this. I'm not going to sugar coat this answer because frankly, reverse engineering this code will do you some good. I will say, having worked with this voxel code myself, it's important you understand what's happening when you click the mouse button and create a new voxel box.
You're correct in understanding that, this function is in fact taking the current mouse position and creating the box. When the click is complete and the box has been made, the process starts over so the program again looks to where the mouse is and places the Ghost box. In this case the Ghost box is not on top of the previously made box, so you'd have to move the mouse up manually a few pixels to get it there.
Rather than fool around with the setVoxelPosition function directly, I'd recommend you 'temporarly change the x,y,z position of the ghost in relation to the matrix intersect mouse position of your computer. Upon a successful click, increase the matrixIntersect.x .y .z properties of this matrixIntersects object, increasing these values only a little so you get the 'box-on-top' effect you want directly after a click. Remember to change them back when the users mouse moves off the object otherwise the Ghost box will no longer be directly under the mouse and things can get messy fast if these properties grow after every click.