Функция проецировать xyz в xy Экранные координаты - PullRequest
0 голосов
/ 29 ноября 2018

Привет, я пытаюсь создать гибридную 2D / 3D-игру, используя коммерческий движок разработки 2D-игр.

В игре будет серия 2D-спрайтов, которые отображаются на экране в зависимости от их глубины в псевдо-3D.пробел, а не только их координаты x и y, как показано на рисунке.

enter image description here

Если спрайт "A" находится в точке x, y, z (150, 20, 100)в мире шириной 500, высотой 500 и глубиной 500, где он должен быть нанесен на экран с разрешением 1024x768?

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

Может ли кто-нибудь помочь мне с необходимой логикой, учитывая сценарий на иллюстрации?Я похож на функцию на любом языке, даже псевдокод, который возвращает пару X и Y после передачи ей параметров x, y, z.

Спасибо

1 Ответ

0 голосов
/ 29 ноября 2018

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

Vec2 screenCenter = Vec2( screensize.x/2, screensize.y/2 ); // half of your screen resolution
                                                            // try changing it to see what happens
                                                            // you can animate it to add special effects
float perspStrength = 500.0f;   // actually an inverse of perspective strength
                                // lower values means bigger effect

Vec2 project( Vec3 pos )        // projection code
{
    Vec2 localPos = pos - screenCenter; // Move point (0,0) to the center of your screen

    float scale = pos.z/perspStrength;  // scale your Z to ~(0-1) range
    scale += 1.0f;                      // move your Z to ~(1-2) range

    localPos.x /= scale;                // scale position according to Z distance
    localPos.y /= scale;

    Vec2 result = localPos + screenCenter;  // Move point (0,0) back to the corner

    return result;
//    return Vec3( result.x, result.y, scale ); // you can also return scale used for this object
                                                // so you can render distant objects as smaller
}

Я написал этот код, предполагая, что он будет использоваться со значениями с плавающей запятой.Я выбрал 500 константу только потому, что вы предполагали, что Z находится в диапазоне (0,500), поэтому я хотел переместить его в (0-1) диапазон.Мы не хотим иметь 0 в нашем коде проекции, потому что мы будем делиться на это значение, поэтому мы добавляем 1, чтобы переместить масштаб в диапазон (1-2).Не стесняйтесь изменить эти значения и посмотрите, что произойдет.

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

Вместо шкалы с плавающей запятой мы можем использовать int и представить шкалу в 1 /1000 единиц, поэтому базовая шкала будет 1000.

Самый простой способ получить шкалу:

int scale = 1000 - pos.z;

Если вам нужно масштабирование эффекта перспективы, вы можете использовать его вместо:

int perspStrength = 100;
int scale = 1000 - (pos.z*perspStrength/100);

Теперь, когда у вас есть scale в 1/1000 единицах, вы можете масштабировать свои векторы:

localPos.x = localPos.x * scale / 1000;
localPos.y = localPos.y * scale / 1000;
...