Привет, я пытаюсь создать гибридную 2D / 3D-игру, используя коммерческий движок для разработки 2D-игр.
В игре будет серия 2D-спрайтов, которые будут отображаться на экране в зависимости от их глубины в псевдо-3D-пространстве, а не только их положения по x и y, как показано на рисунке.
Если спрайт «A» находится в точке x, y, z (150,20,100) в мире шириной 500, высотой 500 и глубиной 500, где он должен быть отображен на экране с разрешением 1024x768?
Я не могу погрузиться в глубокие теории трехмерной проекции экрана, как это делают большинство решений здесь и в Интернете. Просто основы того, где должен быть центр спрайта на экране, когда спрайт находится в точке xyz.
Может ли кто-нибудь помочь мне с необходимой логикой, учитывая сценарий на иллюстрации? Мне нравится функция на любом языке, даже псевдокод, который возвращает пару X и Y после передачи ей параметров x, y, z.
Спасибо
Вы смотрели статью Википедии "3D-проекция"? Рассмотрены три случая ...
@jhamon A) На каком языке вы лучше всего владеете? Если он у вас есть, вы можете опубликовать свое решение на этом языке.
@jhamon B) Моя проблема в том, что я ищу простой и экономичный механизм кодирования, в котором я могу вставить координаты xyz и получить обратно координаты xy. Большинство решений для 3D-проекции кажутся излишними для того, что мне нужно.
@Damien Я проверил страницу Википедии, спасибо, я просто не могу понять ее в данный момент, и у меня нет возможности преобразовать то, что там описано, в код функции, который я могу повторно использовать в своей программе




Если вам нужен простейший код и вы не хотите углубляться в матрицы, попробуйте что-нибудь вроде этого:
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 contant только потому, что вы предположили, что Z находится в диапазоне (0,500), поэтому я хотел переместить его в диапазон (0-1). Мы не хотим иметь 0 в нашем коде проекции, потому что мы будем делить на это значение, поэтому мы добавляем 1, чтобы переместить масштаб в диапазон (1-2). Не стесняйтесь изменять эти значения и смотреть, что произойдет.
Согласно вашему второму вопросу:
Я думаю, что вы переписали этот код, используя целые числа, поэтому деление на 500 отменяет ваше значение Z=100 и дает тот же результат, что и вектор Z=100. Чтобы исправить это, вы можете изменить int на float, и все должно быть в порядке. Если вы не хотите или не можете этого делать и вам нужен код для целых чисел, его нужно немного изменить:
Вместо шкалы с плавающей запятой мы можем использовать 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;
Спасибо @kolenda, это то, что я ищу, и спасибо также за включение значения шкалы в набор результатов, но что делает float perspStrength = 500.0f; значит? может ли это значение быть простым целым числом, например 500?
Я подозреваю, что причина того, что почти все решения для 3D-кодирования так быстро усложняются, заключается в том, что они попадают во вращение камеры и объектов, которые мне не нужны в моем сценарии. Камера всегда смотрит прямо, а объекты буквально плоские и визуализируются как 2D-спрайты.
kolenda, однако после его реализации я заметил, что в вашем решении положение объекта по оси Z не влияет на положение объекта по осям X и Y. Ваш код будет отображаться на объекте в позиции (100,100,100) на том же экране x, y, что и объект в позиции (100,100,0). Так быть не должно!
А) Выберите один язык. Б) Я не совсем понимаю проблему. Разве вы не можете просто удалить позицию y? Тогда это просто проблема масштабирования