Rotate camera based on angle - three.js

I would like to rotate an object on a certain angle along Y axis.
Based on this answer How to rotate a Three.js Vector3 around an axis? I suppose to get an updated vector.
My code is :
var vec = new THREE.Vector3( 0,0,0 );
var axis = new THREE.Vector3( 0,1,0 );
var angle = Math.PI / 2;
vec.applyAxisAngle( axis, angle );
I'm using r67 and it returns me 0,0,0. I've tried r69 as well and it is returns me the same. I'm not quiet ready to move to r69. Could you guys tell me please how to do the same thing but using r67. Thanks.

Your are rotating vector (0, 0, 0) which is center and whatever angle you use to rotate center around any axis you will always get (0, 0, 0). Just imagine you are doing simple 2d rotation. After all, rotation around Y axis can be viewed as 2d rotation in X-Z plane.
Try with some other values for vec variable, for example (1, 0, 0) or (0, 0, 1) and you will see results

Related

Dot product function does not yield the angle of rotation

While playing with quaternions, I noticed that I could not find the angle of rotation of a vector using the dot product between this vector, and its original position. In my example, I rotated a vector by 90 degrees around an arbitrary axis, but the dot product yielded a different angle.
// Axis of rotation (unit vector).
Vec3 Axis = Vec3(1, 1, 0) / sqrt(1 + 1 + 0);
// Creates a quaternion that will rotate a point by 90 degrees around the (1, 1, 0) axis.
Quat q(cos(3.14 / 4), Axis * sin(3.14 / 4));
// Creates a point.
Vec3 Point = Vec3(1, 0, 0);
// Rotates the point by q.
Quat Rot = q * Quat(0, Point) * q.GetConjugate();// Rot == (0, 0.5, 0.5, -0.707)
// Getting Rot's coordinates.
Vec3 v = Vec3(Rot.x, Rot.y, Rot.z);
// Angle is equal to 1.047, but it should be 1.57 (3.14/2)...
float Angle = acos(Dot(Point, v));
Note that every vector and quaternion is of length of 1.
I find that really intriguing, because the shortest angle between a vector rotated by 90 degrees and its original position is 90 degrees.
So my question is: why am I not getting 1.57 radians? What I am not understanding here?
Thank you for your attention.
With the dot product, you are measuring the angle between the initial vector, and the rotated vector, which is generally not the same as the magnitude of the applied rotation.
Imagine if your point was on the rotation axis, then the point would not move when the rotation is applied. To test this, set your point to (1, 1, 0)/sqrt(2), and the angle should be zero.
Then set the point to (1,-1,0)/sqrt(2) and you should get your expected pi/2.
Since you are rotation about the origin, only the component of the point perpendicular to the axis of rotation is effected by the rotation.
A good reference:
https://en.wikipedia.org/wiki/Rodrigues%27_rotation_formula

SceneKit. How to rotate SCNNode around its axis

I'm trying to achieve same rotation as in scene editor but with code so object always rotate around selected axis, however if I look at angles(x,y,z) in editor they changes quite randomly
![Local node axis][1]
I've tried to use quaternions, but can't get it working
PS. my bad was using rotation property instead of orientation both SCNVector4, have read doc properly)
Seems you was really close, you had to swap parameters in GLKQuaternionMultiply call. I used solution in https://stackoverflow.com/a/39813058/4124265 to achieve rotation only by Z axis:
let orientation = modelNode.orientation
var glQuaternion = GLKQuaternionMake(orientation.x, orientation.y, orientation.z, orientation.w)
// Rotate around Z axis
let multiplier = GLKQuaternionMakeWithAngleAndAxis(0.5, 0, 0, 1)
glQuaternion = GLKQuaternionMultiply(glQuaternion, multiplier)
modelNode.orientation = SCNQuaternion(x: glQuaternion.x, y: glQuaternion.y, z: glQuaternion.z, w: glQuaternion.w)
To rotate arround Y:
// Rotate around Y axis
let multiplier = GLKQuaternionMakeWithAngleAndAxis(0.5, 0, 1, 0)
glQuaternion = GLKQuaternionMultiply(glQuaternion, multiplier)
By setting the rotation property, the absolute rotation of the object is changed, rather than the relative rotation.
Here's some pseudo code
Compute the quaternion represents the relative rotation. I would use the GLKQuaternionMakeWithAngleAndAxis function to do so.
Apply the rotation to the orientation property:
let initial_object_orientation = rotateNode.orientation;
new_orientation = GLKQuaternionMultiply(rotation_quaternion, initial_object_orientation)
Assign the new orientation
rotatNode.orientation = new_orientation
Hope it helps.

