How to move the camera in a forge viewer to face the true north direction, using the euler angles

Viewed 87

I understand that forge viewer uses three.js extensively, I have a couple of questions

  1. I want to point my forge viewer camera to the north direction (true north) and further synchronise the rotation based on the north values.

  2. Also is it possible to set the bounds ? I'm trying to synchronise forge viewer based on a set of euler angles (pitch, yaw and roll) available at my hand

I'm using the forge viewer version 7.

1 Answers

Fareed also asked this via email, so I'm copying & pasting my replies here.

Not sure which source model format you used, so suppose it's Revit (RVT).

In Revit model metadata, two attributes can help calculate the north rotation to the true north.

  • metadata['world north vector']['XYZ']: The project north vector of the Revit view.
  • metadata['custom values']['angleToTrueNorth']: The angel from the project north to true north of Revit view.
// Calculate project north angle
const projectNorthVector = new THREE.Vector3().fromArray( model.getData().metadata['world north vector']['XYZ'] );
const autoCam = viewer.autocam;
const frontDirection = autoCam.sceneFrontDirection.clone(); //!<<< viewer world north
const upVector = autoCam.sceneUpDirection.clone();
let crossVector = new THREE.Vector3();
crossVector.crossVectors( frontDirection, projectNorthVector );
const projectNorthAngle = projectNorthVector.angleTo( frontDirection ) * ( crossVector.dot( upVector ) < 0 ? -1 : 1 );

// Calculate true north angle
let trueNorthAngle = metadata['custom values']['angleToTrueNorth'] * (Math.PI / 180);


// Final rotation angle from viewer world north to true north
const finalRotationAngle  = projectNorthAngle + trueNorthAngle;

// and then rotate your vector by Z.

Sorry, I'm not familiar with the Euler angles (pitch, yaw, and roll), but from three.js documentation, I can see it uses intrinsic Tait-Bryan angles.

Three.js uses intrinsic Tait-Bryan angles. This means that rotations are performed with respect to the local coordinate system. That is, for order 'XYZ', the rotation is first around the local-X axis (which is the same as the world-X axis), then around local-Y (which may now be different from the world Y-axis), then local-Z (which may be different from the world Z-axis).

So, probably, you can try to get that with the either way below:

  • Use three.js API to get Euler Tait-Bryan angles from quaternion
const quaternion = viewer.getCamera().quaternion.clone();
const rotation = new THREE.Euler().setFromQuaternion( quaternion, 'XYZ' );
  • Or get it from the camera's rotation
const { rotation } = viewer.getCamera();
const eulerOrder = rotation.order;
viewer.navigation.setCameraUpVector( new THREE.Vector3(0,1,0), true );
const quaternion = viewer.getCamera().quaternion.clone();

let { x, y, z, w } = quaternion;
let roll  = Math.atan2(2*y*w - 2*x*z, 1 - 2*y*y - 2*z*z);
let pitch = Math.atan2(2*x*w - 2*y*z, 1 - 2*x*x - 2*z*z);
let yaw   = Math.asin(2*x*y + 2*z*w);

To set Euler angles to camera, here is an approach, but I think you will need to change the Euler order if it's not XYZ.

const euler = new THREE.Euler(..., ..., ..., 'XYZ');
viewer.getCamera().quaternion..setFromEuler(euler);
Related