4
\$\begingroup\$

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();
    }
}
\$\endgroup\$
2
  • \$\begingroup\$ Try to in GetWorld method multiply matrixes in this order: return rotation * translation *world; btw what is world matrix there? \$\endgroup\$
    – Vodáček
    Commented May 1, 2012 at 18:23
  • \$\begingroup\$ I tried that, and that did not seem to change anything. world is read by other classes for hit detection and seems to be the object's real position \$\endgroup\$
    – user8017
    Commented May 1, 2012 at 18:33

1 Answer 1

3
\$\begingroup\$

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).

\$\endgroup\$
13
  • \$\begingroup\$ The RotateToFace function returns a Matrix, so I applied your code accordingly. However, it didn't work. My model does not move \$\endgroup\$
    – user8017
    Commented May 1, 2012 at 18:46
  • 1
    \$\begingroup\$ @OWiz That's part of the problem. You're doing all of the intermediate calculations with matrices, and it's a mess. You really should be working with simple position and rotation properties, and the only part in the code that needs to convert it to matrices is the GetWorldMatrix method. It would be a lot simpler and cleaner that way. I would recommend trying it in a separate class for starters. \$\endgroup\$ Commented May 1, 2012 at 18:51
  • \$\begingroup\$ Okay, well that theory helps. Forgive me for not doing it the "right" way, I don't have much experience in dealing with quats and matrices. I'll try this now.... It doesn't work. Whenever I include the code relating to translating the object, the model appears to vanish. \$\endgroup\$
    – user8017
    Commented May 1, 2012 at 21:55
  • \$\begingroup\$ @OWiz edit your question by including the code for 'RotateToFace' please \$\endgroup\$
    – Steve H
    Commented May 2, 2012 at 2:22
  • 1
    \$\begingroup\$ @OWiz Regardless of the rotation code, that single Position += ... line should be enough to move the model towards the target. If it's not moving, then it's either that you're not calculating the world matrix correctly, the Position or Target values are wrong, or the Speed is too large. \$\endgroup\$ Commented May 2, 2012 at 6:05

You must log in to answer this question.