Функция, которую вы определили, не имеет обратной. Например, пользователь 207422 уже указал, что все, что находится на расстоянии 100 единиц от камеры, будет отображено в (xa, ya) = (0,0), поэтому обратное не определено однозначно.
Что более важно, это не то, как вы рассчитываете перспективу. Обычно коэффициент масштабирования перспективы определяется как viewdist/zdist
, где zdist
- это перпендикулярное расстояние от камеры до объекта, а viewdist
- это константа, которая представляет собой расстояние от камеры до гипотетического экрана, на который проецируется все , (См. Диаграмму здесь , но не стесняйтесь игнорировать все остальное на этой странице.) Коэффициент масштабирования, который вы используете в своем примере, не имеет такого поведения.
Вот попытка преобразовать ваш код в правильный расчет перспективы (заметьте, я не упрощаю до 2D; перспектива - это проецирование трех измерений в два, попытка упростить задачу до 2D - это бессмысленно):
camera = new MapPoint(60, 60, 10);
camera_z = camera.x*zDistX + camera.y*zDistY + camera.z*zDistz;
// viewdist is the distance from the viewer's eye to the screen in
// "world units". You'll have to fiddle with this, probably.
viewdist = 10.0;
xa = mapP.x*xDistX + mapP.y*xDistY + mapP.z*xDistZ;
ya = mapP.x*yDistX + mapP.y*yDistY + mapP.z*yDistZ;
za = mapP.x*zDistX + mapP.y*zDistY + mapP.z*zDistZ;
zdist = camera_z - za;
scaling_factor = viewdist / zdist;
xa *= scaling_factor;
ya *= scaling_factor;
Вы только вернете xa
и ya
из этой функции; za
только для перспективного расчета. Я предполагаю, что «za-direction» указывает за пределы экрана, поэтому, если ось x предварительного проецирования указывает на зрителя, то zDistX
должно быть положительным и наоборот, и аналогично для zDistY
. Для триметрической проекции вы, вероятно, имели бы xDistZ==0
, yDistZ<0
и zDistZ==0
. Это сделает точку предварительного проецирования по оси z прямой после проекции.
Теперь плохие новости: эта функция также не имеет обратной. Любая точка (xa, ya) является изображением бесконечного числа точек (x, y, z). Но! Если вы предполагаете, что z = 0, то вы можете решить для x и y, что, возможно, достаточно хорошо.
Для этого вам понадобится некоторая линейная алгебра. Вычислить camera_x
и camera_y
аналогично camera_z
. Это координаты камеры после преобразования. Точка на экране имеет посттрансформационные координаты (xa,ya,camera_z-viewdist)
. Проведите линию через эти две точки и вычислите, где in пересекается с плоскостью, натянутой на векторы (xDistX, yDistX, zDistX)
и (xDistY, yDistY, zDistY)
. Другими словами, вам нужно решить уравнения:
x*xDistX + y*xDistY == s*camera_x + (1-s)*xa
x*yDistX + y*yDistY == s*camera_y + (1-s)*ya
x*zDistX + y*zDistY == s*camera_z + (1-s)*(camera_z - viewdist)
Это не красиво, но это будет работать.