OpenGL gluLookAt() 未按预期工作
我正在 OpenGL 的天空盒内制作过山车,并且没有太多关于其功能或计算机图形的背景,事实证明这是非常困难的。我使用 Catmull-Rom 样条插值绘制了一个过山车,并使用 glVertex3f 绘制了每个点。现在我想每 50 毫秒调用一次 update()
函数来围绕轨道移动相机。 gluLookAt() 产生奇怪的结果,要么从屏幕上删除轨道,产生黑屏等。我想我需要移动一些矩阵函数,但我不知道该放在哪里每一个。到目前为止,这是我的代码:我的
int main(int argc, char** argc)
{
// ... load track, etc ...
// Init currpos, nextpos, iter, up
currpos = Vec3f(0, 0, 0);
nextpos = currpos;
iter = 0;
up = Vec3f(0, 1, 0);
deque<Vec3f> points;
Vec3f newpt;
// Loop through the points and interpolate
for (pointVectorIter pv = g_Track.points().begin(); pv != g_Track.points().end(); pv++)
{
Vec3f curr(*pv); // Initialize the current point and a new point (to be drawn)
points.push_back(curr); // Push the current point onto the stack
allpoints.push_back(curr); // Add current point to the total stack
if (points.size() == 4) // Check if there are 4 points in the stack, if so interpolate
{
for (float u = 0.0f; u < 1.0f; u += 0.01f)
{
newpt = interpolate(points[0], points[1], points[2], points[3], u);
glColor3f(1, 1, 1);
glVertex3f(newpt.x(), newpt.y(), newpt.z());
allpoints.push_back(newpt);
}
points.pop_front();
}
}
// glutInit, InitGL(), etc...
}
void InitGL(GLvoid)
{
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LEQUAL);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(100.0, (GLfloat)WINDOW_WIDTH / (GLfloat)WINDOW_HEIGHT, .0001, 999999);
glMatrixMode(GL_MODELVIEW);
glClearColor(0.0f, 0.0f, 0.0f, 0.5f);
}
void display (void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(currpos.x(), currpos.y(), currpos.z(), nextpos.x(), nextpos.y(), nextpos.z(), up.x(), up.y(), up.z());
glPushMatrix();
glEnable(GL_TEXTURE_2D); // Enable texturing from now on
/* draw skybox, this was from previous assignment and renders correctly */
glPopMatrix();
// now draw rollercoaster ...
glPushMatrix();
glBegin(GL_LINE_STRIP);
deque<Vec3f> points;
Vec3f newpt;
for each (Vec3f pt in allpoints)
{
glColor3f(1, 1, 1);
glVertex3f(pt.x(), pt.y(), pt.z());
}
glutTimerFunc(50, update, 1);
glEnd();
glPopMatrix();
// Swap buffers, so one we just drew is displayed
glutSwapBuffers();
}
void update(int a)
{
if (iter < allpoints.size())
{
currpos = allpoints[iter];
nextpos = allpoints[iter + 1];
gaze = nextpos - currpos;
gaze.Normalize();
Vec3f::Cross3(binorm, gaze, up);
binorm.Normalize();
Vec3f::Cross3(up, binorm, gaze);
up.Normalize();
glutPostRedisplay();
}
iter++;
}
想法是,我保留一个全局双端队列allpoints
,其中包括样条线的控制点和插值点。完成后,我每 50 毫秒调用一次 update()
,并沿着 allpoints
中的每个点移动相机。在该项目的先前版本中,我可以看到过山车的绘制正确。 gluLookAt()
似乎没有按照我想要的方式工作。通过上面的代码,程序开始时相机看着天空盒的一侧和过山车的一部分,然后当调用 update()
时,过山车消失但相机不动。我一直在搞乱 OpenGL 矩阵函数的放置位置,并且根据它们所在的位置,有时 update()
也会导致空白屏幕。
I am making a rollercoaster inside of a skybox in OpenGL, and without much background on it's functions or computer graphics it is proving to be very difficult. I drew a rollercoaster using Catmull-Rom spline interpolation, and drew each point with glVertex3f. Now I want to call an update()
function every 50ms to move the camera around the track. gluLookAt()
is producing weird results, either removing the track from the screen, producing a black screen, etc. I think I need to move some of the matrix functions around but I am not sure where to put each one. Here is my code so far:
int main(int argc, char** argc)
{
// ... load track, etc ...
// Init currpos, nextpos, iter, up
currpos = Vec3f(0, 0, 0);
nextpos = currpos;
iter = 0;
up = Vec3f(0, 1, 0);
deque<Vec3f> points;
Vec3f newpt;
// Loop through the points and interpolate
for (pointVectorIter pv = g_Track.points().begin(); pv != g_Track.points().end(); pv++)
{
Vec3f curr(*pv); // Initialize the current point and a new point (to be drawn)
points.push_back(curr); // Push the current point onto the stack
allpoints.push_back(curr); // Add current point to the total stack
if (points.size() == 4) // Check if there are 4 points in the stack, if so interpolate
{
for (float u = 0.0f; u < 1.0f; u += 0.01f)
{
newpt = interpolate(points[0], points[1], points[2], points[3], u);
glColor3f(1, 1, 1);
glVertex3f(newpt.x(), newpt.y(), newpt.z());
allpoints.push_back(newpt);
}
points.pop_front();
}
}
// glutInit, InitGL(), etc...
}
void InitGL(GLvoid)
{
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LEQUAL);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(100.0, (GLfloat)WINDOW_WIDTH / (GLfloat)WINDOW_HEIGHT, .0001, 999999);
glMatrixMode(GL_MODELVIEW);
glClearColor(0.0f, 0.0f, 0.0f, 0.5f);
}
void display (void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(currpos.x(), currpos.y(), currpos.z(), nextpos.x(), nextpos.y(), nextpos.z(), up.x(), up.y(), up.z());
glPushMatrix();
glEnable(GL_TEXTURE_2D); // Enable texturing from now on
/* draw skybox, this was from previous assignment and renders correctly */
glPopMatrix();
// now draw rollercoaster ...
glPushMatrix();
glBegin(GL_LINE_STRIP);
deque<Vec3f> points;
Vec3f newpt;
for each (Vec3f pt in allpoints)
{
glColor3f(1, 1, 1);
glVertex3f(pt.x(), pt.y(), pt.z());
}
glutTimerFunc(50, update, 1);
glEnd();
glPopMatrix();
// Swap buffers, so one we just drew is displayed
glutSwapBuffers();
}
void update(int a)
{
if (iter < allpoints.size())
{
currpos = allpoints[iter];
nextpos = allpoints[iter + 1];
gaze = nextpos - currpos;
gaze.Normalize();
Vec3f::Cross3(binorm, gaze, up);
binorm.Normalize();
Vec3f::Cross3(up, binorm, gaze);
up.Normalize();
glutPostRedisplay();
}
iter++;
}
The idea is that I am keeping a global deque allpoints
that includes the control points of the spline and the interpolated points. Once that is complete, I call update()
every 50ms, and move the camera along each point in allpoints
. In a previous version of the project, I could see that the rollercoaster was being drawn correctly. It is gluLookAt()
that doesn't seem to work how I want it to. With the code above, the program starts with the camera looking at one side of the skybox with a part of the rollercoaster, and then when update()
is called, the rollercoaster disappears but the camera does not move. I have been messing around with where I am putting the OpenGL matrix functions, and depending on where they are sometimes update()
will cause a blank screen as well.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
除了缺少
glPopMatrix
(user971377 已经发现)之外,您还可以在绘图例程中调用glLoadIdentity
,这当然会覆盖您在中对模型视图矩阵所做的任何更改。 >update
方法(使用gluLookAt
)。始终记住:
gluLookAt
、glOrtho
、gluPerspective
、glTranslate
、glRotate
、所有其他矩阵和变换函数始终作用于当前选定矩阵堆栈(由glMatrixMode
更改)的顶部元素(由glPush/PopMatrix
更改)。他们总是乘以当前矩阵,而不是替换它。因此,与gluPerspective
一样,您应该在调用gluLookAt
之前调用glLoadIdentity
。整个相机的更改应该在渲染例程中完成,而不是更新例程。与其在
update
中进行任何 GL 转换,您应该更改相机所依赖的变量,并在display 中设置相机(模型视图矩阵上的
gluLookAt
)方法。为了演示这些函数的标准用法,您的代码应该类似于:
Besides the absence of
glPopMatrix
(which user971377 already spotted), you callglLoadIdentity
in your drawing routine, which of course overwrites any changes you did on the modelview matrix in theupdate
method (usinggluLookAt
).Always keep in mind:
gluLookAt
,glOrtho
,gluPerspective
,glTranslate
,glRotate
, and all other matrix and transformation functions always work on the top element (changed byglPush/PopMatrix
) of the currently selected matrix stack (changed byglMatrixMode
). And they always multiply the current matrix, istead of replacing it. So like forgluPerspective
, you should callglLoadIdentity
before callinggluLookAt
. And the whole camera change should be done in the rendering routine, istead of the update routine.Instead of doing any GL transformations in
update
you should rather change the variables on which the camera depends and set the camera (gluLookAt
on the modelview matrix) in thedisplay
method. To demonstrate the standard use of these functions, your code should be something like:}
在您的代码中注意到
glPushMatrix();
被调用,没有glPopMatrix();
只是一个想法,这可能与您的问题有关。
Noticed in your code
glPushMatrix();
is called with noglPopMatrix();
Just a thought, this might have something to do with you issue.
gluLookAt 始终将其结果应用于当前矩阵,在您的情况下是 GL_MODEL_VIEW。但是,当您渲染过山车时,您会在该矩阵中加载标识,这会擦除您使用 gluLookAt 放置的值。
在这种情况下,您不需要触摸模型视图。事实上,GL_MODEL_VIEW代表模型矩阵乘以视图矩阵。在这种情况下,您可以先使用
glPushMatrix()
,然后使用glMulMatrix( myModelMatrix )
,然后再渲染glPopMatrix()
。这样,您可以将视图矩阵保留在 GL_MODEL_VIEW 内,并且仍然为每个对象使用不同的模型矩阵。我还建议您只每帧更改一次投影矩阵,而不是每帧更改一次。
gluLookAt always applies its result to current matrix, which in your case is GL_MODEL_VIEW. But when you render your roller coaster, you load identity in that matrix, which erase the value you put using gluLookAt.
In this case, you don't need to touch the model view. In fact, GL_MODEL_VIEW stands for model matrix multiply by view matrix. In this case, you can
glPushMatrix()
followed byglMulMatrix( myModelMatrix )
and after renderingglPopMatrix()
. With this, you can keep your view matrix inside the GL_MODEL_VIEW and still use a different model matrix for each objectI also suggest you only change projection matrix once a frame, and not each frame.
我已经很久没有接触 OpenGL 了,但这里有一些需要考虑的事情:
It's been a long time since I touched OpenGL, but here are a few things to consider: