Wan Hao Jun
Wan Hao Jun

Reputation: 33

Moving PerspectiveCamera in the direction it is facing in C#

I am currently working in a wpf application which has a Viewport3D camera. And I am creating a 3D walkthrough module. I want my PerspectiveCamera to move based on the direction the it is facing after the Look Directions has changed. I am using my keyboard to control the movement, for example:
NUMPAD8: move forward
NUMPAD2: move backward
NUMPAD4: rotate left
NUMPAD6: rotate right

This method below is to detect keyboard event:

 private void button20_KeyDown(Object sender, KeyEventArgs e)
    {
        if (e.Key == Key.NumPad6)
        {
            Rotate(1);
        }
        else if (e.Key == Key.NumPad4)
        {
            Rotate(-1);
        }
        else if (e.Key == Key.NumPad8)
        {
            Move(-10);
        }
        else if (e.Key == Key.NumPad2)
        {
            Move(10);
        }
    }

This is to calculate rotation:

public void Rotate(double d)
    {
        double u = 0.05;
        double angleD = u * d;
        PerspectiveCamera camera = (PerspectiveCamera)Viewport3D.Camera;
        Vector3D lookDirection = camera.LookDirection;
        double L = lookDirection.Length;
        double D = 2 * L * Math.Sin(angleD / 2);
        double m = Math.Sqrt(lookDirection.X * lookDirection.X + lookDirection.Y * lookDirection.Y);
        double angleA = 2 * Math.Asin(D / (2 * m));
        double x = lookDirection.X;
        double y = lookDirection.Y;
        double angleB = Math.Atan2(y, x);
        double angleG = angleB - angleA;
        double newx = m * Math.Cos(angleG);
        double newy = m * Math.Sin(angleG);
        Vector3D NewlookDirection = new Vector3D(newx, newy, lookDirection.Z);
        camera.LookDirection = NewlookDirection;

    }

This is to calculate the camera movement:

public void Move(double d)
    {
        double u = 0.05;
        PerspectiveCamera camera = (PerspectiveCamera)Viewport3D.Camera;
        Vector3D lookDirection = camera.LookDirection;
        Point3D position = camera.Position;
        //Point3D NewPosition = new Point3D();
        position.Y += d;
        //NewPosition.X = position.X + u * lookDirection.X * d;
        //NewPosition.Y = position.Y + u * lookDirection.Y * d;
        //NewPosition.Z = position.Z + u * lookDirection.Z * d;
        //camera.Position = NewPosition;
        camera.Position = position;
    }

The rotation calculation works perfect but the movement seems not working good as it moves the camera based on the camera position instead of the facing direction after the rotation.

Upvotes: 2

Views: 3051

Answers (1)

J.H.
J.H.

Reputation: 4322

The commented out code looks more or less right... you didn't say what was wrong with it. Have you tried to normalize the lookDirection vector? Normalizing a vector makes it have a magnitude (length) of 1.

public void Move(double d)
{
    double u = 0.05;
    PerspectiveCamera camera = (PerspectiveCamera)Viewport3D.Camera;
    Vector3D lookDirection = camera.LookDirection;
    Point3D position = camera.Position;

    lookDirection.Normalize();
    position = position + u * lookDirection * d;

    camera.Position = position;
}

UPDATE:

private void Window_KeyDown(object sender, KeyEventArgs e)
{
    if (e.Key == Key.NumPad6)
    {
        Rotate(10);
    }
    else if (e.Key == Key.NumPad4)
    {
        Rotate(-10);
    }
    else if (e.Key == Key.NumPad8)
    {
        Move(-10);
    }
    else if (e.Key == Key.NumPad2)
    {
        Move(10);
    }
    else if (e.Key == Key.PageUp)
    {
        RotateVertical(10);
    }
    else if (e.Key == Key.PageDown)
    {
        RotateVertical(-10);
    }
}
public void Rotate(double d)
{
    double u = 0.05;
    double angleD = u * d;
    PerspectiveCamera camera = (PerspectiveCamera)Viewport3D.Camera;
    Vector3D lookDirection = camera.LookDirection;

    var m = new Matrix3D();
    m.Rotate(new Quaternion(camera.UpDirection, -angleD)); // Rotate about the camera's up direction to look left/right
    camera.LookDirection = m.Transform(camera.LookDirection);
}

public void RotateVertical(double d)
{
    double u = 0.05;
    double angleD = u * d;
    PerspectiveCamera camera = (PerspectiveCamera)Viewport3D.Camera;
    Vector3D lookDirection = camera.LookDirection;

    // Cross Product gets a vector that is perpendicular to the passed in vectors (order does matter, reverse the order and the vector will point in the reverse direction)
    var cp = Vector3D.CrossProduct(camera.UpDirection, lookDirection);
    cp.Normalize();

    var m = new Matrix3D();
    m.Rotate(new Quaternion(cp, -angleD)); // Rotate about the vector from the cross product
    camera.LookDirection = m.Transform(camera.LookDirection);
}

Upvotes: 2

Related Questions