Проецирование 3D-вектора в координаты 2D-экрана

Я использую XNA 4.0 и пытаюсь взять Vector3 и превратить его в Vector2, который представляет его координаты на экране. Я знаю, что вы можете использовать Viewport.Project, и это дает мне отличные результаты, но мне нужно сделать свой собственный метод для этого. Мне нужно преобразовать каждую вершину в 2D-координаты за кадр и на процессоре, а не на графическом процессоре. Использование предоставленного метода Project немного медленнее, чем хотелось бы. Он также возвращает значение «z», которое я даже не буду использовать. Я просто хочу вернуть (x, y) самым простым способом.

Вот что я придумал до сих пор, и это дает почти правильные результаты. Но еще не совсем там

    private Vector2 ScreenCoords(Vector3 v)
    {
        return new Vector2(
            viewProj.M11 * v.X + viewProj.M21 * v.Y + viewProj.M31 * v.Z + viewProj.M41,
            viewProj.M12 * v.X + viewProj.M22 * v.Y + viewProj.M32 * v.Z + viewProj.M42);
    }

viewProj просто (viewMatrix * ProjectionMatrix)

Вершина в центре экрана, кажется, всегда возвращается как (0, 0), но я получаю немного испорченные результаты, поскольку вершина меняет координаты экрана (когда я перемещаю камеру). Когда вершина перемещается влево, X моего проецируемого результат уменьшается, и по мере того, как вершина движется вниз, Y моего прогнозируемого результата увеличивается. Так что, по крайней мере, у меня есть это право, но скорость, с которой они меняются, неверна или постоянна.

РЕДАКТИРОВАТЬ: вот как это делается, вероятно, самый быстрый способ сделать это (обратите внимание, что это возвращает координаты в диапазоне [-1, 1])

    private Vector2 ScreenCoords(Vector3 v) 
    {
        float 
            w = viewProj.M14 * v.X + viewProj.M24 * v.Y + viewProj.M34 * v.Z + viewProj.M44;
        return new Vector2(
            (viewProj.M11 * v.X + viewProj.M21 * v.Y + viewProj.M31 * v.Z + viewProj.M41) / w,
            (viewProj.M12 * v.X + viewProj.M22 * v.Y + viewProj.M32 * v.Z + viewProj.M42) / w);          
    }

Вот сравнение с использованием Viewport.Project для получения 2D-координат -
FPS с Project - 81
FPS с ScreenCoords - 143
FPS без любого из них - 152
Так что я бы рекомендовал что-то вроде этого для всех, кто много проецирует на кадр.


person Frobot    schedule 07.05.2012    source источник


Ответы (1)


Вы должны понимать, что перспективные проекции нуждаются в однородных координатах, вы должны разделить

компоненты хоумогенным фактором W.

Это математика:

Vector4 position = new Vector4(pos3, 1);
Vector4.Transform(ref position, ref worldViewProjection, out position);
position /= position.W;

Также вы можете найти дополнительную информацию здесь: http://en.wikipedia.org/wiki/Transformation_matrix#Perspective_projection

person Blau    schedule 07.05.2012
comment
Это дало мне то, что мне было нужно, спасибо! Я пытаюсь избежать использования таких вещей, как преобразование и проект, и получить ответ, используя собственную математику, но это привело меня туда. Публикация нового метода вверху, если кому-то это нужно. - person Frobot; 07.05.2012
comment
Хорошо знать, за чем стоит математика, но я думаю, что это преобразование используется для более эффективного выполнения его внутри шейдера. - person Blau; 07.05.2012
comment
Да, и преобразование также получает значение для этого пикселя в z-буфере, который я вырезал, так как он мне не понадобится. Надеюсь, я смогу реализовать весь свой алгоритм внутри шейдера, и тогда мне даже не нужно будет находить координаты 2D-экрана на процессоре, и это будет НАМНОГО быстрее. - person Frobot; 07.05.2012