OpenGL中如何单独拖拽移动多个2D图形(正方形、圆角矩形)
解决OpenGL图形独立拖拽问题
第一步:给图形添加独立属性
不能用全局变量控制所有图形的位置,要给每个图形单独存储位置、尺寸等属性。比如定义结构体:
typedef struct { float x, y; // 图形的基准坐标(比如左上角或中心,根据你的绘图逻辑定) float width, height; // 图形尺寸 int type; // 图形类型标记:0=正方形,1=圆角矩形 } Shape; // 示例图形数组,可根据需求添加更多 Shape shapes[] = { {100, 100, 50, 50, 0}, // 正方形:位置(100,100),边长50 {200, 200, 60, 40, 1} // 圆角矩形:位置(200,200),宽60高40 }; int shapeCount = sizeof(shapes)/sizeof(shapes[0]); int selectedShape = -1; // 选中图形的索引,-1表示未选中任何图形 float offsetX, offsetY; // 鼠标点击点相对于选中图形的偏移量
第二步:实现点击位置的坐标转换与图形命中判断
GLUT鼠标坐标以窗口左上角为原点,而OpenGL常用左下角为原点,需要先做坐标转换;再判断点击点是否落在图形范围内:
// 把GLUT鼠标坐标转换为OpenGL坐标 void convertMouseCoord(int mx, int my, float *ox, float *oy) { *ox = mx; *oy = glutGet(GLUT_WINDOW_HEIGHT) - my; } // 判断点(px, py)是否在目标图形内 int isPointInShape(float px, float py, Shape *shape) { switch(shape->type) { case 0: // 正方形判断(假设x,y是左上角坐标) return (px >= shape->x && px <= shape->x + shape->width && py >= shape->y && py <= shape->y + shape->height); case 1: // 圆角矩形先按普通矩形判断,精确圆角判断可后续优化 return (px >= shape->x && px <= shape->x + shape->width && py >= shape->y && py <= shape->y + shape->height); default: return 0; } }
第三步:处理鼠标事件回调
鼠标按下事件(解决Q2:点击非图形区域不触发移动)
void mouseDown(int button, int state, int mx, int my) { if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN) { float ox, oy; convertMouseCoord(mx, my, &ox, &oy); selectedShape = -1; // 遍历所有图形,判断是否点击到某一个 for (int i=0; i<shapeCount; i++) { if (isPointInShape(ox, oy, &shapes[i])) { selectedShape = i; // 记录鼠标相对于图形的偏移,避免拖拽时图形瞬移 offsetX = ox - shapes[i].x; offsetY = oy - shapes[i].y; break; } } } }
鼠标拖拽事件(解决Q1:仅移动选中的图形)
void mouseDrag(int mx, int my) { if (selectedShape != -1) { // 仅当有选中图形时处理拖拽 float ox, oy; convertMouseCoord(mx, my, &ox, &oy); // 更新选中图形的位置,保持鼠标点击点在图形上的相对位置不变 shapes[selectedShape].x = ox - offsetX; shapes[selectedShape].y = oy - offsetY; glutPostRedisplay(); // 触发画面重绘 } }
鼠标释放事件
void mouseUp(int button, int state, int mx, int my) { if (button == GLUT_LEFT_BUTTON && state == GLUT_UP) { selectedShape = -1; // 释放鼠标后取消选中状态 } }
第四步:修改Display函数,基于图形数组绘制
把原来的固定绘图逻辑改成遍历图形数组,用每个图形自身的坐标做平移:
void Display() { glClear(GL_COLOR_BUFFER_BIT); glLoadIdentity(); for (int i=0; i<shapeCount; i++) { glutPushMatrix(); glTranslatef(shapes[i].x, shapes[i].y, 0); // 根据图形类型调用对应绘图函数 if (shapes[i].type == 0) { drawsquare(); // 注意:该函数要基于原点绘制(比如从(0,0)画到(width,height)) } else if (shapes[i].type == 1) { drawRoundRect(); // 同理,基于原点绘制 } glutPopMatrix(); } glutSwapBuffers(); }
第五步:注册鼠标回调函数
在main函数中添加鼠标事件的回调注册:
int main(int argc, char** argv) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB); glutInitWindowSize(800, 600); glutCreateWindow("Draggable Shapes"); // 初始化正交投影,让坐标和窗口像素对应 glClearColor(1.0, 1.0, 1.0, 1.0); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluOrtho2D(0, 800, 0, 600); // 注册回调 glutDisplayFunc(Display); glutMouseFunc(mouseDown); glutMotionFunc(mouseDrag); glutMouseUpFunc(mouseUp); glutMainLoop(); return 0; }
关键注意事项
- 绘图函数要基于原点绘制:如果你的
drawsquare()或drawRoundRect()是用固定坐标绘制的,必须改成以(0,0)为基准,这样glTranslatef才能正确控制图形位置。 - 精确碰撞优化(可选):如果需要精确判断圆角矩形的圆角区域,可通过计算点到圆角圆心的距离是否小于圆角半径来实现,新手可先从矩形判断入手。
内容的提问来源于stack exchange,提问作者Wiki
相关产品推荐
相关产品推荐

