Three js camera with gyroscope ( deviceorientation event) - three.js

I have a camera animation for desktop which goes like this:
in mousemove event I have
mouseX = (event.clientX - windowHalfX) / 100;
mouseY = (event.clientY - windowHalfY) / 100;
and in the render function I have
camera.position.x += (mouseX - camera.position.x) * 0.05;
camera.position.y += (-mouseY - camera.position.y) * 0.05;
I want to achieve the same effect with a mobile gyroscope. I tried this:
in the deviceorientation event
gammaRotation = event.gamma;
betaRotation = event.beta;
and in the renderer function I have mostly the same thing as with the desktop version
camera.position.x += (gammaRotation/100 - camera.position.x) * 0.05;
camera.position.y += (-betaRotation/100 - camera.position.y) * 0.05;
But when the beta is 90 ( thats when the phone is vertical to the ground 90 degrees) my camera jumps to one site to another and then goes back to working correctly. It only "jumps" when beta is 90.
I guess it's a math error, but can't really work it out because I don't know how to enable inspector for Iphone right now...

I think you're misusing the deviceorientation data. The alpha, beta, gamma properties of the event represents device rotations around the z, x, y axes respectively, so you should assign them to the camera's rotation, not its position, like in this demo.
The jump from 90 to -90 is to be expected with rotations in 3D space for the same reason that a 2D rotation of +180 is the same as -180. There are multiple ways to describe the same rotation, so you can't convert rotations into positions reliably.

Related

Threejs - How to change the rotation center of a object?

I'm trying to make a solar system with Three.js. I have maked the earth rotate around the sun, but my problem is I do not know how to make the moon rotate around the earth, because the center the rotation center is always the sun, (I guess that it's for because the sun is in the coordinate 0,0,0).
This is my render function with translation and rotation moves:
function render(){
cameraControls.update();
angle +=0.01;
scene.getObjectByName("sun").rotation.y += 0.005;
scene.getObjectByName("moon").rotation.y += 0.020;
scene.getObjectByName("moon").position.x = 30 * Math.cos(angle);
scene.getObjectByName("moon").position.z = 30 * Math.sin(angle);
scene.getObjectByName("earth").rotation.y += 0.015;
scene.getObjectByName("earth").position.x = 80 * Math.cos(angle);
scene.getObjectByName("earth").position.z = 80 * Math.sin(angle);
scene.getObjectByName("clouds").rotation.y += 0.017;
scene.getObjectByName("clouds").position.x = 80 * Math.cos(angle);
scene.getObjectByName("clouds").position.z = 80 * Math.sin(angle);
renderer.render(scene, camera);
requestAnimationFrame(render);
}
An example of how it looks
I'm a beginner with Three.js. Thanks!
You can do this by using THREE.Group as pivot objects. The general idea looks like this:
var pivot = new THREE.Group();
scene.add( pivot );
pivot.add( mesh );
In your animation loop you always rotate the pivot objects.
Demo: https://jsfiddle.net/f2Lommf5/6202/

Rotate Three.js scene on mouse move

I have a scene redered just fine and need to make it rotate horizontally and/or vertically as the mouse moves over the DOM. I was able to do the horizontal rotation by changind the scene rotation.y property:
const step = 0.005;
let halfWindowWidth = window.innerWidth / 2;
let target = (Math.PI / halfWindowWidth * mouseX / 2) - 0.785398;
if (target < y) {
if (y - (step * 2) > target) {
target = y - (step * 2);
}
} else if (target > y) {
if (y + (step * 2) < target) {
target = y + (step * 2);
}
}
scene.rotation.y = target;
I know that maybe I will need to work on the x and z axis to make it rotate vertically, but I don't know what calculations should I do.
The rotation must take place as the mouse goes further from the center of the DOM, from -90˚ to 90˚ (180˚ in total). The step constant I use to have the rotation be animated and not simply jump when the mouse moves too quick.
Take a look at the following examples
http://threejs.org/examples/#misc_controls_orbit
http://threejs.org/examples/#misc_controls_trackball
there are other examples for different mouse controls, but both of these allow the camera to rotate around a point and zoom in and out with the mouse wheel, the main difference is OrbitControls enforces the camera up direction, and TrackballControls allows the camera to rotate upside-down.
All you have to do is include the controls in your html document
<script src="js/OrbitControls.js"></script>
and include this line in your source
controls = new THREE.OrbitControls( camera, renderer.domElement );

