gluUnProject возвращает неточную координату z при некоторых условиях

Я получаю некоторые проблемы с gluUnProject, потому что получаю неточную координату Z.

Привлекательная программа - это, в основном, 3D-просмотрщик. Я реализовал небольшую функцию, позволяющую пользователю щелкнуть по загруженной модели и получить расстояние между двумя точками.

Это код:

//  Declare variables for viewport, modelview and projection matrix
int viewport[] = new int[4];
float modelview[] = new float[16];
float projection[] = new float[16];
//  GL y-coordinate position
int realY;
//  Returned [wx, wy, wz, 1] coordinates
float worldCoordinates[] = new float[4];

gl2.glGetIntegerv(GL2.GL_VIEWPORT, viewport, 0);
gl2.glGetFloatv(GL2.GL_MODELVIEW_MATRIX, modelview, 0);
gl2.glGetFloatv(GL2.GL_PROJECTION_MATRIX, projection, 0);

//  Retrive the Y coordinate, note viewport[3] is height of window in pixels
realY = viewport[3] - click.y - 1;

//  Allocate a buffer to store the result
FloatBuffer fb = FloatBuffer.allocate(1);

//  Retrieve the Z coordinate, read a block of pixels from the frame buffer
gl2.glReadPixels(click.x, realY, 1, 1, GL2.GL_DEPTH_COMPONENT, GL2.GL_FLOAT, fb);

System.out.println("Depth: "+fb.get(0));

//  Avoid centering if the click is on nothing
if (fb.get(0) == 1.0f) {
    return null;
}
//  Map window coordinates to object coordinates, retrieve the world coordinates
glu.gluUnProject(click.x, realY, fb.get(0), modelview, 0, projection, 0,
            viewport, 0, worldCoordinates, 0);

Когда я измеряю расстояние между двумя точками, лежащими на поверхности, перпендикулярной пользователю, все работает правильно. Если мы изображаем систему с тремя осями, причем z указывает на пользователя, а y - вверх, две точки лежат на плоскости XY. Он работает независимо от вращения вокруг Z.

enter image description here

Например, здесь я создал небольшую квадратную плоскость, и обе точки имеют одинаковую высоту (одна затенена меткой):

Мировые координаты P1: (0,019062456, 0.03357359, 0.08333321, 1)

Координаты мира P2: (0,025983132, 0.028048635, 0.08333321, 1)

Но если я поворачиваю всю сцену по глобальным осям X, то измененные координаты Z меняются:

enter image description here

Координаты X и Y не имеют значения, что важно для Z. Это не более 0.08333321.

Мировые координаты P1: (0.026863147, 0.027185505, 0.0831252, 1)

Мировые координаты P2: (0.020072304, 0.034560144, 0.08312501, 1)

Более того, после поворота по глобальному X масштабирование влияет на координату Z точек.

Ps: Я использую JOGL. Увеличение и уменьшение масштаба выполняется путем увеличения/уменьшения параллелепипеда glOrtho. Глубина Z, создаваемая glReadPixels, fb.get (0), включена в [0, 1].

Где я ошибаюсь?

1
добавлено отредактировано
Просмотры: 2
nl ja de

1 ответы

Ожидаете ли вы видеть точную координату точки на своем самолете? Ты не получишь это так.

Когда вы представляете свой квадрат, координаты преобразуются в 3D, а примитивный растрированный (т. Е. Преобразованный в 2D и интерполированный), генерирующий экран X, Y и (как правило) 24-битное значение глубины. Это довольно потеря точности (и она даже не линейна), поэтому, если вы ее прочитали и инвертируете преобразование, вы получите приблизительное значение к исходному значению.

Если ваш многоугольник окажется перпендикулярным направлению просмотра, интерполяция по крайней мере даст согласованное значение z по всей поверхности (так как все преобразованные значения Z одинаковы), хотя это не обязательно будет right z-значение. Поэтому любое изменение глубины приведет к изменению ошибки, и если ваша плоскость не перпендикулярна, она перестает быть согласованной по всему полю.

Глубина в основном достаточно хороша для рисования без слишком большого количества ошибок (и даже тогда, не всегда), но не для восстановления точной геометрии.

Если вам нужны лучшие результаты, вы можете растрировать фактическое пространство модели X, Y, Z на (плавающее) FBO с помощью шейдера и прочитать это обратно. Альтернативно, пересечь луч с вашей геометрией в программном обеспечении.

1
добавлено
Спасибо JasonD за ваш ответ, это подтвердило мой главный страх: ошибка аппроксимации/интерполяции. Тем не менее, было бы достаточно всего лишь плавающего FBO, чтобы улучшить ситуацию? Как я могу проверить, какой из них я использую в данный момент?
добавлено автор elect, источник
Нет, я использую оппортунистический FBO. Поэтому вы предлагаете мне создать дополнительный FBO с определенным форматом (float). Я сейчас ищу работу в Google, но я не могу найти что-то полезное/конкретное для моих целей, есть ли у вас какая-нибудь хорошая ссылка? (создание плавающего FBO)
добавлено автор elect, источник
Если вы явно не сделали FBO, вы просто будете рендерить в окно. Так что, вероятно, это всего лишь 8-битный буфер для каждого канала. В любом случае, я предлагаю дополнительный буфер, который может хранить необходимую информацию, непосредственно в более подходящем формате и пространстве. Стоит ли делать (или достаточно), зависит от ваших точных требований.
добавлено автор JasonD, источник
У меня нет ничего, что можно было бы передать, хотя я делал это в прошлом, когда мне было нужно что-то похожее на ваше дело. Я использовал полные 4-канальные плавающие FBOs, GL_RGBA32F. Они довольно большие, хотя вам может потребоваться только отображение подмножества вашего дисплея, если вы просто захватываете отдельные пиксели.
добавлено автор JasonD, источник