18

Is it possible to do rotations taking axis of the world and not of the object?

I need to do some rotations of an object, but after the first rotation, I can't do other rotations like i want.

If it's not possible to do rotation on the axis of the world, my second option is to reset the axis after the first rotation. Is there some function for this?

I can't use object.eulerOrder because it changes the orientation of my object when I set object.eulerOrder="YZX" after some rotations.

Florian Margaine
  • 58,730
  • 15
  • 91
  • 116
Enzo
  • 4,111
  • 4
  • 21
  • 33

5 Answers5

22

UPDATED: THREE - 0.125.2

DEMO: codesandbox.io

const THREE = require("three");

const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(
  75,
  window.innerWidth / window.innerHeight,
  0.1,
  1000
);
camera.position.z = 5;

const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);

const geometry = new THREE.BoxGeometry(1, 1, 1, 4, 4, 4);
const material = new THREE.MeshBasicMaterial({
  color: 0x628297,
  wireframe: true
});
const cube = new THREE.Mesh(geometry, material);
scene.add(cube);

// select the Z world axis
const myAxis = new THREE.Vector3(0, 0, 1);
// rotate the mesh 45 on this axis
cube.rotateOnWorldAxis(myAxis, THREE.Math.degToRad(45));

function animate() {
  // rotate our object on its Y axis,
  // but notice the cube has been transformed on world axis, so it will be tilted 45deg.
  cube.rotation.y += 0.008;
  requestAnimationFrame(animate);
  renderer.render(scene, camera);
}

animate();
Neil
  • 7,861
  • 4
  • 53
  • 74
  • 1
    getRotationFromMatrix is not recognized as a function, also multiplySelf. Do I need to use a specific three.js version? – Ramy Al Zuhouri Oct 15 '13 at 15:30
  • 11
    `getRotationFromMatrix(object.matrix, object.scale)` -> `setFromRotationMatrix(object.matrix)` and `multiplySelf` -> `multiply`. r71 – Poul Kruijt Jul 23 '15 at 13:39
  • 3
    Note: Use `THREE.Math.degToRad(30)` to convert degrees to radians. A bit more readable than `30 * Math.PI/180`. – XåpplI'-I0llwlg'I - Oct 09 '17 at 04:02
  • fiddle does not work anymore - hints from comments also don't make things work – Wolfgang Fahl Aug 10 '19 at 14:07
  • 1
    @WolfgangFahl - updated to r107, looks way easier to do these days, hope this helps you! – Neil Aug 18 '19 at 12:17
  • @Neil - thx this is very helpful for https://stackoverflow.com/questions/57311356/rotating-an-object-properly-around-a-pivot-point-given-axis-and-angle/57312831#57312831 see https://codesandbox.io/s/threejs-bare-example-rcy1b for an intermedidate state – Wolfgang Fahl Aug 18 '19 at 19:41
2

Here's a small variation. Tested with r56.

THREE.Object3D._matrixAux = new THREE.Matrix4(); // global auxiliar variable
// Warnings: 1) axis is assumed to be normalized. 
//  2) matrix must be updated. If not, call object.updateMatrix() first  
//  3) this assumes we are not using quaternions
THREE.Object3D.prototype.rotateAroundWorldAxis = function(axis, radians) { 
    THREE.Object3D._matrixAux.makeRotationAxis(axis, radians);
    this.matrix.multiplyMatrices(THREE.Object3D._matrixAux,this.matrix); // r56
    THREE.Object3D._matrixAux.extractRotation(this.matrix);
    this.rotation.setEulerFromRotationMatrix(THREE.Object3D._matrixAux, this.eulerOrder ); 
    this.position.getPositionFromMatrix( this.matrix );
}
THREE.Object3D.prototype.rotateAroundWorldAxisX = function(radians) { 
    this._vector.set(1,0,0);
    this.rotateAroundWorldAxis(this._vector,radians);
}
THREE.Object3D.prototype.rotateAroundWorldAxisY = function(radians) { 
    this._vector.set(0,1,0);
    this.rotateAroundWorldAxis(this._vector,radians);
}
THREE.Object3D.prototype. rotateAroundWorldAxisZ = function(degrees){ 
    this._vector.set(0,0,1);
    this.rotateAroundWorldAxis(this._vector,degrees);
}

The three last lines are just to resync the params (position,rotation) from the matrix... I wonder if there is a more efficient way to do that...

leonbloy
  • 73,180
  • 20
  • 142
  • 190
2

Somewhere around r59 this gets a lot easier (rotate around x):

bb.GraphicsEngine.prototype.calcRotation = function ( obj, rotationX)
{
    var euler = new THREE.Euler( rotationX, 0, 0, 'XYZ' );
    obj.position.applyEuler(euler);
}
acarlon
  • 16,764
  • 7
  • 75
  • 94
2

Updated answer from @Neil (tested on r98)

function rotateAroundWorldAxis(obj, axis, radians) {
   let rotWorldMatrix = new THREE.Matrix4();
   rotWorldMatrix.makeRotationAxis(axis.normalize(), radians);
   rotWorldMatrix.multiply(obj.matrix);
   obj.matrix = rotWorldMatrix;
   obj.setRotationFromMatrix(obj.matrix);
}
Christoph
  • 1,310
  • 16
  • 28
Most Wanted
  • 6,254
  • 5
  • 53
  • 70
0

@acarlon Your answer might just have ended a week of frustration. I've refined your function a bit. Here are my variations. I hope this saves someone else the 20+ hours I spent trying to figure this out.

function calcRotationAroundAxis( obj3D, axis, angle ){

    var euler;

    if ( axis === "x" ){
        euler = new THREE.Euler( angle, 0, 0, 'XYZ' );      
    }

    if ( axis === "y" ){
        euler = new THREE.Euler( 0, angle, 0, 'XYZ' );              
    }

    if ( axis === "z" ){
        euler = new THREE.Euler( 0, 0, angle, 'XYZ' );      
    }
    obj3D.position.applyEuler( euler );
}

function calcRotationIn3D( obj3D, angles, order = 'XYZ' ){

   var euler;

   euler = new THREE.Euler( angles.x, angles.y, angles.z, order );

   obj3D.position.applyEuler( euler );

}

This works beautifully in r91. Hope it helps.

Emma Scott Lavin
  • 185
  • 1
  • 14