quaternion from two directions, optimization
I try to write the quaternion from two directions,
(directions is unit vectors)
and found the solution that use:
We can find CosAngle as DotProduct of dir vectors
SinHalfAngle = sqrt(0.5 * (1.0 - CosAngle) );
CosHalfAngle = sqrt(0.5 * (1.0 + CosAngle) );
But it takes 2 sqrts.
We easy know the SinAngleSqared ( from CrossProduct ) , and CosAngle, Can we do it faster ?
void QuaternionFromTwoDirs( quaternion& quat,
vector3& UnitFrom,
vector3& UnitTo)
{
float CosA = Dot(UnitFrom,UnitTo);
vector3 Cross( Cross(UnitFrom,UnitTo) ); // rotation Axe
// here we can find Cross.len_sqared() fast
Cross.norm();
// half-angle formulae (sin^2 t = ( 1 - cos (2t) ) /2)
Cross *= (float)sqrt(0.5f * (1.0f - CosA));
quat.x = Cross.x;
quat.y = Cross.y;
quat.z = Cross.z;
// cos^2 t = ( 1 + cos (2t) ) / 2
quat.w = (float)sqrt(0.5f * (1.0f + CosA));
}
Second version:
inline void QuaternionFromTwoDirs2( quaternion& quat,
const vector3& UnitFrom,
const vector3& UnitTo){
float CosA = UnitFrom%UnitTo;
if( CosA < - 0.99999f ){ // angle close to PI
vector3 Cross( 0, UnitFrom.x, -UnitFrom.y );
if( (UnitFrom.z*UnitFrom.z) > (UnitFrom.y*UnitFrom.y) ) // if (0, 1, 0) Cross > (1, 0, 0) Cross
Cross.set( -UnitFrom.z, 0, UnitFrom.x );
Cross.norm();
quat.set( Cross.x, Cross.y, Cross.z, 0.0f );
}else{
vector3 Bisect( UnitFrom + UnitTo );
Bisect.norm();
float HalfCosA = UnitFrom%Bisect;
vector3 BCross( UnitFrom*Bisect );
quat.set( BCross.x, BCross.y, BCross.z, HalfCosA );
}
}
inline void QuaternionFromTwoDirs2( quaternion& quat,
const vector3& UnitFrom,
const vector3& UnitTo){
float CosA = UnitFrom%UnitTo;
if( CosA < - 0.99999f ){ // angle close to PI
vector3 Cross( 0, UnitFrom.x, -UnitFrom.y );
if( (UnitFrom.z*UnitFrom.z) > (UnitFrom.y*UnitFrom.y) ) // if (0, 1, 0) Cross > (1, 0, 0) Cross
Cross.set( -UnitFrom.z, 0, UnitFrom.x );
Cross.norm();
quat.set( Cross.x, Cross.y, Cross.z, 0.0f );
}else{
vector3 Bisect( UnitFrom + UnitTo );
Bisect.norm();
float HalfCosA = UnitFrom%Bisect;
vector3 BCross( UnitFrom*Bisect );
quat.set( BCross.x, BCross.y, BCross.z, HalfCosA );
}
}
3d version:
inline void QuaternionFromTwoDirs2( quaternion& quat,
const vector3& UnitFrom,
const vector3& UnitTo){
float CosA = Dot(UnitFrom, UnitTo );
if( CosA < - 0.99999f ){ // angle close to PI
vector3 Cross( 0, UnitFrom.x, -UnitFrom.y );
if( (UnitFrom.z*UnitFrom.z) > (UnitFrom.y*UnitFrom.y) ) // if (0, 1, 0) Cross > (1, 0, 0) Cross
Cross.set( -UnitFrom.z, 0, UnitFrom.x );
Cross.norm();
quat.set( Cross.x, Cross.y, Cross.z, 0.0f );
}else{
vector3 Bisect( UnitFrom + UnitTo );
Bisect.norm();
float HalfCosA = Dot(UnitFrom%Bisect);
vector3 BCross( Cross(UnitFrom, Bisect) );
quat.set( BCross.x, BCross.y, BCross.z, HalfCosA );
}
}
//---------------------
Trying to write some thing like lookat for quternion , using up vector too , but still can''t do faster the matrix->lookat -> quaternion
inline void QuaternionFromTwoDirs2( quaternion& quat,
const vector3& UnitFrom,
const vector3& UnitTo){
float CosA = Dot(UnitFrom, UnitTo );
if( CosA < - 0.99999f ){ // angle close to PI
vector3 Cross( 0, UnitFrom.x, -UnitFrom.y );
if( (UnitFrom.z*UnitFrom.z) > (UnitFrom.y*UnitFrom.y) ) // if (0, 1, 0) Cross > (1, 0, 0) Cross
Cross.set( -UnitFrom.z, 0, UnitFrom.x );
Cross.norm();
quat.set( Cross.x, Cross.y, Cross.z, 0.0f );
}else{
vector3 Bisect( UnitFrom + UnitTo );
Bisect.norm();
float HalfCosA = Dot(UnitFrom%Bisect);
vector3 BCross( Cross(UnitFrom, Bisect) );
quat.set( BCross.x, BCross.y, BCross.z, HalfCosA );
}
}
//---------------------
Trying to write some thing like lookat for quternion , using up vector too , but still can''t do faster the matrix->lookat -> quaternion
This topic is closed to new replies.
Advertisement
Popular Topics
Advertisement
Recommended Tutorials
Advertisement