使用GLUT绘制多个矩形时如何避免新矩形覆盖原有已绘制矩形?
GLUT多矩形绘制时原有内容消失的修复方法
核心根因说明
你当前代码的问题本质是即时模式OpenGL的绘制机制特性:
- 程序没有持久存储已绘制完成的矩形参数,仅用两个全局变量记录当前正在交互的临时矩形,之前完成的矩形没有任何数据留存
- 每次
display回调触发时,glClear会清空整个画布的内容,之后仅绘制当前交互的单个矩形,旧图形自然完全消失 - 即时模式下的OpenGL不会自动留存帧缓冲的绘制内容,只要窗口被遮挡、尺寸变化触发重绘,帧缓冲的旧内容就会被系统重置,必须每次重绘时从内存存储的数据源重新绘制所有图形。
具体调整步骤
1. 引入矩形数据存储结构
需要新增一个可动态扩容的容器,持久保存每一个已完成矩形的对角坐标:
#include <vector> // 引入vector头文件 struct Position { Position() : x(0), y(0) {} float x, y; }; // 全局变量区:新增存储已完成矩形的容器,每个元素存储一个矩形的两个对角点 std::vector<std::pair<Position, Position>> finishedRects; Position start, finish; // 保留原有的交互临时坐标
2. 修改鼠标交互逻辑
在鼠标左键抬起(即单个矩形绘制完成)时,将当前绘制的矩形参数存入存储容器,自动跳过宽或高接近0的无效点击生成的空矩形:
void mouse(int button, int state, int x, int y) { if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN) { start.x = finish.x = x; start.y = finish.y = y; } if (button == GLUT_LEFT_BUTTON && state == GLUT_UP) { finish.x = x; finish.y = y; // 新增:将有效矩形存入存储容器 if (abs(finish.x - start.x) > 1 && abs(finish.y - start.y) > 1) { finishedRects.emplace_back(start, finish); } } glutPostRedisplay(); }
3. 重写显示绘制逻辑
每次display回调触发时,先清空画布,再循环遍历存储容器里的所有已完成矩形全部绘制,最后绘制当前正在拖拽的临时预览矩形:
void display() { glClear(GL_COLOR_BUFFER_BIT); glBegin(GL_QUADS); // 循环绘制所有已保存的矩形 for (const auto& rect : finishedRects) { const Position& s = rect.first; const Position& f = rect.second; glVertex2f(s.x, s.y); glVertex2f(f.x, s.y); glVertex2f(f.x, f.y); glVertex2f(s.x, f.y); } // 绘制当前鼠标按住未抬起的临时预览矩形 glVertex2f(start.x, start.y); glVertex2f(finish.x, start.y); glVertex2f(finish.x, finish.y); glVertex2f(start.x, finish.y); glEnd(); glFlush(); }
额外注意事项
- 如果绘制时发现矩形和鼠标拖动的方向上下颠倒,是因为GLUT的鼠标坐标系原点在窗口左上角,而OpenGL默认坐标系原点在左下角,可以在初始化投影矩阵时调整坐标系匹配鼠标坐标,或在读取鼠标y值时做翻转适配。
- 如果使用双缓冲模式,记得把
glFlush替换为glutSwapBuffers,避免重绘时出现闪烁。
内容的提问来源于stack exchange,提问作者user15754100
相关产品推荐
相关产品推荐

