OpenGL问题:点击菜单选项时场景对象持续偏移
问题分析与修复方案
你的问题核心在于OpenGL矩阵状态的累积和矩阵栈管理不当,导致每次重绘时物体的变换叠加,从而持续移动。具体来说:
问题根源
模型视图矩阵未在每次重绘时重置
OpenGL是状态机,reshape()函数中的glLoadIdentity()和glTranslatef(0.0, 0.0, -5.0)只在窗口大小变化时执行一次。之后每次调用display(),都会在上一次的矩阵变换结果上继续叠加新的glTranslatef操作,导致物体不断偏移。矩阵栈使用不规范
在display()中,你只在绘制球体后弹出了一次矩阵栈,但后续绘制圆锥和眼睛的变换仍然在最初的glPushMatrix()上下文里,这让这些部件的变换也会被持续累积。
修复步骤
1. 每次重绘时重置模型视图矩阵
在display()函数开头,明确切换到模型视图矩阵并重置它,确保每次绘制都从相机初始位置开始:
glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glTranslatef(0.0, 0.0, -5.0); // 保持相机到场景的距离,和reshape里的设置一致
2. 正确隔离每个部件的变换
为每个独立的绘制部件(球体、圆锥、眼睛)单独使用glPushMatrix()和glPopMatrix(),这样每个部件的变换只会影响自身,不会干扰其他部件或累积到下一次重绘。
修正后的完整代码
#include "stdafx.h" #include <windows.h> #include <GL/glut.h> #include <stdlib.h> #define RED 1 #define GREEN 2 #define BLUE 3 #define WHITE 4 //white colour for sphere float red =1.0,green =1.0,blue=0.0,white = 0.0; void init(void) { glClearColor (0.0, 0.0, 0.0, 0.0); glShadeModel (GL_FLAT); } void display(void){ glClear (GL_COLOR_BUFFER_BIT); // 重置模型视图矩阵,确保每次绘制从初始状态开始 glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glTranslatef(0.0, 0.0, -5.0); // Sphere glColor3f(red,green,blue); glPushMatrix(); glTranslatef (-3.5, -1.5, 0.0); glTranslatef (1.0, 0.0, 0.0); glScalef (3.0, 3.0, 0.0); glutSolidSphere(0.4,40,40); glPopMatrix(); //Cone glColor3f(0.0,0.0,0.0); glPushMatrix(); glTranslatef (-3.5 + 1.0 + 0.95, -1.5 - 0.2, 0.0); // 直接计算圆锥的绝对位置,避免依赖球体的变换 glRotated(300,1.0,4.0,1.0); glutSolidCone(0.6, 0.9, 30, 30); glPopMatrix(); //Sphere(eye) glColor3f(0.0,0.0,0.0); glPushMatrix(); glTranslatef (-3.5 + 1.0 - 0.75, -1.5 + 0.8, 0.0); // 直接计算眼睛的绝对位置 glScalef(0.6,0.6,0.0); glutSolidSphere(0.2,40,40); glPopMatrix(); glFlush(); } void reshape (int w, int h){ glViewport (0, 0, (GLsizei) w, (GLsizei) h); glMatrixMode (GL_PROJECTION); glLoadIdentity (); gluPerspective(65.0, (GLfloat) w/(GLfloat) h, 1.0, 20.0); // 这里移除MODELVIEW的设置,因为display里已经每次重置了 glMatrixMode(GL_MODELVIEW); } void mouse(int option){ switch(option){ case RED: red = 1.0,green = 0.0,blue = 0.0; break; case GREEN: red = 0.0,green = 1.0,blue = 0.0; break; case BLUE: red = 0.0,green = 0.0,blue = 1.0; break; case WHITE: red = 1.0,green = 1.0,blue = 1.0; break; } glutPostRedisplay(); } int main(int argc, char** argv){ glutInit(&argc, argv); glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB); glutInitWindowSize (700, 500); glutInitWindowPosition (100, 100); glutCreateWindow ("Testing"); glutDisplayFunc(display); glutReshapeFunc(reshape); int sphere = glutCreateMenu(mouse); //change colour of pacman glutAddMenuEntry("Red",RED); glutAddMenuEntry("Green",GREEN); glutAddMenuEntry("Blue",BLUE); glutAddMenuEntry("White",WHITE); glutCreateMenu(mouse); glutAddSubMenu("Pacman",sphere); glutAttachMenu(GLUT_RIGHT_BUTTON); init (); glutMainLoop(); return 0; }
额外说明
- 我把圆锥和眼睛的位置改成了绝对坐标计算,这样每个部件的变换完全独立,避免了依赖前一个部件的变换上下文,进一步防止了状态累积。
- 移除了
reshape()中对MODELVIEW矩阵的设置,因为现在display()每次都会重置这个矩阵,确保一致性。
内容的提问来源于stack exchange,提问作者Nivanraj Mohan
相关产品推荐
相关产品推荐

