3D: Preserve object’s orientation when placing on surface

Let’s say you have an arbitrary object that you are sliding from a surface to another surface. Your object has an arbitrary orientation (like the schema below) and you want to place it on another surface which has a different orientation, but when moving to that new surface, you want to preserve the X and Y local axis of the object (as much as possible) and slide the Z axis to the Z axis of the target surface. You can build a quaternion with the object’ up vector and the normal of the surface to obtain the smallest arc rotation for these two vectors.

Here’s the code to build the quaternion given the two vectors in space:

// Find the quat that rotates v0 to v1. 
void Quaternion::Build(
    const Vector3D<T>& v0, 
    const Vector3D<T>& v1)
{
  Vector3 cross = Vector3::CrossProduct(v0, v1);
  T d = Vector3::DotProduct(v0, v1);
  T s = sqrt((1+d)*2);
  T recip = 1.0f / s;
 
  // Set quaternion components
  x = cross[0] * recip;
  y = cross[1] * recip;
  z = cross[2] * recip;
  u = s * 0.5f;
}

And then you do this to build an orthogonal matrix with the computed rotation:

const Matrix GetOrthogonalMatrix(
    const Matrix& objMat, 
    const Vector3& placementPosition, 
    const Vector3& placementNormal)
{
  Quaternion q;
  const Vector3 objUpAxis = Normalize(objMat.GetZAxis());
  q.Build(objUpAxis, placementNormal);
 
  Matrix matRot = Matrix(q) * GetRotationMatrix(objMat);
  Matrix matScale;
  Matrix matTrans;
  matTrans.BuildTranslation( placementPosition );
  matScale.BuildScale( GetScaleMatrix(objMat) );
  return matTrans * matRot * matScale;
}
This entry was posted in C++ and tagged , , , , . Bookmark the permalink.

Leave a Reply

Your email address will not be published. Required fields are marked *