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

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);

Related

3D model in HTML/CSS; Calculate Euler rotation of triangle

TLDR; Given a set of triangle vertices and a normal vector (all in unit space), how do I calculate X, Y, Z Euler rotation angles of the triangle in world space?
I am attemping to display a 3D model in HTML - with actual HTML tags and CSS transforms. I've already loaded an OBJ file into a Javascript class instance.
The model is triangulated. My first aim is just to display the triangles as planes (HTML elements are rectangular) - I'll be 'cutting out' the triangle shapes with CSS clip-path later on.
I am really struggling to understand and get the triangles of the model rotated correctly.
I thought a rotation matrix could help me out, but my only experience with those is where I already have the rotation vector and I need to convert and send that to WebGL. This time there is no WebGL (or tutorials) to make things easier.
The following excerpt shows the face creation/'rendering' of faces. I'm using the face normal as the rotation but I know this is wrong.
for (const face of _obj.faces) {
const vertices = face.vertices.map(_index => _obj.vertices[_index]);
const center = [
(vertices[0][0] + vertices[1][0] + vertices[2][0]) / 3,
(vertices[0][1] + vertices[1][1] + vertices[2][1]) / 3,
(vertices[0][2] + vertices[1][2] + vertices[2][2]) / 3
];
// Each vertex has a normal but I am just picking the first vertex' normal
// to use as the 'face normal'.
const normals = face.normals.map(_index => _obj.normals[_index]);
const normal = normals[0];
// HTML element creation code goes here; reference is 'element'.
// Set face position (unit space)
element.style.setProperty('--posX', center[0]);
element.style.setProperty('--posY', center[1]);
element.style.setProperty('--posZ', center[2]);
// Set face rotation, converting to degrees also.
const rotation = [
normal[0] * toDeg,
normal[1] * toDeg,
normal[2] * toDeg,
];
element.style.setProperty('--rotX', rotation[0]);
element.style.setProperty('--rotY', rotation[1]);
element.style.setProperty('--rotZ', rotation[2]);
}
The CSS first translates the face on X,Y,Z, then rotates it on X,Y,Z in that order.
I think I need to 'decompose' my triangles' rotation into separate axis rotations - i.e rotate on X, then on Y, then on Z to get the correct rotation as per the model face.
I realise that the normal vector gives me an orientation but not a rotation around itself - I need to calculate that. I think I have to determine a vector along one triangle side and cross it with the normal, but this is something I am not clear on.
I have spent hours looking at similar questions on SO but I'm not smart enough to understand or make them work for me.
Is it possible to describe what steps to take without Latex equations? I'm good with pseudo code but my Math skills are severely lacking.
The full code is here: https://whoshotdk.co.uk/cssfps/ (view HTML source)
The mesh building function is at line 422.
The OBJ file is here: https://whoshotdk.co.uk/cssfps/data/model/test.obj
The Blender file is here: https://whoshotdk.co.uk/cssfps/data/model/test.blend
The mesh is just a single plane at an angle, displayed in my example (wrongly) in pink.
The world is setup so that -X is left, -Y is up, -Z is into the screen.
Thank You!
If you have a plane and want to rotate it to be in the same direction as some normal, you need to figure out the angles between that plane's normal vector and the normal vector you want. The Euler angles between two 3D vectors can be complicated, but in this case the initial plane normal should always be the same, so I'll assume the plane normal starts pointing towards positive X to make the maths simpler.
You also probably want to rotate before you translate, so that everything is easier since you'll be rotating around the origin of the coordinate system.
By taking the general 3D rotation matrix (all three 3D rotation matrices multiplied together, you can find it on the Wikipedia page) and applying it to the vector (1,0,0) you can then get the equations for the three angles a, b, and c needed to rotate that initial vector to the vector (x,y,z). This results in:
x = cos(a)*cos(b)
y = sin(a)*cos(b)
z = -sin(b)
Then rearranging these equations to find a, b and c, which will be the three angles you need (the three values of the rotation array, respectively):
a = atan(y/x)
b = asin(-z)
c = 0
So in your code this would look like:
const rotation = [
Math.atan2(normal[1], normal[0]) * toDeg,
Math.asin(-normal[2]) * toDeg,
0
];
It may be that you need to use a different rotation matrix (if the order of the rotations is not what you expected) or a different starting vector (although you can just use this method and then do an extra 90 degree rotation if each plane actually starts in the positive Y direction, for example).