three.js: Limiting camera's rotation

I'm working with three.js, attempting to model a real world camera. As such, I'd like to limit its axis of rotation to 90 degrees along x and y axises.
Is there a simply way to do this? My current code isn't working particularly well (and goes crazy when you attempt to move the camera past the X and Y boundaries simultaneously)
if(xRot != null && xRot != undefined){
camera.rotateX(xRot);
}
if(yRot != null && yRot != undefined){
camera.rotateY(yRot);
}
if(camera.rotation.x < minCameraRotX){
camera.rotation.x = minCameraRotX;
}else if (camera.rotation.x > maxCameraRotX){
camera.rotation.x = maxCameraRotX;
}
if(camera.rotation.y < minCameraRotY){
camera.rotation.y = minCameraRotY;
}else if(camera.rotation.y > maxCameraRotY){
camera.rotation.y = maxCameraRotY;
}
Any advice would be greatly appreciated!!!
I actually managed to find a solution by checking some of the existing code in a Three.js demo for a library called PointerLock. The idea is to actually stack multiple objects inside each other: start with an object that moves horizontally (the yaw object), place another object inside the yaw object that moves vertically (the pitch object), and then place the actual camera inside the pitch object.
Then, you only rotate the outside objects (yaw and pitch) along their respective axises, so if you rotate both, they'll self-correct. For example, if you rotate the yaw 45 degrees along the y-axis (making it turn to the right) and then rotate the pitch 45 degrees (making it turn downward), the pitch will go 45 degrees downward from the yaw's already rotated position.
Given that the camera is inside both, it just points wherever the yaw and pitch direct it.
Here is the code
/*
* CAMERA SETUP
*
* Root object is a Yaw object (which controls horizontal movements)
* Yaw object contains a Pitch object (which controls vertical movement)
* Pitch object contains camera (which allows scene to be viewed)
*
* Entire setup works like an airplane with a
* camera embedded in the propellor...
*
*/
// Yaw Object
var yawObject = new THREE.Object3D();
// Pitch Object
var pitchObject = new THREE.Object3D();
// Camera Object
var camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
// Max Camera angles (in radians)
var minCameraRotX = 0.5;
var maxCameraRotX = 0.5;
var minCameraRotY = 1;
var maxCameraRotY = 1;
// Setup
yawObject.add( pitchObject );
pitchObject.add( camera );
scene.add(yawObject);
...
var rotateCamera = function(xRot, yRot, zRot){
yawObject.rotation.y += yRot;
pitchObject.rotation.x += xRot;
// Enforce X-axis boundaries (rotates around y-axis)
yawObject.rotation.y = Math.max( minCameraRotY, Math.min( maxCameraRotY, yawObject.rotation.y ) );
// Enforce Y-axis boundaries (rotates around x-axis)
pitchObject.rotation.x = Math.max( minCameraRotX, Math.min( maxCameraRotX, pitchObject.rotation.x ) );
}
Here is the source code I referenced: https://github.com/mrdoob/three.js/blob/acda8a7c8f90ce9b71088e903d8dd029e229678e/examples/js/controls/PointerLockControls.js
Also, this is sort of cheesy, but this little plane cartoon helped me visual exactly what was going on in my setup

Rotate a Sprite around another Sprite -libGDX-

