Direct3D находит координаты 2D экрана, но зеркальный сбой при стрессе - PullRequest
0 голосов
/ 16 декабря 2018

У меня есть эта функция, чтобы получить положение 2D пикселя из положения 3D координат.Xyz - это координаты перед преобразованием (от 1 до -1).Это архитектура модельного вида с камерой постоянно -3,5,0,0, смотрящей на 0,0,0, в то время как координаты объекта / сцены преобразуются с помощью горизонтального поворота по оси x и вертикального поворота по оси y и т. Д., Чтобы получить окончательный кадр.

Эта функция в основном используется для наложения 2D-текста поверх 3D-сцены.Где 2D-текст расположен относительно базовой 3D-сцены.

void My3D::Get2Dfrom3Dx(float x, float y, float z, float* psx, float* psy)  {

    XMVECTOR xmScreenCoord = XMLoadFloat3( (XMFLOAT3*) &screenCoord);
    XMMATRIX xmWorldViewProjection = XMLoadFloat4x4( (XMFLOAT4X4*) &m_WorldViewProjection);
    XMVECTOR result = XMVector3TransformCoord( xmScreenCoord, xmWorldViewProjection);
    XMStoreFloat3( (XMFLOAT3*) &screenCoord, result);

    screenCoord.x = ((screenCoord.x + 1.0f) / 2.0f) * m_nCurrWidth;
    screenCoord.y = ((-screenCoord.y + 1.0f) / 2.0f) * m_nCurrHeight;

*psx = screenCoord.x;
*psy = screenCoord.y; }

Эта функция отлично работает, когда сцена полностью / в основном видна (угол между -4 и -1,5.)

У меня возникает неприятная проблема с отображением текста в зеркальном отображении в3D положение, где оно не должно быть.Это происходит, когда, например, я просматриваю изображение снизу (на 60+ градусов вверх под объектом) и масштабирую (перемещая расположение глаза ближе к -5,0,0.). Текст не должен быть виден так, как долженнаходиться за глазом (обратите внимание, что угол глаза не превышает 0,0,0, что действительно портит изображение), но каким-то образом вышеуказанная функция заставляет вычисленные координаты xy экрана показывать в области просмотра в ситуациях, когда они не должны этого делать.

Кажется, я думаю, что есть простое решение этого побочного эффекта, но не могу его найти.Надеюсь, кто-то уже видел эту 2d зеркальную проблему / эффект и знает простой твик.

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

Опять же, камера постоянно находится на линии -3,5, 0, 0, скажем -,5,0,0, поскольку мир вокруг нее трансформируется.

Ответы [ 2 ]

0 голосов
/ 24 декабря 2018

Ответ Майкла очень помог мне продвинуться по пути, по которому решение должно быть простым сравнением.В моем случае мне пришлось переоценивать координаты экрана, применяя только преобразование World, а не WorldViewProjection.Я называю это TargetTransformed.Тогда моим значением сравнения было просто расположение Глаз / Камера (это никогда не корректируется (кроме масштабирования), так как мир трансформируется вокруг Глаза.) И снова обратите внимание, что моя Камера в этом случае составляет -3,5,0,0, смотря на 0,0,0 (центр модели, реально 8,0,0 при этом линия через центр).Поэтому мне пришлось сравнивать компонент x, а не компонент z.Я добавляю немного помадки .1F, поскольку зеркальный артефакт возникает, когда цель значительно отстает от камеры.В этом случае я возвращаю окончательные местоположения screenCoord, переведенные (-8000) в космическое пространство, чтобы гарантировать, что они не видны в окне просмотра.

if ((Eye.x + 0.1F) > TargetTransformed.x) 
{
    screenCoord.x += -8000;
    screenCoord.y += -8000;
    //TRACE("point is behind camera.\n");
    *psx = screenCoord.x;
    *psy = screenCoord.y;
}
else
{
    *psx = screenCoord.x;
    *psy = screenCoord.y;
}

И для полноты, в моем проекте есть 2 модели вида: a) просматривая линию через центр модели.Который это можно перевести, чтобы посмотреть с любого направления и сместить на экране х и у.Модель первого вида отлично работает с этим кодом.Модель второго вида b) нацеливает камеру на фокусную точку модели, а затем обеспечивает полный поворот вокруг этой случайной точки (не центра модели), что требует вычисления сложной дополнительной матрицы перевода и вектора, который я называю TargetViewTranslation.И для этого дополнительного перевода формула добавляет компонент z дополнительного преобразования.

