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!
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: