Reputation: 2051
Am I doing the following right?
Well obviously not cause otherwise I wont be posting a question here, but I'm trying to do a Quaternion rotation of a model around another model.
Lets say I have a box model that has a vector3 position and a float rotation angle. I also have a frustum shaped model that is pointing towards the box model, with its position lets say 50 units from the box model. The frustum also has a vector3 position and a Quaternion rotation.
In scenario 1, the box and frustum are "unrotated". This is all fine and well. In scenario 2, I rotate the box only and I want the frustum to rotate with it (kinda like a chase camera) with the frustum always pointing directly at the box and at the same distance from the box as in the unrotated distance. Obviously if I just rotate the model and the frustum by using Matrix.CreateRotationY() for both the box and the frustum, the frustum is slightly offset to the side.
So I thought a Quaternion rotation of the frustum around the box would be best? To this end I have tried the following, with no luck. It draws my models on the screen, but it also draws what looks like a giant box to the screen and no matter how far away I move the camera the box is always in the way
For the purpose of testing, I have 3 boxes and their 3 associated frustums In my Game1 class I initialize the box[0] with positions and rotations
boxObject[0].Position = new Vector3(10, 10, 10);
boxObject[1].Position = new Vector3(10, 10, 10);
boxObject[2].Position = new Vector3(10, 10, 10);
boxObject[0].Rotation = 0.0f;
boxObject[1].Rotation = 45.0f;
boxObject[2].Rotation = -45.0f;
So all 3 boxes drawn at the same position but at different angles. Then to do the frustums, I initiate their position:
float f = 50.0f;
frustumObject[0].Position = new Vector3(boxObject[0].Position.X,
boxObject[0].Position.Y, boxObject[0].Position.Z + f);
frustumObject[1].Position = new Vector3(boxObject[1].Position.X,
boxObject[1].Position.Y, boxObject[1].Position.Z + f);
frustumObject[2].Position = new Vector3(boxObject[2].Position.X,
boxObject[2].Position.Y, boxObject[2].Position.Z + f);
And then try and rotate around their associated box model:
frustumObject[0].ModelRotation = new Quaternion(boxObject[0].Position.X,
boxObject[0].Position.Y, boxObject[0].Position.Z + f, 0);
frustumObject[0].ModelRotation = new Quaternion(boxObject[0].Position.X,
boxObject[0].Position.Y, boxObject[0].Position.Z + f, 45);
frustumObject[0].ModelRotation = new Quaternion(boxObject[0].Position.X,
boxObject[0].Position.Y, boxObject[0].Position.Z + f, -45);
And finally, to draw the models, I Draw() them in my GameModel class which also has:
public Model CameraModel { get; set; }
public Vector3 Position { get; set; }
public float Rotation { get; set; }
public Quaternion ModelRotation { get; set; }
public void Draw(Matrix view, Matrix projection)
{
transforms = new Matrix[CameraModel.Bones.Count];
CameraModel.CopyAbsoluteBoneTransformsTo(transforms);
// Draw the model
foreach (ModelMesh myMesh in CameraModel.Meshes)
{
foreach (BasicEffect myEffect in myMesh.Effects)
{
// IS THIS CORRECT?????
myEffect.World = transforms[myMesh.ParentBone.Index] *
Matrix.CreateRotationY(Rotation) * Matrix.CreateFromQuaternion(ModelRotation) * Matrix.CreateTranslation(Position);
myEffect.View = view;
myEffect.Projection = projection;
myEffect.EnableDefaultLighting();
myEffect.SpecularColor = new Vector3(0.25f);
myEffect.SpecularPower = 16;
}
myMesh.Draw();
}
}
Can anyone spot where I am going wrong? Is it because I am doing 2 types of rotations n the Draw()?
myEffect.World = transforms[myMesh.ParentBone.Index] * Matrix.CreateRotationY(Rotation) * Matrix.CreateFromQuaternion(ModelRotation) * Matrix.CreateTranslation(Position);
Upvotes: 4
Views: 6266
Reputation: 166
From a quick glance, it would be best to create your Quaternions using a static create method such as Quaternion.CreateFromAxisAngle(Vector3. UnitY, rotation)
. The values of X,Y,Z and W of a Quaternion do not relate to position in any way. The handy static methods take care of the tricky math.
In your situation it appears as though you want to keep the frustum pointing at the same side of the box as the box rotates, therefore rotating the frustum about the box. This requires a slightly different approach to the translation done in your draw method.
In order to rotate an object about another, you first need to translate the object so that the centre of the desired rotation is at the origin. Then rotate the object and translate it back by the same amount as the first step.
So in you situation, something like this should do it (untested example code to follow);
// Construct the objects
boxObject.Position = new Vector3(10, 10, 10);
boxObject.Rotation = 45.0f;
frustumObject.Position = new Vector3(0, 0, 50f); // Note: this will be relative to the box (makes the math a bit simpler)
frustumObject.TargetPosition = boxObject.Position;
frustumObject.ModelRotation = Quaternion.CreateFromAxisAngle(Vector3. UnitY, boxObject.Rotation); // Note: this rotation angle may need to be in radians.
// Box Draw()
// Draw the box at its position, rotated about its centre.
myEffect.World = transforms[myMesh.ParentBone.Index] * Matrix.CreateTranslation(Position) * Matrix.CreateRotationY(Rotation);
// Frustum Draw()
// Draw the frustum facing the box and rotated about the boxes centre.
myEffect.World = transforms[myMesh.ParentBone.Index] * Matrix.CreateTranslation(Position) * Matrix.CreateFromQuaternion(ModelRotation) * Matrix.CreateTranslation(TargetPosition);
Assumptions:
Hope this helps.
Upvotes: 5