GLUT绘制多边形时如何避免重绘导致已绘制的多边形消失?
问题根因
- OpenGL即时渲染模式下,
glClear会清空整个画布的所有内容,所有图形必须在每次display回调中重新调用绘制命令生成,不存在“一次性绘制后永久保留在画布上”的效果。 - 现有代码的全局变量仅支持单个正在绘制的多边形的临时存储,没有任何用于持久化保存已闭合多边形的存储结构:
- 鼠标左击开启新多边形时,代码会直接执行
numPoints = 0,直接覆盖清空上一个多边形的顶点坐标数据,从数据层面就把之前的多边形丢失了 display函数每次清屏后,仅能读取当前临时多边形的坐标做绘制,没有已存储的多边形数据可以用来重绘,清屏后自然看不到之前的图形
- 鼠标左击开启新多边形时,代码会直接执行
- 原代码使用固定容量40的数组存坐标,不仅单个多边形顶点数超过40就会出错,也完全没有多图形存储的扩展能力
修复方案
- 拆分数据存储结构:划分为「已完成多边形的持久化存储区」和「当前正在绘制的多边形临时存储区」两部分
- 持久化区用嵌套动态数组,按列表顺序存储每一个已闭合多边形的所有顶点坐标
- 临时区保留原来的鼠标位置、当前顶点数、闭合状态变量,用来处理实时绘制的预览效果
- 修改鼠标回调逻辑:右键点击闭合当前多边形时,先把当前临时区的顶点数据完整拷贝到持久化存储区,再清空临时区准备绘制下一个多边形,不要等开启新多边形时才丢弃旧数据
- 修改渲染流程:每次清屏后,先遍历持久化存储区把所有已完成的多边形全部重绘,再绘制当前正在编辑的临时多边形的预览线
- 可选优化:把原单缓冲模式改为双缓冲,避免多图形绘制时的画面闪烁,只需把初始化时的
GLUT_SINGLE换成GLUT_DOUBLE,渲染完成后用glutSwapBuffers()代替glFlush()即可
核心修改代码参考
// 持久化存储区:保存所有已完成的多边形,每一项是一个多边形的全部X/Y坐标 vector<vector<float>> completedPolyX; vector<vector<float>> completedPolyY; // 临时存储区:当前正在绘制的多边形的相关变量 float mouseX, mouseY; vector<float> currentX, currentY; int currentPointCount = 0; bool isCurrentClosed = false; void mouse(int button, int state, int x, int y) { mouseX = x; mouseY = y; // 左键添加顶点 if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN) { // 上一个多边形已闭合/点数超限时,清空临时区准备开启新多边形 if (isCurrentClosed || currentPointCount > 1000) { currentX.clear(); currentY.clear(); currentPointCount = 0; isCurrentClosed = false; } currentX.push_back(mouseX); currentY.push_back(mouseY); currentPointCount++; } // 右键闭合当前多边形 if (button == GLUT_RIGHT_BUTTON && state == GLUT_DOWN && currentPointCount >=3) { // 把当前多边形存入持久化存储区,永久保留数据 completedPolyX.push_back(currentX); completedPolyY.push_back(currentY); isCurrentClosed = true; } } void display() { glClear(GL_COLOR_BUFFER_BIT); // 先绘制所有已完成的多边形 if (!completedPolyX.empty()) { glBegin(GL_LINE_LOOP); for (int polyIdx = 0; polyIdx < completedPolyX.size(); polyIdx++) { for (int pointIdx = 0; pointIdx < completedPolyX[polyIdx].size(); pointIdx++) { glVertex2f(completedPolyX[polyIdx][pointIdx], completedPolyY[polyIdx][pointIdx]); } } glEnd(); } // 再绘制当前正在编辑的多边形预览 if (currentPointCount > 0) { glBegin(GL_LINE_STRIP); for (int i = 0; i < currentPointCount; i++) { glVertex2f(currentX[i], currentY[i]); } // 未闭合时,连线到当前鼠标位置做实时预览 if (!isCurrentClosed) { glVertex2f(mouseX, mouseY); } glEnd(); } // 使用双缓冲模式时,将glFlush()替换为glutSwapBuffers() glFlush(); } int main(int argc, char** argv) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB); glutInitWindowSize(600, 400); glutInitWindowPosition(0, 0); glutCreateWindow("Testing"); gluOrtho2D(0, 600, 400, 0); glutDisplayFunc(display); glutMouseFunc(mouse); glutMainLoop(); }
内容的提问来源于stack exchange,提问作者user15754100
相关产品推荐
相关产品推荐