if ((Eye.x + 0.1F - m_structTargetViewTranslation.Z) > TargetTransformed.x) 
{
    screenCoord.x += -8000;
    screenCoord.y += -8000;
    //TRACE("point is behind camera.\n");
    *psx = screenCoord.x;
    *psy = screenCoord.y;
}
else
{
    *psx = screenCoord.x;
    *psy = screenCoord.y;
}

И успешно, моя проблема с зеркальным текстом решена.Надеюсь, это поможет другим с этой проблемой зеркального текста.Понимая, что может потребоваться преобразовать только контрольный пример с помощью преобразования World, и это должно быть простое сравнение, и расположение камеры может повлиять на то, какой компонент x или z используется.И если вы переводите мир любыми дополнительными способами, то этот перевод также может повлиять на сравнение значений x или z.Использование TRACE и просмотр значений xyz помогли выяснить, какие компоненты мне нужно было использовать в моем конкретном случае.

0 голосов
/ 16 декабря 2018

Проблема заключается в том, как работает проекция.По сути, перспективная проекция разделит координаты x и y на координату z.Вот как вы получаете эффект перспективы, то есть то, что вещи, которые находятся дальше (большая координата z), выглядят на экране меньше.Одна проблема с этим перспективным делением (упрощенная) заключается в том, что он не работает правильно для вещей, которые находятся за камерой.Материал за камерой будет иметь отрицательную координату Z.Когда вы разделите x и y на отрицательное значение, ваша точка будет отражена вокруг начала координат.Что именно то, что вы видите.Поскольку материал, расположенный за камерой, в любом случае не будет виден, один из способов решения этой проблемы - просто обрезать всю геометрию перед делением на z, чтобы все, что имеет отрицательное значение z, было обрезано и удалено.

Я полагаю, что разделение в вашем коде происходит внутри XMVector3TransformCoord().Как вы сами отметили, текст в проблемных случаях не должен быть виден в любом случае.Поэтому я предлагаю вам просто проверить, находится ли текст за камерой, и не отображать его, если он есть.Один из способов сделать это - просто проверить результат преобразования вашей позиции в мировом пространстве с помощью матрицы xmWorldViewProjection и продолжить, только если он окажется перед камерой.xmScreenCoord содержит однородные координаты пространства клипа вашей точки.Точка будет перед камерой, если координата z xmScreenCoord больше нуля.Поэтому я думаю, вы захотите сделать что-то вроде

if (XMVectorGetZ(xmScreenCoord) > 0)
{
    …
}

Sidenote из-за обсуждения в комментариях ниже: Когда кто-то хочет решить проблему, связанную с проекцией объектов на экран, часто можно явно избежатьвычисляя проекцию, вместо этого превращая задачу в двойственную и работая непосредственно в проективном пространстве на однородных координатах.Так как ваша проблема заключается в размещении текста в 2D на экране, я не думаю, что это вариант здесь.Вы можете разместить геометрию для рисования вашего текста непосредственно в пространстве клипа.Вы начнете снова с вычисления координат пространства клипа трехмерной точки, к которой вы хотите прикрепить 2D-текст (умножив их на m_WorldViewProjection, но не разделив на w).Затем вы можете сгенерировать однородные координаты для геометрии для рисования вашего текста, просто сместив координаты x и y от этой точки, чтобы получить углы четырехугольника или все, что вам нужно построить.Если затем вы также масштабируете размер квадра по координате w точки, вы получите квад в этой позиции, который проецирует на экран всегда одинаковый размер (так как предварительное умножение с w эффективно отменяет проекцию).Тем не менее, все, что вы фактически делаете, это оставляете приложение проекции и обязательно привязываетесь к графическому процессору.Если вы хотите визуализировать большое количество четырехугольников, это можно рассмотреть, так как это можно сделать полностью на GPU, например, с помощью геометрического шейдера.Однако, если у вас есть только несколько текстовых элементов, было бы намного проще и, возможно, также более эффективно просто пропустить рисование текстовых элементов, которые будут позади камеры, как описано выше…

...