Rotating on multiple axis with three.js - javascript

I'm experimenting with three.js and the deviceorientation event. I'm rotating a cube with my phone's accelerometer, using the technique used in the THREE.DeviceOrientationState plugin. Basically the coordinates from the deviceorientation event angles are converted to radians and applied to a meshes' rotation coordinates (mesh.rotation.x, etc). Pretty basic.
This technique works fine as long as the phone is not rotated more than 90 degrees, but once it hits 90 degrees the rotation get messed up and the cube basically "flips". Not sure how else to describe it. Also, rotation works perfectly when rotating on only one axis, but as soon as two or more axis are involved and the phone is rotated more than 90 degrees we have problems.
Basically I need to know how to combine more than one rotation angle so that the cube rotates with the phone no matter how much the phone is rotated. The cube should always mimic the rotation of the phone. (I know, it's a bit weird to do that since you can't see the phone screen when it has been rotated so much, but bear with me, I have a plan.)
I thought maybe I was hitting gimbal lock, so tried using quaternions, but I get the same results. To be honest, I'm a little embarrassed to be asking this question. It has been a while since I did any 3D programming, but I feel like I should know how to do this.
Here's some example code. What else do I need to do to combine the rotation angles?
$(window).on('deviceorientation', function(e) {
var x = (!e.originalEvent.beta ? 0 : e.originalEvent.beta) * Math.PI / 180;
var y = (!e.originalEvent.gamma ? 0 : e.originalEvent.gamma) * Math.PI / 180;
var z = (!e.originalEvent.alpha ? 0 : (e.originalEvent.alpha - 180)) * Math.PI / 180;
cube.rotation.x = x;
cube.rotation.y = y;
cube.rotation.z = z;
});
UPDATE: Here is a jsfiddle that illustrates the issue. It has been modified to use the DeviceOrientationControls feature, which is now included in three.js. You'll see that the problem persists. Basically I need the cube to mimic the orientation of the phone exactly, no matter how much I turn the phone.
UPDATE 2: I changed the shape in the above jsfiddle from a cube to a 3d rectangle that is in the shape of a phone. I think it's easier to see what's happening with a rectangle than a cube.

Related

THREE.JS : Rotate everyting (including camera) despite the orbit controller

Here is what I would like to do:
When a condition is verified, I would like to rotate everything on the scene, including the camera.
The user will not remark any difference since the camera still show exactly the same thing, but in fact the objects would be rotated.
Of course the orbit controller should still work...
The question might be silly, but I'm having troubles. Either the camera gets shifted and doesn't show the exact same thing or the orbit controller doesn't work.
How would you do?
Thanks.
EDIT: I should detail more what I tried.
So let's say the only thing I have on my scene is a cube with a number on each face.
Face 1 is pointing toward +X.
Face 2 is pointing toward +Y.
Face 3 is pointing toward +Z.
Face -1 is pointing toward -X.
Face -2 is pointing toward -Y.
Face -3 is pointing toward -Z.
At some point in my code, I want the cube to rotate without the user knowing.
Face 1 should still point toward +X.
Face -1 should still point toward -X.
But :
Face 2 should point toward +Z.
Face -2 should point toward -Z.
Face 3 should point toward -Y.
Face -3 should point toward +Y.
Ok?
But I don't want the user to notice this rotation.
So I wanted to rotate the camera at the exact same time in order to hide the fact that the cube rotated.
What I tried:
when I want to rotate X :
cube.rotateX(direction * Math.PI / 2);
camera.position.set(camera.position.x, direction * (-camera.position.z), direction * camera.position.y);
camera.lookAt(new THREE.Vector3(0, 0, 0));
and when I want to rotate Y :
cube.rotateY(-direction * Math.PI / 2);
camera.position.set((-direction) * camera.position.z, camera.position.y, -direction * (-camera.position.x));
camera.lookAt(new THREE.Vector3(0, 0, 0));
Sadly, although it works for the Y rotation, it does not work for the X rotation, because the camera.up will fuck it up and make it look like there was a rotation around the Y axis.
How should I do ?
Try creating a THREE.Group and add everything in your current scene to it (your cube, camera, lights, etc.). Then rotate the group.
var group = new THREE.Group();
group.add(yourCube);
group.add(yourLight);
group.add(yourCamera);
scene.add(group);
// later...
group.rotateN(90 * Math.PI / 180); // whatever rotation function you choose to use
Anything you add to the group from this point on will use the group's coordinate system. Anything added to the scene will continue to use the standard world coordinate system.
If you rotate the group again, anything inside the group will rotate along with it, but anything in the scene will remain in place.

Rotating a simple cube twice

I have some experience on Blender 3d, but almost none on 3d programing and I've trying to work with three.js now.
My question is: I have a simple cube and I rotated it around y-axis; then I need to rotate it again around y-axis, but as if the axis was rotated too. On Blender I would press RKEY twice.
To rotate first time I used: cube.rotation.y += Math.PI*.5;
How can I do that in Three.js? I've tried some matrix transformations too, but I could get done.
--
#muimota help me with a jfiddle, then I'm completing my explanation below:
Thanks #muimota, this example will help me to explain what I'm trying to do! Here is a changed fiddle with a more clear explanation: the cube was rotated two times (y and z) and then will be rotated infinitely on y axis. What I trying to do is to make it always rotate parallels with one of its faces – just like first rotation was parallels to its top face.
If you rotate a cube 90º every frame it will look the same and you might think it didn't rotate (but it did).
Here is an example:
http://jsfiddle.net/Lbabobdx/
function render() {
//ROTATES 90º every frame looking the same
mesh.rotation.y += Math.PI/2;
renderer.render(scene, camera);
}

