Я делаю приложение OpenGL С++, которое отслеживает местоположение пользователей по отношению к экрану, а затем обновляет отображаемую сцену с точки зрения пользователя. Это известно как «настольная виртуальная реальность», или вы можете думать об экране как о диораме или аквариуме. Я новичок в OpenGL и до сих пор определил только очень простую сцену, просто куб, и изначально он отображается правильно.
Проблема в том, что когда я начинаю двигаться и хочу перерендерить кубическую сцену, плоскость проекции кажется переведенной, и я не вижу того, что, по моему мнению, должен. Я хочу, чтобы этот самолет починили. Если бы я писал трассировщик лучей, мое окно всегда было бы фиксированным, но мой глаз мог блуждать. Может кто-нибудь объяснить мне, как я могу добиться желаемого эффекта (закрепить окно просмотра), когда моя камера/глаз блуждают по координате, отличной от исходной?
Все примеры, которые я нахожу, требуют, чтобы камера/глаз находились в начале координат, но это концептуально неудобно для меня. Кроме того, поскольку это «аквариум», я устанавливаю d_near на плоскость xy, где z = 0.
В пространстве экрана/мира я назначаю центр экрана на (0,0,0) и его 4 угла на: TL(-44.25, 25, 0) TR( 44.25, 25, 0) BR( 44.25,-25 , 0) BL(-44,25,-25, 0) Эти значения указаны в сантиметрах для дисплея 16x9.
Затем я рассчитываю глаз пользователя (фактически веб-камеру на моем лице), используя POSIT, чтобы он обычно находился где-то в диапазоне (+/-40, +/-40, 40-250). Мой метод POSIT точен.
Я определяю свои собственные матрицы для преобразования перспективы и просмотра, а также использую шейдеры.
Я инициализирую следующим образом:
float right = 44.25;
float left = -44.25;
float top = 25.00;
float bottom = -25.00;
vec3 eye = vec3(0.0, 0.0, 100.0);
vec3 view_dir = vec3(0.0, 0.0, -1.0);
vec3 up = vec3(0.0, 1.0, 0.0);
vec3 n = normalize(-view_dir);
vec3 u = normalize(cross(up, n));
vec3 v = normalize(cross(n, u));
float d_x = -(dot(eye, u));
float d_y = -(dot(eye, v));
float d_z = -(dot(eye, n));
float d_near = eye.z;
float d_far = d_near + 50;
// perspective transform matrix
mat4 P = mat4((2.0*d_near)/(right-left ), 0, (right+left)/(right-left), 0,
0, (2.0*d_near)/(top-bottom), (top+bottom)/(top-bottom), 0,
0, 0, -(d_far+d_near)/(d_far-d_near), -(2.0*d_far*d_near)/(d_far-d_near),
0, 0, -1.0, 0);
// viewing transform matrix
mat4 V = mat4(u.x, u.y, u.z, d_x,
v.x, v.y, v.z, d_y,
n.x, n.y, n.z, d_z,
0.0, 0.0, 0.0, 1.0);
mat4 MV = C * V;
//MV = V;
Судя по тому, что я нашел в Интернете, мой view_dir и выше должны оставаться фиксированными. Это означает, что мне нужно обновить только d_near и d_far, а также d_x, d_y и d_y? Я делаю это в своем glutIdleFunc(idle);
void idle (void) {
hBuffer->getFrame(hFrame);
if (hFrame->goodH && hFrame->timeStamp != timeStamp) {
timeStamp = hFrame->timeStamp;
std::cout << "(" << hFrame->eye.x << ", " <<
hFrame->eye.y << ", " <<
hFrame->eye.z << ") \n";
eye = vec3(hFrame->eye.x, hFrame->eye.y, hFrame->eye.z);
d_near = eye.z;
d_far = eye.z + 50;
P = mat4((2.0*d_near)/(right-left), 0, (right+left)/(right-left), 0,
0, (2.0*d_near)/(top-bottom), (top+bottom)/(top-bottom), 0,
0, 0, -(d_far+d_near)/(d_far-d_near), -(2.0*d_far*d_near)/(d_far-d_near),
0, 0, -1.0, 0);
d_x = -(dot(eye, u));
d_y = -(dot(eye, v));
d_z = -(dot(eye, n));
C = mat4(1.0, 0.0, 0.0, eye.x,
0.0, 1.0, 0.0, eye.y,
0.0, 0.0, 1.0, 0.0,
0.0, 0.0, 0.0, 1.0);
V = mat4(u.x, u.y, u.z, d_x,
v.x, v.y, v.z, d_y,
n.x, n.y, n.z, d_z,
0.0, 0.0, 0.0, 1.0);
MV = C * V;
//MV = V;
glutPostRedisplay();
}
}
Вот мой код шейдера:
#version 150
uniform mat4 MV;
uniform mat4 P;
in vec4 vPosition;
in vec4 vColor;
out vec4 color;
void
main()
{
gl_Position = P * MV * vPosition;
color = vColor;
}
Хорошо, я внес некоторые изменения в свой код, но безуспешно. Когда я использую V вместо MV в вершинном шейдере, все выглядит так, как я хочу, перспектива правильная и объекты имеют нужный размер, однако сцена транслируется смещением камеры.
При использовании C и V для получения MV моя сцена визуализируется с точки зрения наблюдателя прямо, и визуализированная сцена заполняет окно, как и должно, но перспектива глаза/камеры теряется.
На самом деле, я хочу перевести 2D-пиксели, плоскость проекции, на соответствующие значения x и y глаза/камеры, чтобы сохранить центр объекта (чей центр xy равен (0,0)) в центр визуализируемого изображения. Я руководствуюсь примерами из учебника "Интерактивная компьютерная графика: нисходящий подход с использованием шейдеров OpenGL (6-е издание)". Используя файлы в паре с книгой, свободно доступные в Интернете, я продолжаю использовать подход «основной ряд».
Следующие изображения сделаны, когда не используется матрица C для создания MV. Когда я использую C для создания MV, все сцены выглядят как на первом изображении ниже. Я не хочу перевода в z, поэтому я оставляю это значение равным 0.
Поскольку плоскость проекции и плоскость моей камеры параллельны, преобразование из одной системы координат в другую представляет собой просто сдвиг и inv(T) ~ -T.
Вот мое изображение для глаза в (0,0,50):
Вот мое изображение для глаза в (56,-16,50):