version 70 about the TrackballControls.js rotation - javascript

My question in github--
https://github.com/mrdoob/three.js/issues/6043#issuecomment-73478885
I know TrackballControls.js be used for controlling a camera, not a model.
But I want rotation model with this TrackballControls.js.When I control the model with mouse,I can pan,zoom,rotate.When I rotate the model, I won't feel in a rotating camera, but seemed to rotate the model itself. I need a mouse event.
method:
controls.target = model.position;
or controls.target.copy( model.position )
they no use;

As seen in the lao3d.com Viewer you want to rotate the object around the worlds Y and X axis independent of its translation.
So I made this little example http://jsfiddle.net/nk3977jb/1/ .
It takes into consideration that the camera might be rotated.
And therefore creates its current Up and Right vector using the quaternion of the camera to get the up and view vector to then calculate the cross product of it.
var view = new THREE.Vector3(0, 0, -1);
view.applyQuaternion(camera.quaternion);
var cross = new THREE.Vector3();
cross.crossVectors(view, camera.up);
You can think of view being -Z going into the Screen, +Y being the cameras up vector pointing upwards from whichever rotation the camera has and cross being the crossproduct of -Z and +Y therefore pointing right.
With these axis setup you can rotate the object around them.

Related

Attaching position to camera but rotating in world axis

Quick abstract: I don't know how to give to an object, attached to the camera, a local rotation so that it is rotated as if it is attached to the scene.
Background: I am the creator of this website which offers to players of the related game the ability to build levels on a 3D Builder, in a web browser. Everything work fine with it but some parts are not well optimized, specially the toolbar (or dashboard), where objects can be selected to be added to the main scene.
Those toolbar objects need to be sticked at the bottom of the screen and always above all layers but their rotation has to be relative to the main axis of the scene. That's where I face some weird behaviors on browsers other than Firefox and Chrome.
If first thought this other thread was saving my life on this matter by implementing the Object3D.onBeforeRender function, but I faced other issues.
Currently those objects are attached to the scene and their position is updated relatively to the camera with the onBeforeRender function of each object. On such way I noticed some flickering results with Edge and iPhone browser, despite everything ends up fine in the rendering. Not nice on the scene rotation...
So I tried something else by attaching each object to the camera and giving them their supposed world rotation. Now when testing on Edge there is no flickering and the results is much better but I can't get how to give them the same rotation than when they are attached to the scene.
Here is a visual:
and an animated gif (you can see a little how the red background and cube at the right part are moving/flickering, but it is awfull if done quicklier):
For the #1 (at the right) there's a good rendering but a bad experience on some browsers and for the #2 (at the left) the rotation, based on the camera, is not good but the experience is fine.
Here are some code abstracts I've implemented:
For #1:
rightCube.relPos = new THREE.Vector3(500, 0, 0); // a new property to be used
rightCube.onBeforeRender = function( renderer, scene, camera, geometry, material, group ) {
camReference.position.copy(this.relPos);
var pos = camReference.getWorldPosition();
this.position.set( pos.x, pos.y, pos.z );
};
scene.add(rightCube);
And camReference is a simple Object3D representing the camera origin
For the #2:
leftCube.onBeforeRender = function( renderer, scene, camera, geometry, material, group ) {
this.rotation.copy(camera.getWorldRotation());
};
camera.add(leftCube);
I admit on this last part, that getting the camera world rotation is not sufficient but that's where I'm stuck and need some help: I don't know how to give to an object, attached to the camera, a local rotation so that it is rotated as if it is attached to the scene.
This post is pretty long but I hope my problem can be well understood... and that someone will give me the key to make it work.
Three.js r82
I've found out how to deal with that problem. I had to go into some calculus and I am surprised that it is not yet implemented in Three.js. If I have missed something #WestLangley please let me know!
Basically my request is to have a rotateToWorld functionnality from the camera coordinate. Getting the rotation of the camera is not enought because of the orbit control position offset which could be different than the Scene Axis. From the camera coordinate, rotating to the World can be seen as a rotation around x then y (Euler rotations), z being directed to the viewer. Here is a figure I tried to draw as a better explanation:
Here is the function I have coded to do that:
var rotateToWorld = function (camera, controls) {
var p = camera.position.clone();
var o = controls.target.clone();
// position relative to the control
p.sub(o);
var Dxyz = Math.sqrt(p.x*p.x + p.y*p.y + p.z*p.z);
var Dxz = Math.sqrt(p.x*p.x + p.z*p.z);
return {
x: Math.acos(Dxz/Dxyz) * (p.y>0?1:-1), // Angle Rotation on x axis camera
y: Math.acos(p.z/Dxz) * (p.x>0?-1:1), // Angle Rotation on y axis camera
z: 0 // No rotation around z axis
};
};
Then from a cube object attached to the camera (not to the scene) it can be rendered like that:
cube.onBeforeRender = function( renderer, scene, camera, geometry, material, group ) {
var R = rotateToWorld(camera, controls); // controls defined elsewhere in the code
this.rotation.set(R.x, R.y, 0);
};
As a result this is what I got with a perspective camera:
And now it works with Microsoft Edge, Safari and other browsers despite when attaching to the scene and updating the position of the object (to keep it in front of the camera) it was only workable with Firefox and Chrome (as for today).
I wonder now if this is a functionnality that could be added to Three.js...
EDIT:
#WestLangley pointed out in comments that the clone() function of Vector3 instantiate a new object each time it is called, so better is to use a closure function to initialize once p and o as Vector3 objects then update them with the copy() function.
So here is a better version:
var rotateToWorld = function() {
var p = new THREE.Vector3();
var o = new THREE.Vector3();
return function rotateToWorld(camera, controls) {
p.copy(camera.position);
o.copy(controls.target);
// position relative to the control
p.sub(o);
var Dxyz = Math.sqrt(p.x*p.x + p.y*p.y + p.z*p.z);
var Dxz = Math.sqrt(p.x*p.x + p.z*p.z);
return {
x: Math.acos(Dxz/Dxyz) * (p.y>0?1:-1), // Angle Rotation on X axis camera
y: Math.acos(p.z/Dxz) * (p.x>0?-1:1), // Angle Rotation on Y axis camera
z: 0 // No rotation around z axis
};
}
}();
Again, thanks #WestLangley! :)

How can I set Z up coordinate system in three.js?

In three.js Y axis represent up and down and Z axis represent forward and backward. But I want Z axis to represent up and down and Y axis to forward and backward. Here is a image showing what I want:
I want to change the entire coordinate system in such a way that, if I rotate a mesh around y axis, it follows the new coordinate system not the traditional one.
Now, I have searched stack overflow and found this link:
Three.JS rotate projection so that the y axis becomes the z-axis .
It doesn't work.
THREEJS: Matrix from Z-Up Coordinate System to Y-Up Coordinate System. This method just change the object or mesh y and z vertices but if I rotate it around y axis it rotates around the traditional y axis. I have to apply the matrix to the rotation matrix also to make it rotate like the new coordinate system.
Changing a matrix from right-handed to left-handed coordinate system
Reorienting axes in three.js fails when webpage is refreshed. This doesn't work also.
Is there any way I can make three.js to work like Z up coordinate system?
You can set the up vector of the camera using
camera.up.set(0,0,1);
Then, it will work like you expect.
The answer above works in simple case, but if you wish for example to use the editor, you better set before doing anything
THREE.Object3D.DefaultUp = new THREE.Vector3(0,0,1);
So any new object will also use this convention.
Using the previous answer, I struggled in the editor on on all the implications around the controls, saving the objects etc...
Please note that if you use a grid you still have to rotate it so that it covers XY plane instead of XZ
var grid = new THREE.GridHelper( 30, 30, 0x444444, 0x888888 );
grid.rotateX(Math.PI / 2);

three.js - Invert camera rotation matrix

