OpenGL C++中混用glOrtho与gluPerspective的黑屏渲染问题
解决从glOrtho切换到gluPerspective后黑屏的问题
刚看了你的问题,切换到游戏场景后黑屏、只有调窗口才正常显示,直接进场景却没问题——其实问题不是glVertex3f参数的锅,核心是矩阵状态没及时更新,导致物体被裁剪了。
问题根源分析
- 投影矩阵未更新:你切换场景时改了
key1的值,但myReshape只有窗口大小变化时才会触发。这意味着切换后,OpenGL用的还是欢迎页的正交投影设置(glOrtho(0.0, 100.0, 0.0, 100.0, -5.0 , 10.0)),这个投影的z轴可见范围是-5到10。 - 物体被裁剪:游戏场景的
Drawkey1/2里,你用glTranslatef(0.0, 0.0, -22.0)把物体移到了z=-22的位置,这个值远小于正交投影的近裁剪面(-5),所以直接被OpenGL裁掉了,自然黑屏。 - 调窗口才正常的原因:调整窗口会触发
myReshape,此时才会把投影矩阵改成透视模式(gluPerspective),它的z可见范围是0.1到200,物体的位置刚好在这个范围内,所以能显示。
另外,你的myReshape还有个小错误:在投影矩阵模式下调用了gluLookAt,这是不对的——gluLookAt是用来设置相机(模型视图矩阵)的,应该放在模型视图矩阵模式里。
解决方案
1. 修正myReshape函数,分离投影与模型视图设置
把gluLookAt从投影矩阵分支里移除,确保投影矩阵只负责投影方式,模型视图矩阵的设置放到Draw函数里:
void myReshape(int w, int h) { glViewport(0, 0, w, h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); // 先重置投影矩阵 if (key1 == 3){ // 欢迎页正交投影 glOrtho(0.0, 100.0, 0.0, 100.0, -5.0 , 10.0); } else if (key1 == 1 || key1 == 2){ // 游戏场景透视投影 gluPerspective(45.0, (float)w/(float)h, 0.1f, 200.0); } // 切回模型视图矩阵并重置 glMatrixMode(GL_MODELVIEW); glLoadIdentity(); }
2. 切换场景时手动更新矩阵并触发重绘
在你修改key1的地方(比如键盘响应函数),手动调用myReshape和glutPostRedisplay(),强制更新矩阵并刷新画面:
void keyboard(unsigned char key, int x, int y) { switch(key) { case '1': key1 = 1; // 用当前窗口尺寸触发矩阵更新 myReshape(glutGet(GLUT_WINDOW_WIDTH), glutGet(GLUT_WINDOW_HEIGHT)); glutPostRedisplay(); // 通知GLUT重绘 break; case '2': key1 = 2; myReshape(glutGet(GLUT_WINDOW_WIDTH), glutGet(GLUT_WINDOW_HEIGHT)); glutPostRedisplay(); break; case '3': key1 = 3; myReshape(glutGet(GLUT_WINDOW_WIDTH), glutGet(GLUT_WINDOW_HEIGHT)); glutPostRedisplay(); break; // 其他按键处理逻辑... } }
3. 在游戏场景的Draw函数里添加相机设置
把原来的gluLookAt移到Drawkey1/2里,确保模型视图矩阵正确设置相机:
void Drawkey1_2(){ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glMatrixMode(GL_MODELVIEW); glLoadIdentity (); // 设置相机位置和朝向(原来在myReshape里的代码移到这) gluLookAt(0.0, 0.0, 5.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0); // 平移物体到合适位置 glTranslatef(0.0, 0.0, -22.0); int i; par(-8.7, 9.2, 9.0, 9.2, 0.0, 0.0); par(-8.7, 9.2, -8.5, -8.7, 0.0, 0.0); par(-8.5, -8.7, -8.7, 9.2, 0.0, 0.0); par( 9.2, 9.0, -8.7, 9.2, 0.0, 0.0); while(p != NULL){ par((p -> x)/2.0,(p -> x)/2.0 + 0.4,(p -> y)/2.0,(p -> y)/2.0 + 0.4, 0.0, 0.0); p = p -> next; // 原代码的nexploration_ratet应该是笔误,改成next } par(food_x/2.0, food_x/2.0 + 0.4 , food_y/2.0 , food_y/2.0 + 0.4, 0.0 , 0.0); glutSwapBuffers(); // 如果用了双缓冲,记得加这个 }
验证效果
这样修改后,切换场景时会立刻更新投影矩阵,游戏场景的物体不会再被正交投影裁剪,不用调窗口就能正常渲染了。
内容的提问来源于stack exchange,提问作者Sunim
相关产品推荐
相关产品推荐

