Перемещение PerspectiveCamera в направлении, в котором она обращена в C #

В настоящее время я работаю в приложении wpf с камерой Viewport3D. И я создаю модуль трехмерного прохождения. Я хочу, чтобы мой PerspectiveCamera двигался в зависимости от направления, в котором он смотрит после изменения направления взгляда. Я использую клавиатуру для управления движением, например:
NUMPAD8: двигаться вперед
NUMPAD2: двигаться назад
NUMPAD4: повернуть влево
NUMPAD6: повернуть вправо

Этот метод ниже предназначен для обнаружения события клавиатуры:

 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);
        }
    }

Это необходимо для расчета вращения:

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;

    }

Это необходимо для расчета движения камеры:

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;
    }

Вычисление вращения работает идеально, но движение кажется некорректным, поскольку оно перемещает камеру в зависимости от положения камеры, а не направления взгляда после поворота.


person Wan Hao Jun    schedule 12.04.2017    source источник


Ответы (1)


Закомментированный код выглядит более или менее правильно ... вы не сказали, что с ним не так. Вы пробовали нормализовать вектор lookDirection? При нормализации вектора его величина (длина) равна 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;
}

ОБНОВИТЬ:

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);
}
person J.H.    schedule 12.04.2017
comment
Большое спасибо за решение, но ваше решение чем-то похоже на закомментированный код. Закомментированная часть - это что-то вроде увеличения и уменьшения масштаба в направлении лицевой стороны. Например, если я продолжаю увеличивать масштаб, в конечном итоге он будет проходить сквозь пол. Я хочу что-то вроде иммерсивного прохождения. Как первая перспектива пользовательского вида в трехмерной среде. Проще говоря, пользователь похож на прогулку в трехмерной среде. - person Wan Hao Jun; 13.04.2017
comment
Wpf выполняет только рендеринг. Вам нужно создать движок столкновений или использовать уже существующий, например Bullet Physics. Имеет оболочку C # BulletSharp - andrestraks.github.io/BulletSharp. - person J.H.; 16.04.2017
comment
Спасибо. Не могли бы вы объяснить код в части вращения? Потому что я получил этот код из Интернета и не совсем понимаю, что именно он делает. Необходимо лишь кратко объяснить. Очень ценю. - person Wan Hao Jun; 16.04.2017
comment
Эээ ... нет. Похоже, что он выполняется вручную, хотя некоторые уравнения (без сомнения, уравнения вращения). Я бы посоветовал вам реализовать этот код самостоятельно, если вы действительно хотите его понять. Начнем с некоторых трехмерных уравнений вращения. Я обновил свой ответ, включив в него еще один способ поворота камеры с помощью Matrix3D (класс wpf). Я также добавил метод RotateVertical, который поворачивает камеру вверх / вниз (вместо влево / вправо). - person J.H.; 20.04.2017