I have a scene with objects and a camera controlled by a trackball. When I add a new object to the root object, I want it in the orientation it would have had before the camera moved around. For example, if you don't rotate the camera, a torus will show up with the hole facing the screen, the ring in the x,y screen plane.
I tried to apply the inverse matrix of the camera, but that doesn't work.
var m = THREE.Matrix4()
m.getInverse(camera.matrixWorld)
obj.setRotationFromMatrix(m)
What am I missing ?
The solution was simply to apply the camera rotation:
obj.setRotationFromMatrix(camera.matrixWorld)
The object is then facing the camera.
You need to declare the object as "new" as well reordering some of the wording. Try this:
var m = new THREE.Matrix4();
m.getInverse( camera.matrixWorld );
obj.rotation.setFromRotationMatrix(m);

Rotating Mesh in world axis - THREE.js

I'm having difficulty rotating an object. I am currently using THREE.Shape to configure a custom shape, after creating the shape, I configure it as a Mesh and set the position of it to:
buildingMesh.position.set( -70, -300, levelY );
Now because of the position of the mesh as well as the camera it appears as if its standing up.
Heres what that looks like:
Now I recently added a Orbital camera that rotates around the world axis, once the camera moves, this is how it looks:
Now this makes sense because the y axis was never configured when using the Three.Shape. What I am trying to figure out now is how can I turn that object so it appears to be standing up, as shown in the first image. I have tried using rotation on the x,y,z axis's but it always seems to only rotate within the objects axis.
Any suggestions?
Heres something I tried that I found on another question:
rotateAroundWorldAxis: function(object, axis, radians) {
this.rotWorldMatrix = new THREE.Matrix4();
this.rotWorldMatrix.makeRotationAxis(axis.normalize(), radians);
this.rotWorldMatrix.multiply(object.matrix); // pre-multiply
object.matrix = this.rotWorldMatrix;
object.rotation.setFromRotationMatrix(object.matrix);
}
Try:
mesh.rotate.x = Math.PI // will rotate over x axis 180 degree
where 'mesh' is object you have created (you can rotate 'y' and 'z' too)
So the primary problem here was that the mesh was built by multiple layers. All these layers actually had to be grouped together into an Object3D Which in turn allowed me to simply do: group.rotateOnAxis(axis,Math.pow(Math.PI, 2) / 2);
Hope this helps anyone in the future.

How to get Orientation of Camera in THREE.js

I am creating a 3d game using THREE.JS and the Web Audio API. One of the problems I am having is that I want to use the web audio Listener orientation, and define the listener to be the camera, whose position and direction are constantly being updated
My question, is there anyway to easily get the vector direction of a THREE camera?
I was trying to calculate it by using the old camera position, and using the velocity vectors to calculate which way it is facing, but this won't work when the camera is standing still...
Would it be feasible to create a unit vector by getting using camera.rotation.x, camera.rotation.y, camera.rotation.z ?
or is there an even easier way?
Thanks so much for your time!
You want to know the direction in world space in which the camera is looking.
In camera space, the camera is located at the origin and is looking down it's negative z-axis.
Pick a point in front of the camera in camera space:
var pLocal = new THREE.Vector3( 0, 0, -1 );
Now transform that point into world space:
var pWorld = pLocal.applyMatrix4( camera.matrixWorld );
You can now construct the desired direction vector:
var dir = pWorld.sub( camera.position ).normalize();
EDIT: Updated for three.js r.57
EDIT: Also see: three.js set and read camera look vector
In revision 69 (not sure in what revision it was introduced), you can call
camera.getWorldDirection()
to get the camera orientation vector.
if your camera is a child of the player object .e.g. in FPS game. Do the same calculation on the player (parent of camera) , and use this (the Bullit gets the right direction, in this case from obj)
Bullit.prototype.getDirection=function(obj){
this.position.add(obj.position);
var pLocal = new THREE.Vector3( 0, 0, -1 );
var pWorld = pLocal.applyMatrix4( obj.matrixWorld );
var dir = pWorld.sub( obj.position ).normalize();
this.direction=dir;
}

Categories

Resources