Матричные преобразования для воссоздания функциональности камеры "Взгляд на" - PullRequest
3 голосов
/ 07 февраля 2012

Резюме:

Мне дан ряд точек в трехмерном пространстве, и я хочу проанализировать их с любого угла обзора. Я пытаюсь выяснить, как воспроизвести функциональность Open Look в OpenFL в WPF. Я хочу, чтобы движение мышью X, Y управляло сферическими координатами Phi и Theta (соответственно) камеры, чтобы при перемещении мыши камера вращалась вокруг центра масс (обычно источника) облака точек. , который будет представлять цель взгляда на

Что я сделал:

Я сделал следующий код, но пока он не выполняет то, что я хочу:

    internal static Matrix3D CalculateLookAt(Vector3D eye, Vector3D at = new Vector3D(), Vector3D up = new Vector3D())
    {
        if (Math.Abs(up.Length - 0.0) < double.Epsilon) up = new Vector3D(0, 1, 0);
        var zaxis = (at - eye);
        zaxis.Normalize();
        var xaxis = Vector3D.CrossProduct(up, zaxis);
        xaxis.Normalize();
        var yaxis = Vector3D.CrossProduct(zaxis, xaxis);

        return new Matrix3D(
            xaxis.X, yaxis.X, zaxis.X, 0,
            xaxis.Y, yaxis.Y, zaxis.Y, 0,
            xaxis.Z, yaxis.Z, zaxis.Z, 0,
            Vector3D.DotProduct(xaxis, -eye), Vector3D.DotProduct(yaxis, -eye), Vector3D.DotProduct(zaxis, -eye), 1
            );
    }

Я получил алгоритм по этой ссылке: http://msdn.microsoft.com/en-us/library/bb205342(VS.85).aspx

Затем я применяю возвращенную матрицу ко всем точкам, используя это:

    var vector = new Vector3D(p.X, p.Y, p.Z);

    var projection = Vector3D.Multiply(vector, _camera);    // _camera is the LookAt Matrix

    if (double.IsNaN(projection.X)) projection.X = 0;
    if (double.IsNaN(projection.Y)) projection.Y = 0;
    if (double.IsNaN(projection.Z)) projection.Z = 0;

    return new Point(
        (dispCanvas.ActualWidth * projection.X / 320),
        (dispCanvas.ActualHeight * projection.Y / 240)
        );

Я вычисляю центр всех точек как вектор at, и я установил свой начальный вектор eye на (center.X,center.Y,center.Z + 100), что достаточно далеко от всех точек

Затем я делаю движение мыши и применяю следующий код, чтобы получить сферические координаты, и помещаю это в функцию CalculateLookAt:

        var center = GetCenter(_points);
        var pos = e.GetPosition(Canvas4);   //e is of type MouseButtonEventArgs
        var delta = _previousPoint - pos;

        double r = 100;
        double theta = delta.Y * Math.PI / 180;
        double phi = delta.X * Math.PI / 180;

        var x = r * Math.Sin(theta) * Math.Cos(phi);
        var y = r * Math.Cos(theta);
        var z = -r * Math.Sin(theta) * Math.Sin(phi);

        _camera = MathHelper.CalculateLookAt(new Vector3D(center.X * x, center.Y * y, center.Z * z), new Vector3D(center.X, center.Y, center.Z));

        UpdateCanvas();   // Redraws the points on the canvas using the new _camera values

Вывод:

Это не заставляет камеру вращаться вокруг точек. Так что либо мое понимание того, как использовать функцию «Смотреть на», отключено, либо моя математика неверна.

Любая помощь будет принята с благодарностью.

Ответы [ 2 ]

4 голосов
/ 09 февраля 2012

Vector3D не преобразуется в аффинном пространстве.Vector3D не будет переводиться, потому что это вектор, который не существует в аффинном пространстве (т.е. трехмерном векторном пространстве с компонентом перевода), только в векторном пространстве.Вам нужно Point3D:

var m = new Matrix3D(
                1, 0, 0, 0, 
                0, 1, 0, 0, 
                0, 0, 1, 0, 
                10, 10, 10, 1);

var v = new Point3D(1, 1, 1);
var r = Point3D.Multiply(v, m); // 11,11,11

Обратите внимание, что ваш предполагаемый ответ также неверен, так как он должен быть 10 + 1 для каждого компонента, поскольку ваш вектор равен [1,1,1].

0 голосов
/ 09 февраля 2012

Что ж, оказывается, у библиотек Matrix3D есть некоторые интересные проблемы.

Я заметил, что Vector3D.Multiply(vector, matrix) не будет переводить вектор.

Например:

var matrixTest = new Matrix3D(
    1, 0, 0, 0,
    0, 1, 0, 0,
    0, 0, 1, 0,
    10, 10, 10, 1
    );

var vectorTest = new Vector3D(1, 1, 1);

var result = Vector3D.Multiply(vectorTest, matrixTest);
// result = {1,1,1}, should be {11,11,11}

Мне пришлось переписать некоторые основные математические функции матрицы, чтобы код работал.

Все работало, кроме логической стороны, проблема заключалась в базовой математике (обрабатываемой библиотекой Matrix3D).

Вот исправление. Замените все вызовы метода Vector3D.Multiply следующим:

    public static Vector3D Vector3DMultiply(Vector3D vector, Matrix3D matrix)
    {
        return new Vector3D(
            vector.X * matrix.M11 + vector.Y * matrix.M12 + vector.Z * matrix.M13 + matrix.OffsetX,
            vector.X * matrix.M21 + vector.Y * matrix.M22 + vector.Z * matrix.M23 + matrix.OffsetY,
            vector.X * matrix.M31 + vector.Y * matrix.M32 + vector.Z * matrix.M33 + matrix.OffsetZ
            );
    }

И все работает!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...