Friday, September 14, 2018

3d - Moving a rotated model in XNA


This seems like a simple problem with an equally simple solution that is invisible to me.


I have a model that spawns at the origin and looks at my player model wherever it goes.



I would like it to move forward where it's going. Whenever I try to translate it, it disappears. What am I doing wrong and how do I fix it?


public override void Update()
{
//Glo is a global class, where I store the player's world.
targetShip = Glo.world.Translation;
targetShip.Normalize();

//Rotates the model to face the player's position
rotation = RotateToFace(targetShip, pos, Vector3.Up);
pos += Vector3.Normalize(targetShip - pos) * 20f;


}

public override Matrix GetWorld()
{
// return rotation * translation * world ;
return Matrix.CreateFromQuaternion(rotation) * Matrix.CreateTranslation(pos);
}




UPDATE: When I replace:


translation *= Matrix.CreateTranslation(direction);

with


translation *= Matrix.CreateTranslation(Vector3.Forward);

It now moves forward.


It does not correctly face me, however. It still thinks it's at the origin, and is rotating accordingly.




Here is the edited RotateToFace function The original just returns a Matrix.



Quaternion RotateToFace(Vector3 O, Vector3 P, Vector3 U)
{

//The direction we're facing.
Vector3 D = (O - P);
//Our relative Right.
Vector3 Right = Vector3.Cross(U, D);
Vector3.Normalize(ref Right, out Right);
//Our back
Vector3 Backwards = Vector3.Cross(Right, U);

Vector3.Normalize(ref Backwards, out Backwards);
//Our relative up
Vector3 Up = Vector3.Cross(Backwards, Right);
//Make a matrix out of all of these.
Matrix rot = new Matrix(Right.X, Right.Y, Right.Z, 0, Up.X, Up.Y, Up.Z, 0, Backwards.X, Backwards.Y, Backwards.Z, 0, 0, 0, 0, 1);
Quaternion rot2 = Quaternion.CreateFromRotationMatrix(rot);
return rot2;
}




Draw code:


public void Draw(Camera camera)
{
Matrix[] transforms = new Matrix[model.Bones.Count];
model.CopyAbsoluteBoneTransformsTo(transforms);

foreach (ModelMesh mesh in model.Meshes)
{
foreach (BasicEffect be in mesh.Effects)
{

be.EnableDefaultLighting();
be.Projection = camera.projection;
be.View = camera.view;
be.World = GetWorld() * mesh.ParentBone.Transform;

}

mesh.Draw();
}
}


Answer



I can't figure out your code, a lot of parts in it don't make sense, such as normalizing the position. But if I understood the problem, you want to make the model to always be looking and moving in the direction of a certain target. And you already have an helper method called RotateToFace that takes care of the rotation part.


Then moving the model should really be as simple as taking the direction between itself and the target, and adding that direction to the model's position multiplied by a certain speed factor. Something like:


public class Entity
{
public Vector3 Position { get; set; }
public Quaternion Rotation { get; set; }
public Vector3 Target { get; set; }
public float Speed { get; set; }
public float MinChaseDistance { get; set; }


public void Update(float elapsed)
{
Rotation = RotateToFace(Target, Position, Vector3.Up);
if(Vector3.Distance(Target, Position) > MinChaseDistance)
Position += Vector3.Normalize(Target - Position) * Speed * elapsed;
}

public Matrix GetWorldMatrix()
{

return Matrix.CreateFromQuaternion(Rotation) *
Matrix.CreateTranslation(Position);
}
}

Note: Missed it earlier, but the distance check is actually essential, because if you don't have that and Target happens to match Position, you'll get a call to Normalize on a zero vector, and the Position becomes corrupt (i.e. filled with NaNs).


No comments:

Post a Comment

Simple past, Present perfect Past perfect

Can you tell me which form of the following sentences is the correct one please? Imagine two friends discussing the gym... I was in a good s...