Quaternion - method .setFromBasis( e1, e2, e3 )

These posts and examples are about movement on a curve.

Struggling with paths - #14 by hofk
Car Racing - For lovers of fast cars!

MotionAlongCurve
MovementOnCurve
CarRacing

However, the solution via matrices requires computational effort. I have been looking for a solution with quaternions that requires fewer formula steps.

The solution is a new method in the quaternion class.
I added it to three.module.129.Quaternion.js in the example BasisToQuaternion.

This makes the calculation of the correct orientation quite simple.

// t tangent, n normal, b binormal
t = curve.getTangent( f );
b.crossVectors( t, n ).normalize( );
n.crossVectors( t, b.negate( ).normalize( ) );

p = curve.getPoint( f );

// added method .quaternion.setFromBasis( ) from ../jsm/three.module.129.Quaternion.js;

dice.quaternion.setFromBasis( t, b, n );
dice.position.set( p.x, p.y - 0.1, p.z );	
 
box.quaternion.setFromBasis( t, b, n );	
box.position.set( p.x, p.y, p.z );

modelBee.quaternion.setFromBasis(  t.negate( ), n, b ); // another orientation
modelBee.position.set( p.x, p.y, p.z );


class Quaternion { 

...

	setFromBasis( e1, e2, e3 ) {
		
		const	m11 = e1.x, m12 = e1.y, m13 = e1.z,
				m21 = e2.x, m22 = e2.y, m23 = e2.z,
				m31 = e3.x, m32 = e3.y, m33 = e3.z,
				trace = m11 + m22 + m33;
	
		if ( trace > 0 ) {
	
			const s = 0.5 / Math.sqrt( trace + 1.0 );
	
			this._w = 0.25 / s;
			this._x = -( m32 - m23 ) * s;
			this._y = -( m13 - m31 ) * s;
			this._z = -( m21 - m12 ) * s;
	
		} else if ( m11 > m22 && m11 > m33 ) {
	
			const s = 2.0 * Math.sqrt( 1.0 + m11 - m22 - m33 );
	
			this._w = ( m32 - m23 ) / s;
			this._x = -0.25 * s;
			this._y = -( m12 + m21 ) / s;
			this._z = -( m13 + m31 ) / s;
	
		} else if ( m22 > m33 ) {
	
			const s = 2.0 * Math.sqrt( 1.0 + m22 - m11 - m33 );
	
			this._w = ( m13 - m31 ) / s;
			this._x = -( m12 + m21 ) / s;
			this._y = -0.25 * s;
			this._z = -( m23 + m32 ) / s;
	
		} else {
	
			const s = 2.0 * Math.sqrt( 1.0 + m33 - m11 - m22 );
	
			this._w = ( m21 - m12 ) / s;
			this._x = -( m13 + m31 ) / s;
			this._y = -( m23 + m32 ) / s;
			this._z = -0.25 * s;
	
		}
		
		this._onChangeCallback();

		return this;

	}
...

}

UPDATE: typo Fom => From


If someone doesn’t want to change the original three.js, they can also integrate the method into their code using .prototype .

THREE.Quaternion.prototype.setFromBasis = function( e1, e2, e3 ) { ... }

See Car Racing - For lovers of fast cars!


:question:
On request ( Math experts: is there anything you wish Three.js math library had?) some hints:

In the docu we have some methods that set the quaternion as a representation of the rotation of different arguments.

.setFromAxisAngle
.setFromEuler
.setFromRotationMatrix
.setFromUnitVectors
.fromBufferAttribute

For the basis: Basis (linear algebra) - Wikipedia

The vectors of length 1 on the x, y z axis form the basis of the three-dimensional vector space.

If you want to rotate an object, you have the above-mentioned built-in methods at your disposal.

If I want to move an object on a CatmullRomCurve3 so that it does not “wobble” but always looks in the direction of the tangent, I calculate the tangent, normal and binormal. These three vectors form the basis of a new (local) vector space.

(By the way: With coordinate transformation you could now convert from the global system x,y,z into this system. )

The new quaternation method .setFromBasis( e1, e2, e3 ), on the other hand, determines the rotation of this system in relation to the global x,y,z system directly and without detours.

Example: FlightRouteQuaternion
( renewed/added by FlightRouteQuaternion from Collection of examples from discourse.threejs.org )

Set // before
shuttle.quaternion.setFromBasis( t[ iShuttle ], b[ iShuttle ], n[ iShuttle ] );
and see what happens.

For the visualization of rotation/quaternion:

Quaternion - Axis, Angle Visualization

quaternion

7 Likes

Really cool, very helpful. Thanks