Екранний простір до світового простору


10

Я пишу 2D гру, в якій у моєму ігровому світі є вісь x, що працює зліва направо, y вісь працює зверху вниз, а вісь z виходить із екрана:

введіть тут опис зображення

Поки мій ігровий світ зверху вниз, гра відображається з невеликим нахилом:

введіть тут опис зображення

Я працюю над проектом зі світового простору в простір екрану, і навпаки. У мене колишній працює наступним чином:

var viewport = new Viewport(0, 0, this.ScreenWidth, this.ScreenHeight);
var screenPoint = viewport.Project(worldPoint.NegateY(), this.ProjectionMatrix, this.ViewMatrix, this.WorldMatrix);

Метод NegateY()розширення робить саме те, що звучить, оскільки вісь y XNA проходить знизу вгору, а не зверху вниз. На знімку екрана показано, що це все працює. В основному, я маю купу точок у тривимірному просторі, які потім виводжу в просторі екрану. Я можу змінювати властивості камери в режимі реального часу і бачити, як вона оживляє нову позицію. Очевидно, що моя реальна гра використовуватиме спрайти, а не очки, і положення камери буде виправлене, але я просто намагаюся отримати всю математику на місці, перш ніж дістатися до цього.

Зараз я намагаюся перетворити назад іншим способом. Тобто, задавши точку x і y у просторі екрану вище, визначте відповідну точку у світовому просторі. Отже, якщо я вказую курсор на, скажімо, ліворуч від зеленої трапеції, я хочу отримати прочитання світового простору (0, 480). Координата z не має значення. Або, скоріше, координата z завжди буде нульовою при відображенні назад у світовий простір. По суті, я хочу реалізувати цей метод підпису:

public Vector2 ScreenPointToWorld(Vector2 point)

Я спробував декілька речей, щоб зробити це робочим, але мені просто не пощастило. Моє останнє мислення полягає в тому, що мені потрібно зателефонувати Viewport.Unprojectдвічі з різними значеннями близького / далекого z , обчислити отримане Ray, нормалізувати його, а потім обчислити перетину Rayз а, Planeщо в основному представляє рівень мого світу. Однак я застряг на останньому кроці і не був впевнений, чи надмірно ускладнюю речі.

Чи може хтось вказати мені в правильному напрямку щодо того, як цього досягти?

Відповіді:


4

Я думаю, що ваша ідея в значній мірі! Спочатку обчисліть промінь для курсору, використовуючи як близьку площу, так і дальню площину як значення Z для ваших 2D координат (тобто використовуйте 0 і 1 для своєї координати Z). Ось допоміжний метод вирішити це:

public Ray GetScreenRay(Vector2 screenPosition, Viewport viewport, Matrix projectionMatrix, Matrix viewMatrix, Matrix worldMatrix)
{
    Vector3 nearPoint = viewport.Unproject(new Vector3(screenPosition, 0f), projectionMatrix, viewMatrix, worldMatrix);
    Vector3 farPoint = viewport.Unproject(new Vector3(screenPosition, 1f), projectionMatrix, viewMatrix, worldMatrix);
    return new Ray(nearPoint, Vector3.Normalize(farPoint - nearPoint));
}

Далі вам потрібно мати Planeекземпляр, який відповідає вашим основним. Найпростіший спосіб його обчислити - скористатися конструктором, який займає три точки на площині, і передавши йому будь-які три вершини від наземного об'єкта. Приклад розрахунку площини заземлення:

Plane groundPlane = new Plane(ground.Vertices[0], ground.Vertices[1], ground.Vertices[2]);

І нарешті знайдіть точку перетину між промінням і площиною за допомогою цього методу . Ви можете використовувати параметр результату для обчислення координат перетину, як у наведеному нижче прикладі:

float? result;
mouseRay.Intersects(ref groundPlane, out result);
if(result != null)
    Vector3 worldPoint = mouseRay.Position + mouseRay.Direction * result.Value;

Можливо, вам доведеться щось зробити і щодо цього NegateYметоду, але я не знаю куди.


Це дуже корисно - дуже дякую. Це був останній рядок, який я пропав. Я не міг зрозуміти, що робити з поплавком, як тільки в мене це було! Я думаю, що мені доведеться мати ваше ім’я в моїх ігрових кредитах :)
me--

@ user13414 Дійсно, документація дещо обмежена цим методом і не дає жодного прикладу, як використовувати відстань для повернення точки перетину.
Девід Гувейя
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.