judeclarke said:
What I have is a object going from one point to another point over time. When it decides to go to another point I want to orient the object in direction it is going.
This reminds me on an older post, where the question was to make a turret rotating towards a goal. I add my proposed solution below. (Originally this also had limits so the turrets orientation is restricted - i have removed this code sections and hope i did not mess it up somehow.)
I guess it's pretty confusing so here a description on how it works. Your problem is similar to the process of constructing a ‘look at matrix’, which would be easy. But doing the rotation gradually over time makes it harder.
- Calculate the axis and angle between your objects forward direction and the vector from object center to the target point.
Notice that axis and angle is the most natural way to imagine a 3D rotation. Spread two fingers and imagine the axis one finger would need to rotate so it matches the other.
Now imagine a triangle from the (almost) common root of the fingers to the two finger tips. You get a triangle, and the axis of rotation is the same as the triangle normal. (The rotating finger remains on the plane of the triangle).
So it becomes obvious how you can calculate axis with cross product of the two vectors and angle from their dot product. - relate the angle to some maximum speed you want the object to turn, and reduce it if necessary. (I also added some smoothing so it behaves more natural)
- Convert your axis and angle representation into a rotation matrix or a quaternion (like i did below), so you can apply it to your objects transform data.
- Rotate the object, and optionally constrain its up vector if desired. I did this by constructing orientation matrix manually just like usual when we need a ‘look at’ matrix.
- repeat all this in the next frame until the object is nicely ‘looking’ at the target.
If you're new to 3D rotations as it seems, this is not easy to begin with. But it's often necessary, so worth to learn. Expect to invest some time.
judeclarke said:
My transform matrix a Translation vector, Rotation vector and Scale vector.
It sounds like you have a SRT representation of transforms. (scale, rotation in euler angles, translation - given as 3-vectors)
This is useful e.g. for a scene graph in a game editor, because a human can edit the number intuitively.
But it is not optimal for a game runtime. Becasue euler angles are hard and slow to work. Aslo notice SRT is not yet a matrix.
The typical solution is to convert your SRT hierarchy to 4x4 transfrom matrices (you likely do this already so you can render your stuff),
then use the matrices to solve problems as discussed, and finally convert results back to SRT if needed.
When working with 3D rotations it is key to understand that matrices already contain front-, up-, and right-(or left) vectors to define orientation, which makes things easy that would be super hard when using euler angles.
{
struct Turret
{
// orientaton convention: X axis: front (turret shooting direction), Y axis: up, Z axis: side
quat orientation;
vec position;
quat mountOrientation; // e.g. the ground or a vehicle frame, we use it to define up vector and angle limits
Turret ()
{
orientation.Identity();
mountOrientation.Identity();
position = vec(0,0,0);
}
};
static Turret turret;
static vec target (10, 3, 0);
ImGui::DragFloat3 ("target pos", (float*)&target, 0.01f);
vec curDir = turret.orientation.Rotate(vec(1,0,0));
vec targetDir = vec(target - turret.position).Unit();
float dot = curDir.Dot(targetDir);
if (fabs(dot) < 1.0f - 1.0e-5f) // otherwise axis would be result of division by zero
{
// calculate axis and angle rotation between directions
float angle = acos(dot); // Notice this is always positive (the direction of the axis defines if we rotate left or right)
vec axis = (curDir.Cross(targetDir)).Unit();
// optional: some damping to make it smooth. This simple approach assumes constant timestep and needs to be adjusted to this value. (for 60 fps try 0.3)
const float damp = 0.03f;
angle *= damp;
// limit angle if necessary
const float maxAngularVelocity = 30.0f / 180.0f * 3.14f; // e.g. 30 degrees per second
const float timestep = 1.0f / 500.0f; // i have 500 fps
float maxAnglePerUpdate = maxAngularVelocity * timestep;
if (angle > maxAnglePerUpdate) angle = maxAnglePerUpdate;
// finally rotate turret
quat rot; rot.FromAxisAndAngle (axis, angle);
if (0) // no upvector, ok for a spaceship
{
turret.orientation = rot * turret.orientation;
turret.orientation.Normalize();
}
else // using upvector, turret side axis remains on the up plane defined by mountOrientation
{
const vec globalUp = turret.mountOrientation.Rotate(vec(0,1,0));
// if turrets already aligned to up vector, could just use vec(0,1,0) and no need to rotate relative from its mounting base.
vec newTurretDir = rot.Rotate(curDir);
if (fabs( globalUp.Dot(newTurretDir) ) < 1.0f - 1.0e-5f) // turret would be clueless if pointing exactly up / downwards
{
vec side = vec(globalUp.Cross(newTurretDir)).Unit();
vec localUp = newTurretDir.Cross(side);
matrix temp;
temp[0] = newTurretDir;
temp[1] = side;
temp[2] = localUp;
temp.Rotation()->ToQuat(turret.orientation);
}
}
}
// visualize
RenderLine (target, turret.position, 0.5f,0.5f,0.5f);
RenderQuat (turret.position, turret.orientation);
RenderQuat (turret.position, turret.mountOrientation, 0.2f);
RenderPoint (target, 1,1,1);
RenderCircle (1, turret.position, vec(0,1,0), 0,1,0);
}