Find relative position of axes of cube after rotation

I am rotating a cube through a series of 90 degree rotations using quaternions and I want to be able to get relative positions of the quaternions after a rotation compared with its original position that I have stored.
IE I'd like to know which axis is now equivalent to the original x axis (and if it is inverted), and so on...
I'm using threejs, but I'm sure that's not necessary for answering.
Use this pattern to determine the direction the x-axis is pointing after applying a series of rotations.
var dir = new THREE.Vector3( 1, 0, 0 );
dir.applyQuaternion( q1 );
dir.applyQuaternion( q2 ); // etc...
To see it visually, you can add axes as a child of your cube mesh. The axes will be rotated automatically.
var axes = new THREE.AxisHelper( 100 );
mesh.add( axes );
three.js r.71

Three.js: change the pivot point of a sprite

I've created a 3D map and I'm labelling points on this map through Sprites. This in itself works fine, except for the positioning of the sprite labels.
Because I'm creating a map the camera can tilt from 0 to 90 degrees, while ideally the label always stays some distance directly above the item it is labelling on the screen. But unfortunately, as sprites are always centred around their origin and that overlaps the item, I have to move the sprite up on the Y world axis and with that the centre location of the sprite changes as the camera is tilted. This looks weird if the item looked at is off centre, and doesn't work too well when the camera is looking straight down.
No jsfiddle handy, but my application at http://leeft.eu/starcitizen/ should give a good impression of what it looks like.
The code of THREE.SpritePlugin suggests to me it should be possible to use "matrixWorld" to shift the sprite some distance up on the screen's Y axis while rendering, but I can't work out how to use that, nor am I entirely sure that's what I need to use in the first place.
Is it possible to shift the sprites up on the screen while rendering, or perhaps change their origin? Or is there maybe some other way I can achieve the same effect?
Three.js r.67
As suggested by WestLangley, I've created a workable solution by changing the sprite position based on the viewing angle though it took me hours to work out the few lines of code needed to get the math working. I've updated my application too, so see that for a live demo.
With the tilt angle phi and the heading angle theta as computed from the camera in OrbitControls.js the following code computes a sprite offset that does exactly what I want it to:
// Given:
// phi = tilt; 0 = top down view, 1.48 = 85 degrees (almost head on)
// theta = heading; 0 = north, < 0 looking east, > 0 looking west
// Compute an "opposite" angle; note the 'YXZ' axis order is important
var euler = new THREE.Euler( phi + Math.PI / 2, theta, 0, 'YXZ' );
// Labels are positioned 5.5 units up the Y axis relative to its parent
var spriteOffset = new THREE.Vector3( 0, -5.5, 0 );
// Rotate the offset vector to be opposite to the camera
spriteOffset.applyMatrix4( new THREE.Matrix4().makeRotationFromEuler( euler ) );
scene.traverse( function ( object ) {
if ( ( object instanceof THREE.Sprite ) && object.userData.isLabel ) {
object.position.copy( spriteOffset );
}
} );
Note for anyone using this code: that the sprite labels are children of the object group they're referring to, and this only sets a local offset from that parent object.
I had a similar problem, but with flat sprites; I put trees on a map and wanted them to rotate in such a way that they'd rotate around their base, rather than their center. To do that, i simply edited the image files of the trees to be twice as tall, with the bottom as just a transparency:
http://imgur.com/ogFxyFw
if you turn the first image into a sprite, it'll rotate around the tree's center when the camera rotates. The second tree will rotate around it's base when the camera rotates.
For your application, if you resize the textbox in such a way that the center of it would be coincide with the star; perhaps by adding a few newlines or editing the height of the sprite
This is very much a hack, but if you will only use sprites in this way, and could tolerate a global change to how sprites were rendered, you could change the following line in the compiled three.js script:
Find (ctrl+F) THREE.SpritePlugin = function, and you'll see:
this.init = function ( renderer ) {
_gl = renderer.context;
_renderer = renderer;
vertices = new Float32Array( [
- 0.5, - 0.5, 0, 0,
0.5, - 0.5, 1, 0,
0.5, 0.5, 1, 1,
- 0.5, 0.5, 0, 1
] );
I changed the definition of the array to the following:
var vertices = new Float32Array( [
- 0.5, - 0.0, 0, 0,
0.5, - 0.0, 1, 0,
0.5, 1.0, 1, 1,
- 0.5, 1.0, 0, 1
] );
And now all my sprites render with the rotation origin at the bottom.
If you use the minified version, search for THREE.SpritePlugin=function and move the cursor right until you find the Float32Array defined, and make the same changes there.
Note: this changes how things render only when using WebGL. For the canvas renderer you'll have to play a function called renderSprite() in the THREE.CanvasRenderer. I suspect playing with these lines will do it:
var dist = 0.5 * Math.sqrt( scaleX * scaleX + scaleY * scaleY ); // allow for rotated sprite
_elemBox.min.set( v1.x - dist, v1.y - dist );
_elemBox.max.set( v1.x + dist, v1.y + dist );
This function will also be a lot more difficult to find in the minified version, since renderSprite() is not an outward facing function, it'll likely be renamed to something obscure and small.
Note 2: I did try making these modifications with "polyfills" (or rather, redefining the SpritePlugin after Three is defined), but it caused major problems with things not being properly defined for some reason. Scoping is also an issue with the "polyfill" method.
Note 3: My version of three.js is r69. So there may be differences above.

Three.js plane facing away from camera aligned with viewport

I'm trying to have a plane face away from the camera with same orientation so it's aligned in the viewport.
I have a plane in front of the camera, perfectly aligned to the cameras viewport, and I want to flip it in front of the camera, along the objects Y axis, regardless of camera orientation.
The following will orient my plane to face at the camera and works for any orientation:
target.rotation.copy(camera.rotation);
The following will then flip the plane along the plane's Y axis:
target.rotation.y += Math.PI;
All good so far? Except when the camera rotation has a funky tilt to it, let's say it's looking up and to the left, tilted slightly to the right, the plane's flip is tilted, but not the same way as the camera, leaving me with a plane tilted either to the left or right...
I've tried several things such as:
target.rotation.z -= camera.rotation.z;
Nothing... Thanks for your help.
So the problem I was running into was when the camera was in negative z coordinates. This causes the flip on the Y axis to get messed up.
So basically you would do something like this:
var target = new THREE.Object3D();
//position
target.position.copy(s.camera.position);
target.position.add(THREE.Utils.cameraLookDir(s.camera).multiplyScalar(300));
//rotation
target.rotation.copy(s.camera.rotation);
target.rotation.y += PI;
target.rotation.z = -s.camera.rotation.z;
if (s.camera.position.z < 0) {
target.rotation.z = s.camera.rotation.z;
}
EDIT:
Add the following to appropriate spots in your program.
camera.rotation.eulerOrder = 'XZY';
target.rotation.eulerOrder = 'XZY';
Seems to solve previously encountered tilt issues! (see below)
RESOLVED:
Flipped planes tilted the wrong way in some instances, for example when in negative z coords and also the y rotation is not equal to 0, example: point in space hovering and looking at 0, 0, 0.
This is the solution I was looking for when I found this page (taken from this answer):
mesh.lookAt( camera.position );
The local z-axis of the mesh should then point toward the camera.

Resources