three.js lookAt() : how to point some local axis which *isn't* the positive Z axis towards another object

I'm creating an app where a person (right now I'm using a cone-shape) is standing on some surface (right now I'm using a cylinder laid lengthwise) and I'd like their feet to orient toward some point (right now it's the center of the cylinder).
(edit: I just realized that my Z axis in this photo is pointing in the wrong direction; it should be pointing towards the camera, but the question remains unchanged.)
Here is a version of the code similar to what I'm trying to accomplish. https://codepen.io/liamcorbett/pen/YMWayJ (Use arrow keys to move the cone)
//...
person = CreatePerson();
person.mesh.up = new THREE.Vector3(0, 0, 1);
//
// ...
//
function updateObj(obj, aboutObj=false){
let mesh = obj.mesh;
if (aboutObj) {
mesh.lookAt(
aboutObj.mesh.position.x,
aboutObj.mesh.position.y,
mesh.position.z)
};
}
//
// ...
//
function animate() {
// ...
updateObj(person);
// ...
}
The code above gives me something similar to what I'm looking for, but the issue is that lookAt() seems to always point the local Positive Z-axis in some direction, and I'd much prefer that it point the local Negative Y-axis instead.
I'd prefer to not change the x,y,z axes of the model itself, as I feel that's going to be a pain to deal with when I'm applying other logic to the person object.
Is there a way to change which axis lookAt() uses? Or am I going to have to roll my own lookAt() function? Thanks ~
Is there a way to change which axis lookAt() uses?
No, the default local forward vector for 3D objects (excluding cameras) is (0, 0, 1). Unlike other engines, three.js does not allow to configure the forward vector, only the up vector. But this is not really helpful in your case.
You can try to transform the geometry in order to achieve a similar effect.
If you don't want to do this for some reasons and you still want to use Object3D.lookAt(), you have to compute a different target vector (so not the cylinder's center).
Even if the forward vector of the lookAt method can't be changed (as #Mugen87 said), you can still adjust the local rotation afterwards by knowing in advance the difference between the forward Z axis used, and the axis you consider your mesh to be "upward" (ex: a person standing up on the Y axis).
Basically, in your case, just add this line after the lookAt method :
mesh.rotateOnAxis( new THREE.Vector3(1,0,0), Math.PI * -0.5 );
And the cone will look up :)

three js Object3D rotation

I'm still new for using three js. When I'm rotating a camera object, there is a rotation property has x,y,z value.
I'm wondering where the x,y,z in Object 3D rotation come from? I know the x,y,z represent the radians of Object Euler angle, but according the link three.js document provide:https://en.wikipedia.org/wiki/Euler_angles the range of α and γ covers 2π radians, and the range of β covers π radians. However, the range of all the x,y,z only covers π radians when i test it.
From initially x=0,y=0,z=0, straight look up, why only x value changed? And if the Object3D is a camera, is that means the center pixel in the camera view represents the x-axis?
Appreciate of your help.
You might work on formulating your question a bit clearer and give code to reproduce your error.
On the question why only the x-vaue changes when you look straight up from (0,0,0) is because x, y and z represents the axis that you rotate around.
The standard in 3js and in 3D-graphics in general is to have x as the horizontal axis, y as the vertical axis and z is the "depth" axis.
Looking straight up you will rotate 90 degrees aound the horiontal x-axis, thus changing the x-value in the rotation.
I can give you the link to
https://threejs.org/docs/#api/math/Euler
Three.js provides two ways of representing 3D rotations: Euler angles and Quaternions, as well as methods for converting between the two. Euler angles are subject to a problem called "gimbal lock," where certain configurations can lose a degree of freedom (preventing the object from being rotated about one axis). For this reason, object rotations are always stored in the object's quaternion.
Previous versions of the library included a useQuaternion property which, when set to false, would cause the object's matrix to be calculated from an Euler angle. This practice is deprecated---instead, you should use the setRotationFromEuler method, which will update the quaternion.
https://threejs.org/docs/manual/introduction/Matrix-transformations.html

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.

version 70 about the TrackballControls.js rotation

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.

Categories

Resources