3D Point to 2D Function не работает должным образом - PullRequest
0 голосов
/ 22 мая 2018

Я уже некоторое время изучаю эту тему и, наконец, пытаюсь реализовать ее самостоятельно;однако по какой-то причине 3d-точка не преобразуется в 2d-точку правильно, что означает, что моя функция возвращает неправильное значение.Это может быть из двух разных случаев:

1) Моя математика неверна

2) Моя матрица имеет неправильные значения

Поскольку я обращаюсь и использую адреса, яне уверены в матрице.Возможно ли, чтобы кто-то проверил мою математику, чтобы узнать, является ли она неправильной?Любая помощь по этой функции будет оценена.Заранее благодарю за любой совет.

private bool ConvertToScreen(Vector3 position3D, ref Point screenPoint)
    {

    // r is the right rotation (x-axis)
    // u is the up rotation (y-axis)
    // f is the forward rotation (z-axis)
    // p is the position (transform)

        Point returnPoint = new Point(300, 400);

        // Set Values of Matrix
        Matrix matrix = GetMatrix();

        // Do the math calculations here
        float xPrime = matrix.rX * position3D.x + matrix.rY * position3D.y + matrix.rZ * position3D.z + matrix.rW;
        float yPrime = matrix.uX * position3D.x + matrix.uY * position3D.y + matrix.uZ * position3D.z + matrix.uW;
        // Dont need zPrime
        float wPrime = matrix.pX * position3D.x + matrix.pY * position3D.y + matrix.pZ * position3D.z + matrix.pW;

        // If wPrime > 0 we can see the point
        if (wPrime <= 0)
        {
            return false;
        }
        xPrime *= 1 / wPrime;
        yPrime *= 1 / wPrime;

        // Relative To Screen Center
        xPrime = rect.left + 0.5f * xPrime * (rect.right - rect.left) + 0.5f;
        yPrime = rect.top + 0.5f * yPrime * (rect.bottom - rect.top) + 0.5f;

        returnPoint = new Point((int)xPrime, (int)yPrime);

        screenPoint = returnPoint;

        return true;
    }

1 Ответ

0 голосов
/ 22 мая 2018

Есть несколько шагов к этому вычислению, и я советую разбить его на соответствующие секции и проверить каждый из них.

  1. Модель с координатами камеры - Этоэто поворот position = (x,y,z) точек из координат модели в координаты камеры.Здесь мы предполагаем, что цель камеры находится в начале координат.

    local = rot * (position - target)
    
    | x' |   | rx ry rz |   | x |   | rx*x + ry*y + rz*z |
    | y' | = | ux uy yz | * | y | = | ux*x + uy*y + uz*z |
    | z' |   | fx fy fz |   | z |   | fx*x + fy*y + fz*z |
    
  2. Перспективная проекция - Вам необходимо определить расстояние между целью и камерой, а также размер модели, которая будет охватыватьПосмотреть.Давайте назовем их, distance и size.Результат - координаты вида, которые варьируются между 0..1 как по x, так и по y.

    | vx |    | (distance/size)*(x'/(distance+z')) |
    |    | =  |                         |          |
    | vy |    | (distance/size)*(y'/(distance+z')) |
    

    Это происходит из похожих треугольников.Если x'=size и z'=0, то vx=1.Чем больше z', тем меньше становится vx.

  3. Пиксельные координаты

    Здесь вы отображаете координаты вида в пикселях.Ваш видовой экран имеет width и height, и вы хотите [0,0] пикселей в левом верхнем углу и [width-1,height-1] в правом нижнем углу.

           width
    +-------------------+
    |(-1,1)   :    (1,1)|
    |         :         |
    |         : (0,0)   |
    +- - - - -+- - - - -+ height
    |         :         |
    |         :         |
    |(-1,-1)  :   (1,-1)| 
    +-------------------+
    
    px = (width-1)*(vx+1.0)/2.0
    py = (height-1)*(1.0-vy)/2.0
    

Наконец,Я рекомендую использовать программирование ООП (если возможно), чтобы отделить математику вектора / матрицы от цели.Рассмотрим следующий пример в .

    public static Vector3 ThroughCamera(Vector3 point, Vector3 target, Matrix3 camera)
    {
        return camera.Transpose()*(point-target);
    }

    public static Vector2 Perspective(Vector3 point, double distance, double size=1)
    {
        return new Vector2(
            (distance/size)*(point.X/(distance+point.Z)),
            (distance/size)*(point.Y/(distance+point.Z)) );
    }
    public static PointF Pixel(Vector2 point, int width, int height)
    {
        return new PointF(
            (float) ((width-1)*(point.X+1)/2),
            (float) ((height-1)*(1-point.Y)/2) );
    }

    static void dlg_Paint(object sender, PaintEventArgs e)
    {
        Form dlg=sender as Form;
        // Set camera rotation
        Matrix3 camera=Matrix3.Ry(0.67);
        double distance=25;
        double size=20;

        for(int i=0; i<10; i++)
        {
            for(int j=0; j<10; j++)
            {
                // this is the model points
                Vector3 pt=new Vector3(5*(i-5), 5*(j-5), 0);
                // these are the points through the camera
                Vector3 pt_local=ThroughCamera(pt, Vector3.O, camera);
                // these are the view coordinates
                Vector2 pt_view=Perspective(pt_local, distance, size);
                // these are the pixel coordinates
                PointF px=Pixel(pt_view, dlg.ClientSize.Width, dlg.ClientSize.Height);

                e.Graphics.DrawRectangle(Pens.Blue, px.X, px.Y, 1f, 1f);
            }
        }            
    }

scr

...