gluLookAt и glFrustum с движущимся объектом - PullRequest
3 голосов
/ 12 октября 2011

Исходный вопрос / код

Я тонко настраиваю рендеринг для 3D-объекта и пытаюсь установить камеру, следуя за объектом, используя gluLookAt, поскольку положение центра y у объекта постоянно увеличиваетсякак только он достигает своей максимальной высоты.Ниже приведен раздел кода, в котором я настраиваю матрицы ModelView и Projection:

float diam = std::max(_framesize, _maxNumRows);
float centerX = _framesize / 2.0f;
float centerY = _maxNumRows / 2.0f + _cameraOffset;
float centerZ = 0.0f;
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glFrustum(centerX - diam,
          centerX + diam,
          centerY - diam,
          centerY + diam,
          diam,
          40 * diam);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(0., 0., 2. * diam, centerX, centerY, centerZ, 0, 1.0, 0.0);

В настоящее время объект отображается очень далеко и, кажется, перемещается дальше назад на экран (-z) и вниз (-y)пока он в конечном итоге не исчезнет.

Что я делаю не так?Как заставить мою поверхность отображаться в центре экрана, занимая полный обзор и перемещая камеру вместе с объектом по мере его обновления?


Обновленный код и текущая проблема

Это мой текущий код, который теперь помещает мертвую точку объекта и заполняет мое окно.

float diam = std::max(_framesize, _maxNumRows);
float centerX = _framesize / 2.0f;
float centerY = _maxNumRows / 2.0f + _cameraOffset;
float centerZ = 0.0f;
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(centerX - diam,
          centerX,
          centerY - diam,
          centerY,
          1.0,
          1.0 +  4 * diam);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(centerX, _cameraOffset, diam, centerX, centerY, centerZ, 0, 1.0, 0.0);

У меня все еще есть одна проблема, когда просматриваемый объект начинает двигатьсяоно не остается идеально отцентрированным.Похоже, что он почти дрожит вверх на пиксель, а затем уменьшается на 2 пикселя при обновлении.В конце концов объект покидает текущий вид.Как я могу решить этот джиттер?

Ответы [ 3 ]

5 голосов
/ 13 октября 2011

Ваша проблема с пониманием того, что делает проекция. В вашем случае glFrustum . Я думаю, что лучший способ объяснить glFrustum - это рисунок (я только что нарисовал - от руки). Вы начинаете пространство под названием Eye Space . Это пространство, в котором находятся ваши вершины после того, как они были преобразованы матрицей modelview . Это пространство необходимо преобразовать в пространство под названием Нормализованные координаты устройства пространство. Это происходит в два этапа:

  1. Глазное пространство преобразуется в Клип-пространство посредством проекции (матрицы)
  2. Деление перспективы {X, Y, Z} = {x, y, z} / w применяется, принимая его в Нормализованная координата устройства пробел.

Видимый эффект этого - своего рода «линза» OpenGL. На рисунке ниже вы можете видеть зеленую выделенную область (технически это 3 тома) в пространстве глаза, то есть пространство NDC, обратно спроецированное в нее. В верхнем регистре показан эффект симметричного усеченного конуса, то есть left = -right, top = -bottom. На нижнем рисунке показан асимметричный усеченный элемент, то есть left ≠ -right, top ≠ -bottom.

The effect of glFrustum

Обратите внимание, что применение такой асимметрии (по смещению вашего центра) не повернется, то есть повернет усеченный конус, но сместит его. Однако «камера» останется в начале координат, все еще указывая вниз по оси -Z. Конечно, центр проекции изображения сместится, но это не то, что вам нужно в вашем случае.

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

2 голосов
/ 13 октября 2011

Ответ Никола Боласа в значительной степени говорит о том, что вы делаете неправильно, поэтому я пропущу это. Вы ищете решение, а не говорите, что не так, поэтому давайте сразу же приступим к нему.

Это код, который я использую для матрицы проекции:

glViewport(0, 0, mySize.x, mySize.y);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(fovy, (float)mySize.x/(float)mySize.y, nearPlane, farPlane);

