I'm actually working on a website using three.js. You can see a demo here: https://c9.io/frescogusto/demi/workspace/demi_0.3.html
It's on canvas to be viewable on ios and android.
Question is: how do I move the camera from its position to the position of the object that has been clicked? Do I have to use translate method on every axis or there is a faster way?
thanks in advance
pp
renderer.domElement.addEventListener('mousedown', function(event) {
event.preventDefault();
var vector = new THREE.Vector3(
renderer.devicePixelRatio * (event.pageX - this.offsetLeft) / this.width * 2 - 1,
- renderer.devicePixelRatio * (event.pageY - this.offsetTop) / this.height * 2 + 1,
0.5
);
projector.unprojectVector(vector, camera);
var raycaster = new THREE.Raycaster(
camera.position,
vector.sub( camera.position ).normalize()
);
var intersects = raycaster.intersectObjects(YOUR_CLICKABLE_OBJECTS);
if (intersects.length) {
camera.position = intersects[0].point;
// Alternatively, camera.position = intersects[0].object.position.clone();
}
}, false);
This code:
Registers a listener on the mousedown event
Projects the clicked location in 2D screen space into a location in 3D scene space
Casts an imaginary line (a ray) from the camera towards the click
Checks whether any objects intersect with that line; the first object to intersect is the one that was clicked
Snaps the camera to the clicked position
If you'd rather transition the camera slowly to the clicked location instead of snapping it there immediately, you may want to look into a tweening library like TweenJS to help you with the timing of the transition.
(P.S.: I think renderer.devicePixelRatio is only present for the WebGL renderer. You can just remove it for other renderers.)
Related
I'm making a """First Person Controller""" demo, where basically the camera moves forward in the scene when TOUCH event stay pressed, I use setInterval and addScaledVector for the camera movement.
I decided to add Orbit Controls just for rotating the camera to look around, no Zoom. Everything works quite good, but the Orbit Controls make a weird rotation to the target, in the target I use camera.position.x + 1, because if I just put camera.position.x with no value simply doesn't work, also I applied to the camera quaternion.
var vector = new THREE.Vector3();
var speed = 8;
var timer;
var iterations = 0;
controls = new THREE.OrbitControls(camera, renderer.domElement);
controls.rotateSpeed = 1.0;
controls.panSpeed = 0.8;
controls.target.set(camera.position.x + 1, camera.position.y,
camera.position.z);
function process_touchstart(evt) {
evt.preventDefault();
evt.stopImmediatePropagation();
iterations = 0;
timer=setInterval(function(){
iterations++;
vector.applyQuaternion( camera.quaternion );
camera.getWorldDirection( vector );
camera.position.addScaledVector( vector, speed );
controls.target.set(camera.position.x + 1,
camera.position.y,
camera.position.z);
}, 70);
}
Any information is appreciated, I'm kind of new on three.js so any detail is cool
Thank you !
Have you considered using PointerLockControls instead? It is just the same as OrbitControls but specially adapted to what you want. From the docs: The implementation of this class is based on the Pointer Lock API. PointerLockControls is a perfect choice for first person 3D games.
Here is a sample Codepen that does what you want: https://codepen.io/adelriosantiago/pen/OJbWBep?editors=1010
I am making this program where you can click on an object, zoom to it, then look at it from all angles by holding the right mouse button and dragging. I need the camera to be going around the object, not rotate the object with the camera looking at it. I honestly just have no idea how to math it out!
For testing there is already a game object with an xyz we have selected and are looking at
var g = new GameObject(500, 0, 0);//The game object with xyz
this.selected = g;//set selected to g
//Create and set the camera
this.camera = new THREE.PerspectiveCamera(45, w/h, 1, 10000);
this.camera.position.x = 0;
this.camera.position.y = 0;
this.camera.position.z = 0;
//set camera to look at the object which is 500 away in the x direction
this.camera.lookAt(new THREE.Vector3(this.selected.x, this.selected.y, this.selected.z));
So the radius between the camera and the object is 500 and while selected and rotating, the camera should always be 500 away.
I update the scene here:
Main.prototype.update = function(){
this.renderer.render(this.scene, this.camera);//scene is just some ambient lighting
//what to do when mouse right is held down
if(this.rightMouseDown){
//placeholder functionality, needs to rotate around object based on mouse movements
this.camera.position.x -= 5;
}
}
How do I rotate this camera around g with a radius of 500?!?!
As gaitat mentioned, trackball controls are the best place to start with many configurable parameters to make camera rotation/revolution easy. One enormous potential benefit of this method ( especially for your project ) is avoiding "gimbal lock" which is the source of much frustration when working with rotations. Here's a link that might help you with Trackball controls and Orbitcontrols:
Rotate camera in Three.js with mouse
Another option would be setting camera coordinates yourself in the animation loop which is actually quite simple:
var angle = 0;
var radius = 500;
function animate() {
...
// Use Math.cos and Math.sin to set camera X and Z values based on angle.
camera.position.x = radius * Math.cos( angle );
camera.position.z = radius * Math.sin( angle );
angle += 0.01;
...
}
Another option would be to connect the camera to a pivot object and just rotate the pivot:
var camera_pivot = new THREE.Object3D()
var Y_AXIS = new THREE.Vector3( 0, 1, 0 );
scene.add( camera_pivot );
camera_pivot.add( camera );
camera.position.set( 500, 0, 0 );
camera.lookAt( camera_pivot.position );
...
camera_pivot.rotateOnAxis( Y_AXIS, 0.01 ); // radians
If you pursue this option, be aware that the camera object is in "camera pivot space", and might be more challenging to manipulate further.
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've seen a lot of posts people want to have the camera position to screen position. My question is how to do the contrary.
What I currently want to achieve is set the "door" position to a % of the screen, this calculation is ready, and I do have the final screen X, Y (px) position. The current Z offset = 250 of the camera.
I've found this code to convert camera position to screen position:
var vector = projector.projectVector(door.position.clone(), camera);
vector.x = (vector.x + 1) / 2 * window.innerWidth;
vector.y = -(vector.y - 1) / 2 * window.innerHeight;
To do the reversie I tried this, but does not give the result I expect:
var mouseX = ((perc.x) / window.innerWidth) * 2 - 1,
mouseY = -((perc.y) / window.innerHeight) * 2 + 1;
var vector = new THREE.Vector3(mouseX, mouseY, 1);
projector.unprojectVector(vector, camera);
return vector.sub(camera.position).normalize()
I have tried several ways and tried to Google, but didn't found an answer.
Q: How to convert screen position to camera position?
Well, as posted by Gero3, what you want to do is to create a plane that will cover all of your visible camera area (something like new THREE.PlaneGeometry(5000,5000); and then use raycaster to locate screen coordinated on that plane.
Here is an example from another similar question:
http://jsfiddle.net/PwWbT/
Hope that helps.
Use a large invisble plane that defines in which direction the door can expand and then use a raycaster on the plane to search for the position to where the door object should extend.
Is it possible to use Projector and Ray with OrthographicCamera?
I searched for it but I didn't find any example or documents.
Also my Camera isn't set in center of screen.
camera = new THREE.OrthographicCamera(0, width, 0, height, orthonear, orthofar);
That mean top left will be (0 ,0).
So I don't think below code works correctly.
mouse.x = ( event.clientX / width ) * 2 - 1;
mouse.y = -( event.clientY / height) * 2 + 1;
So how can I use Projector and Ray with OrthographicCamera or any other methods to interact with objects?
Original example:
http://mrdoob.github.com/three.js/examples/webgl_interactive_voxelpainter.html
Use the DAT.GUI controls on the right to change the camera to Orthographic...
A little snippet from the code:
ray = projector.pickingRay( mouse2D.clone(), camera );
var intersects = ray.intersectObjects( scene.children );