video game link
I'm trying to make a game (see link above) , and I need to have the stick rotate around himself to maintain the orientation face to center of the circle.
this is how I declare the Sprite, and how I move it around the circle:
declaration:
line = new Sprite(new Texture(Gdx.files.internal("drawable/blockLine.png")));
line.setSize(140, 20);
lineX = Gdx.graphics.getWidth()/2 - line.getWidth()/2;
lineY = (Gdx.graphics.getHeight()/2 - line.getHeight()/2) + circle.getHeight()/2;
movement:
Point point = rotatePoint(new Point(lineX, lineY), new Point(Gdx.graphics.getWidth()/2, Gdx.graphics.getHeight()/2), angle+= Gdx.graphics.getDeltaTime() * lineSpeed);
line.setPosition(point.x, point.y);
rotatePoint function:
Point rotatePoint(Point point, Point center, double angle){
angle = (angle ) * (Math.PI/180); // Convert to radians
float rotatedX = (int) (Math.cos(angle) * (point.x - center.x) - Math.sin(angle) * (point.y-center.y) + center.x);
float rotatedY = (int) (Math.sin(angle) * (point.x - center.x) + Math.cos(angle) * (point.y - center.y) + center.y);
return new Point(rotatedX,rotatedY);
}
Any sugestions ?
I can't test right now but I think the rotation of the line should simply be:
Math.atan2(rotatedPoint.getOriginX() - middlePoint.getOriginX(), rotatedPoint.getOriginY() - middlePoint.getOriginY()));
Then you'll have to adjust rad to degrees or whatever you'll use. Tell me if it doesn't work!
I would take a different approach, I just created a method that places n Buttons around a click on the screen. I am using something that looks like this:
float rotation; // in degree's
float distance; //Distance from origin (radius of circle).
vector2 originOfRotation; //Center of circle
vector2 originOfSprite; //Origin of rotation sprite we are calculating
Vector2 direction = new vector2(0, 1); //pointing up
//rotate the direction
direction.rotate(rotation);
// add distance based of the direction. Warning: originOfRotation will change because of chaining method.
// use originOfRotation.cpy() if you do not want to init each frame
originOfSprite = originOfRotation.add(direction.scl(distance));
Now you have the position of your sprite. You need to increment rotation by x each frame to have it rotate. If you want the orientation of the sprite to change you can use the direction vector, probably rotated by 180 again. Efficiency wise I'm not sure what the difference would be.

Three JS Camera control mouse + kbd

As the title suggests I want to move a camera in ThreeJS.
Im currently letting the camera move on mousedown making it circle a point at which it looks and I want to let keyboard controls move the camera in x and z, thus moving the point at which it looks as well as the position of the camera. The lookAt target is currently 0,0,0.
Having tried the translateX, and translateZ it would move the cameras position relative to its own tilt and angle. Thus, looking down, "forward" would bring the camera down in world Y-axis where I want to move it in world X and Z only.
Camera is perspective if it matters, and the scrollwheel sets radious of orbiting cirle.
Version is r55.
Here's the current code (mostly copied from examples) that doesnt move camera at all.
if (userMouse.isDown){
theta = - ( ( userMouse.position.x - userMouse.down.position.x ) * userMouse.acceleration ) + userMouse.down.theta;
phi = ( ( userMouse.position.y - userMouse.down.position.y ) * userMouse.acceleration ) + userMouse.down.phi;
phi = Math.min( 160, Math.max( 20, phi ) );
}
camera.position.x = userCam.radious * Math.sin( theta * Math.PI / 360 ) * Math.cos( phi * Math.PI / 360 );
camera.position.y = userCam.radious * Math.sin( phi * Math.PI / 360 );
camera.position.z = userCam.radious * Math.cos( theta * Math.PI / 360 ) * Math.cos( phi * Math.PI / 360 );
camera.lookAt(userCam.target);
camera.updateMatrix();
Ive looked through examples and scoured the Interwebs, but have not found this setup.
My guess is I would use some transformWorldMatrix or use the rotation of the camera to get the direction and then just add a movement value.
Im sure its not terribly tricky, I just cant wrap my head around it.
So; how would I move the camera in world X and Z with regard to where its looking?
Sorry if this is a noob question.

Resources