Несколько слов, чтобы описать это: glViewport устанавливает размер и положение места отображения для openGL внутри окна. Не знаю почему, я всегда включаю это для обновления прогноза. Если вы используете его как я, где mySize - это 2D вектор, определяющий размеры окна, область рендеринга openGL будет занимать все окно. Вы должны быть знакомы с 2 следующими звонками и, наконец, gluPerspective. Первый параметр - это ваше «поле зрения по оси Y». Он определяет угол в градусах, который вы увидите, и я никогда не использовал ничего, кроме 45. Хотя он может быть использован для масштабирования, но я предпочитаю оставить это для работы камеры. Второй параметр аспект. Он обрабатывает то, что если вы рендерите квадрат, а размеры вашего окна не будут в соотношении 1: 1, он будет по-прежнему квадратным. Третий - около плоскости отсечения, геометрия ближе к камере не будет отображаться, то же самое с farPlane, но, напротив, он устанавливает максимальное расстояние, в котором отображается геометрия.

Это код для матрицы вида модели

glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(  camera.GetEye().x,camera.GetEye().y,camera.GetEye().z,
camera.GetLookAt().x,camera.GetLookAt().y,camera.GetLookAt().z,
camera.GetUp().x,camera.GetUp().y,camera.GetUp().z);

И снова кое-что, что вы должны знать: опять же, вы можете использовать первые 2 вызова, поэтому мы переходим к gluLookAt. У меня есть класс камеры, который обрабатывает все движения, вращения и тому подобное. Eye, LookAt и Up являются трехмерными векторами, и эти 3 - действительно все, на что указывает камера. Глаз - это положение камеры, в которой оно находится в пространстве. LookAt - это положение объекта, на который вы смотрите, или лучше точки в трехмерном пространстве, на которую вы смотрите, потому что это может быть где угодно, а не просто центр объекта. И если вы беспокоитесь о том, что такое Up vector, это действительно просто. Вектор перпендикулярен вектору (LookAt-Eye), но поскольку таких векторов бесконечное количество, вы должны указать один. Если ваша камера находится на (0,0,0), а вы смотрите на (0,0,-1), и вы хотите стоять на ногах, вектор вверх будет (0,1,0). Если вы хотите встать на голову вместо этого, используйте (0,-1,0). Если вы не поняли идею, просто напишите в комментарии.

Поскольку у вас нет класса камеры, вам нужно хранить эти 3 вектора отдельно. Я считаю, что у вас есть что-то вроде центра 3D-объекта, который вы перемещаете. Установите эту позицию как LookAt после каждого обновления. Также на этапе инициализации (когда вы создаете 3D-объект) выберите положение камеры и вектор вверх. После каждого обновления положения объекта обновляйте положение камеры таким же образом. Если вы переместите свой объект на 1 точку вверх по оси Y, сделайте то же самое с положением камеры. Верхние векторы остаются постоянными, если вы не хотите вращать камеру. И после каждого такого обновления звоните gluLookAt с обновленными векторами.

Для обновленного сообщения: Я действительно не понимаю, что происходит без большей системы отсчета (но я все равно не хочу это знать). Есть несколько вещей, которые меня интересуют. Если центр - это трехмерный вектор, в котором хранится положение вашего объекта, почему вы устанавливаете центр этого объекта в правом верхнем углу окна? Если это центр, у вас должны быть эти + diam также во 2-м и 4-м параметре glOrtho, и если дела идут плохо, вы используете неправильные имена для переменных или делаете что-то где-то до того, как это неправильно. Вы устанавливаете положение LookAt прямо в своем обновленном сообщении, но я не понимаю, почему вы используете эти параметры для Eye. У вас должно быть что-то вроде: centerX, centerY, centerZ-diam в качестве первых 3 параметров в gluLookAt. Это дает вам камеру в том же положении X и Y, что и ваш объект, но вы будете смотреть на нее вдоль оси Z с расстояния diam

2 голосов
/ 12 октября 2011

Матрица перспективной проекции, сгенерированная glFrustum, определяет пространство камеры (пространство вершин, которое она принимает в качестве входных данных) с камерой в начало координат . Вы пытаетесь создать перспективную матрицу с камерой, которая не находится в начале координат. glFrustum не может этого сделать, поэтому способ, которым вы пытаетесь это сделать, просто не сработает.

Существуют способы создания матрицы перспективы, когда камера не находится в исходной точке. Но в этом нет никакого смысла.

Способ, которым обычно обрабатывается движущаяся камера, заключается в простом добавлении преобразования из мирового пространства в пространство камеры перспективной проекции. Это просто вращает и переводит мир в соответствии с камерой. Это работа gluLookAt. Но ваши параметры к этому тоже неверны.

Первые три значения - это местоположение камеры в мировом пространстве. Следующие три должны быть местоположением в мировом пространстве, на которое должна смотреть камера (положение вашего объекта).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...