我正在OpenGL的天空盒内制作一个过山车,并且没有太多关于它的功能或计算机图形的背景,它被证明是非常困难的。我使用Catmull-Rom样条插值绘制了一个过山车,并用glVertex3f绘制了每个点。现在我想每隔50ms调用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
,其中包括样条曲线的控制点和插值点。完成后,我每隔50ms拨打update()
,然后沿着allpoints
中的每个点移动相机。在该项目的先前版本中,我可以看到正在正确绘制过山车。 gluLookAt()
似乎无法按我的意愿行事。使用上面的代码,程序开始时相机用过山车的一部分观看天空盒的一侧,然后当调用update()
时,过山车消失但相机不移动。我一直在搞乱我放置OpenGL矩阵函数的位置,并且根据它们的位置有时update()
也会导致空白屏幕。
答案 0 :(得分:5)
除了缺少glPopMatrix
(用户971377已经发现)之外,您在绘图例程中调用glLoadIdentity
,这当然会覆盖您在update
中对模型视图矩阵所做的任何更改方法(使用gluLookAt
)。
始终牢记:gluLookAt
,glOrtho
,gluPerspective
,glTranslate
,glRotate
以及所有其他矩阵和转换功能始终在顶部工作当前所选矩阵堆栈的元素(由glPush/PopMatrix
更改)(由glMatrixMode
更改)。它们总是将当前矩阵相乘,而不是替换它。与gluPerspective
类似,您应在致电glLoadIdentity
之前致电gluLookAt
。并且整个相机更改应该在渲染例程中完成,而不是更新例程。
而不是在update
中进行任何GL变换,而是应该更改相机所依赖的变量,并在gluLookAt
方法中设置相机(display
在模型视图矩阵上)。为了演示这些函数的标准用法,您的代码应该类似于:
void display()
{
<general state setup (glClear, ...)>
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glLookAt(camera); //view transformation (camera)
//object 1
glPushMatrix(); //save modelview
glTranslate/glRotate/glScale; //local model transformations
<draw object 1>
glPopMatrix();
...
//object n
glPushMatrix(); //save modelview
glTranslate/glRotate/glScale; //local model transformations
<draw object n>
glPopMatrix();
gluSwapBuffers();
}
void update()
{
camera = ...;
}
}
答案 1 :(得分:3)
在您的代码中注意到glPushMatrix();
没有glPopMatrix();
只是想一想,这可能与你的问题有关。
答案 2 :(得分:0)
gluLookAt始终将其结果应用于当前矩阵,在您的情况下为GL_MODEL_VIEW。但是当你渲染你的过山车时,你会在该矩阵中加载身份,这会删除你使用gluLookAt放置的值。
在这种情况下,您无需触摸模型视图。实际上,GL_MODEL_VIEW代表模型矩阵乘以视图矩阵。在这种情况下,您可以glPushMatrix()
后跟glMulMatrix( myModelMatrix )
并在呈现glPopMatrix()
之后。这样,您可以将视图矩阵保留在GL_MODEL_VIEW中,并且仍然为每个对象使用不同的模型矩阵
我还建议你只改变一次帧的投影矩阵,而不是每帧。
答案 3 :(得分:0)
自从我触及OpenGL以来已经有很长一段时间了,但这里有几点需要考虑: