Game Development Community

Rotate a vector about any arbitrary axis

by QuangKim · in Torque Game Engine · 12/29/2005 (8:42 pm) · 3 replies

Iam faced with an issue when i am trying to rotate an Item::class about any arbitrary axis, it seems to roate only abuot the Z-axis, and refuses to do so about any other axis using hte Item::setTransform().
i tried using Quats, and AngAxis to create my own rotation matrices, and rotate the look and up vector about this axis, and set it to the matrix, still for some reason does not sem to work. the rotation matrix is mathematically correct (did chk it out...with the usual cumbersome way :)).

this is what i have done...

{
...
AngAxisF angAx( vLook, fAng );
angAx.setMatrix( &rotMat );

// get the new axes after rotation
vNLook = vLook;
rotMat.mulV( vRight, &vNRight );
mCross( vNRight, vNLook, &vNUp );
vNUp.normalize();


// set the above directions into a matrix
newMat.setColumn( 0, vNRight );
newMat.setColumn( 1, vNLook );
newMat.setColumn( 2, vNUp );
newMat.setColumn( 3, vPos );

// apply the transform to the object...
Parent::setTransform( newMat );
setMaskBits( RotationMask | PositionMask | NoWarpMask );
}

the matrix is computes fnie, but after the setTransform(), the object does not orient itself right, anything that i have missed out? i hope i get a quicl response...

thought it might be because of the object's getting set, made sure that thats not the case too...



Thx,
Ravi

#1
12/29/2005 (8:51 pm)
The object is actually being rotated normally (and as you desire), however, the networking code makes that assumption I alluded to in the public forums post: items should only rotate about their Z axis.

Note the following code from item.cc, roughly line 802:

U32 Item::packUpdate(NetConnection *connection, U32 mask, BitStream *stream)
{
   U32 retMask = Parent::packUpdate(connection,mask,stream);

   if (stream->writeFlag(mask & InitialUpdateMask)) {
      stream->writeFlag(mRotate);
      stream->writeFlag(mStatic);
      stream->writeFlag(mCollideable);
      if (stream->writeFlag(getScale() != Point3F(1, 1, 1)))
         mathWrite(*stream, getScale());
   }
   if (mask & ThrowSrcMask && mCollisionObject) {
      S32 gIndex = connection->getGhostIndex(mCollisionObject);
      if (stream->writeFlag(gIndex != -1))
         stream->writeInt(gIndex,NetConnection::GhostIdBitSize);
   }
   else
      stream->writeFlag(false);
   if (stream->writeFlag(mask & RotationMask && !mRotate)) {
      // Assumes rotation is about the Z axis
      AngAxisF aa(mObjToWorld);
      stream->writeFlag(aa.axis.z < 0);
      stream->write(aa.angle);
   }
   if (stream->writeFlag(mask & PositionMask)) {
      Point3F pos;
      mObjToWorld.getColumn(3,&pos);
      mathWrite(*stream, pos);
      if (!stream->writeFlag(mAtRest)) {
         mathWrite(*stream, mVelocity);
      }
      stream->writeFlag(!(mask & NoWarpMask));
   }
   return retMask;
}

Specifically, the following block:

...
   if (stream->writeFlag(mask & RotationMask && !mRotate)) {
      // Assumes rotation is about the Z axis
      AngAxisF aa(mObjToWorld);
      stream->writeFlag(aa.axis.z < 0);
      stream->write(aa.angle);
   }
...

As you can see, it only ever sends the Z axis rotation (aa.axis.z < 0, and aa.angle), and the corresponding unpackUpdate() (just after in the file) only affects the z axis based on the BitStream sent.

If you want all 3 dimensions of rotation, you should modify your Item class to use the same technique as is used in the Vehicle::packUpdate() and Vehicle::unpackUpdate() in vehicle.cc.

Alternatively, you could derive your class from Vehicle, and that portion would be done for you already (although you'd pick up a lot of things most likely that you don't need).
#2
12/29/2005 (11:07 pm)
Thx, will look at it...:)
#3
01/26/2006 (11:52 pm)
Again, used this, it works the way it should but theres a problem with this...i am adding a ball as an Item, and whenever it moves some distance, the ball starts switching places, it keeps switching between two places, i guess for some reason the client and server synch is getting messed up, because of which the problem occurs, any ideas and fixes for the same...

also the Item::settransform() function modified it too, so that the axis related stuf is removed. this is my current code...


U32 Item::packUpdate(NetConnection *connection, U32 mask, BitStream *stream)
{
U32 retMask = Parent::packUpdate(connection,mask,stream);
if (stream->writeFlag(mask & InitialUpdateMask))
{
stream->writeFlag(mRotate);
stream->writeFlag(mStatic);
stream->writeFlag(mCollideable);
stream->writeFlag( mGenerateShadow );
if (stream->writeFlag(getScale() != Point3F(1, 1, 1)))
mathWrite(*stream, getScale());
}
if (mask & ThrowSrcMask && mCollisionObject)
{
S32 gIndex = connection->getGhostIndex(mCollisionObject);
if (stream->writeFlag(gIndex != -1))
stream->writeInt(gIndex,NetConnection::GhostIdBitSize);
}
else
stream->writeFlag(false);
if (stream->writeFlag(mask & PositionMask))
{
stream->writeAffineTransform(mObjToWorld);
mathWrite(*stream, mObjScale);
//Point3F pos;
//mObjToWorld.getColumn(3,&pos);
//mathWrite(*stream, pos);
if (!stream->writeFlag(mAtRest))
{
mathWrite(*stream, mVelocity);
}
stream->writeFlag(!(mask & NoWarpMask));
}
return retMask;
}

void Item::unpackUpdate(NetConnection *connection, BitStream *stream)
{
Parent::unpackUpdate(connection,stream);
if (stream->readFlag())
{
mRotate = stream->readFlag();
mStatic = stream->readFlag();
mCollideable = stream->readFlag();
mGenerateShadow = stream->readFlag();
if (stream->readFlag())
mathRead(*stream, &mObjScale);
else
mObjScale.set(1, 1, 1);
}
if (stream->readFlag())
{
S32 gIndex = stream->readInt(10);
setCollisionTimeout(static_cast(connection->resolveGhost(gIndex)));
}
if (stream->readFlag())
{
// From StaticShape
MatrixF mat;
stream->readAffineTransform(&mat);
VectorF scale;
mathRead(*stream, &scale);
setScale(scale); // Original Code
Point3F pos;
mat.getColumn(3,&pos);
F32 speed = mVelocity.len();
if ((mAtRest = stream->readFlag()) == true)
mVelocity.set(0,0,0);
else
mathRead(*stream, &mVelocity);
if (stream->readFlag() && isProperlyAdded())
{
// Determine number of ticks to warp based on the average
// of the client and server velocities.
delta.warpOffset = pos - delta.pos;
F32 as = (speed + mVelocity.len()) * 0.5 * TickSec;
F32 dt = (as > 0.00001f) ? delta.warpOffset.len() / as: sMaxWarpTicks;
delta.warpTicks = (S32)((dt > sMinWarpTicks)? getMax(mFloor(dt + 0.5), 1.0f): 0.0f);
if (delta.warpTicks)
{
// Setup the warp to start on the next tick, only the
// object's position is warped.
if (delta.warpTicks > sMaxWarpTicks)
delta.warpTicks = sMaxWarpTicks;
delta.warpOffset /= delta.warpTicks;
}
else
{
// Going to skip the warp, server and client are real close.
// Adjust the frame interpolation to move smoothly to the
// new position within the current tick.
Point3F cp = delta.pos + delta.posVec * delta.dt;
VectorF vec = delta.pos - cp;
F32 vl = vec.len();
if (vl)
{
F32 s = delta.posVec.len() / vl;
delta.posVec = (cp - pos) * s;
}
delta.pos = pos;
mat.setColumn(3,pos);
}
}
else
{
// Set the item to the server position
delta.warpTicks = 0;
delta.posVec.set(0,0,0);
delta.pos = pos;
delta.dt = 0;
mat.setColumn(3,pos);
}
Parent::setTransform(mat);
Parent::setRenderTransform(mat);
}
}


void Item::setTransform(const MatrixF& mat)
{
Parent::setTransform(mat);
setMaskBits(PositionMask | NoWarpMask);
}


i got this in one of the forums.


Thx,
Ravi.