(Cube) Rotation with three.js

I'm working on a project in three.js where I have a cube and can rotate it with some buttons (arrows). The rotation works, but after some rotations it doesn't spin in the right direction anymore. Probably because the axes of the cube are shifted? But this confuses me a little bit..
I need the cube to be able to rotate up, down, left and right by some controls. This is basically how it currently works:
When a direction is pressed, say 'right', we update the mesh.rotation.y with tween.js until mesh.rotation.y is rotated in a 90 degree angle.
//SCENE, MESH,.. SETUP
...
function rotateRight(){
var start = {x:cubeMesh.rotation.x, y:cubeMesh.rotation.y, z:cubeMesh.rotation.z};
//RIGHT: y + 90°
var end = {x:cubeMesh.rotation.x, y:cubeMesh.rotation.y + degreeToRadians(90),
z:cubeMesh.rotation.z};
var tween = new TWEEN.Tween(start)
.to(end, 1000)
.easing( TWEEN.Easing.Exponential.InOut )
.onUpdate(function(){
cubeMesh.rotation.x = this.x;
cubeMesh.rotation.y = this.y;
cubeMesh.rotation.z = this.z;
})
.start();
}
function animateScene(){
requestAnimationFrame(animateScene);
TWEEN.update();
renderer.render(scene, camera);
}
What do I need to change to keep this cube rotating in the right directions? Can we fix the axes of the cube so they won't shift? I've read something about world axis vs object axis, is this something I need to change and how can I implement this?
Thanks in advance!
Sorry, cannot comment and this is for sure not the perfect answer but if you have problems with the rotation, maybe your tweening is not quite right?
What strikes my eye is that your function is only doing rotation on 1 axis and still you update all three axes. Maybe you should leave away x and z and only update the correct axis? Maybe this helps with your problem, too because you know what you are actually changing. It is just an idea , though.
Figured it out, thanks to this post:
How to rotate a 3D object on axis three.js?
Turned the object around the world axes.

particle brownian motion with directions

I'm trying to use brownian motion to create a group of random moving particles.
http://jsfiddle.net/J75Em/16/
So far I've got the particles moving randomly but I'm not sure how to set the forward direction to make it look more natural.
I've tried to use the change in x and y axis to calculate rotation using atan, you can see this by uncommenting rotate but this doesn't seem to perform well.
Is this the right approach for this type of movement? thanks;
This is pretty neat!
You are sort of going about it the right way but you should actually use the atan2 function. This removes the need for any 0 checks.
The atan2 function gives you an angle which is anticlockwise from the positive x vector
(1, 0) --->
The bees are 90 degrees off from this starting angle so you must subtract 90 degrees from the direction. (depending on which way round you do the dy and dx calculation, you might need to add)
You could find that the direction changes rapidly, so you could consider limiting the next change to a set of changes that cause an angle change below some threshold. This will make the movement a little smoother.
I would actually go about it by generating an angle between say -pi/8 and pi/8 radians, and a random length. Essentially using polar coordinates. Then add this new random polar offset to the x and y position like
newX = currentX + (randomLength * cos(randomAngle + currentAngle)) and
newY = currentY + (randomLength * sin(randomAngle + currentAngle))
If you work with angles you can also get more natural effects like if you want the bees to stay within a certain area, you can force a bias towards the center of the area as they get closer and closer to the edge.
Update:
So I've taken a closer look. The trouble is that you expect .rotate to set the rotation when it actually adds to the rotation
There are 2 options for fixing this.
Rotate by the difference between the previous and the current angle
Set the rotation using the .transform method
You can see solution 2 in action here http://jsfiddle.net/c5A2A/

Rotating in IE8: translation not working properly

I have a need to rotate an image in a web application. In an earlier post it was explained to me that on rotation I need to 'translate' the image because the center point changes.
I'm using the HeyGrady 2D transfrom JQuery plugin for rotating and provide it the translation as was suggested, which works fine on FF/Chrome/Safari/IE9. However, on IE8 this does not work well.
Please have a look at the following link.
If you run this on FF/Chrome/Safari/IE9 the image rotates just fine (stays within the black border). However, if you run this on IE8 it will cross the black border boundary when rotating to 90 or 270 degrees.
The plugin project page mentions that "IE also lacks support for transform-origin and translate() [...] The jQuery Transform plug-in handles these calculations automatically". However, it does not seem to do so.
Anyone has any ideas what the problem may be?
Thanks!
I also ran into this same issue in IE 8 using HeyGrady's jQuery transform plugin. Here's a fix by adding this to the execMatrix function, around line 290:
Replace this line:
this.fixPosition(matrix, tx, ty);
With this:
// factor in the object's current rotation so translation remains straight up/down/left/right
// otherwise, object will be translated along the rotated axis, which produces undesirable effects
var rotation = parseInt(this.$elem.css('rotate')) * -1, // the current rotation in degrees, inverted
radians = rotation * (Math.PI / 180), // convert degrees to radians
newX = (tx * (Math.cos(radians))) - (ty * (Math.sin(radians))), // calculate new x
newY = (tx * (Math.sin(radians))) + (ty * (Math.cos(radians))); // calculate new y
this.fixPosition(matrix, newX, newY);

Categories

Resources