模型:
在AutoCAD中绘制一个 400x400大小的方框,并分别绘制红绿蓝三个矩形以及一根黄色线
且三个矩形有重叠的地方
实现鼠标进行点击的时候,打印出四个图元中命中的图元ID
思路:
将OpenGL环境初始化后,
进行图形绘制与显示,当鼠标点击的时候,
进入GL_SELECT选择模式,并将鼠标点的区域设置为10X10,
再设置好挑选的视景体(与绘制采用一致的glOrtho),
在选择缓冲区中进行绘制,然后返回点击数量,
将点击的图元打印出来
代码如下:
#include <windows.h> #include <GL/glut.h> #include <stdio.h> void Init() { glClearColor(0.25f, 0.25f, 0.25f, 0); glEnable(GL_DEPTH_TEST); glShadeModel(GL_FLAT); } void draw(GLenum nEnum) { glMatrixMode(GL_MODELVIEW); glLoadIdentity(); if (GL_SELECT == nEnum) { glPushName(1); } glColor3f(1.0, 0.0, 0.0); // 红色矩形 glRectf(100, 100, 200, 200); if (GL_SELECT == nEnum) { glPushName(2); } glColor3f(0.0, 1.0, 0.0); // 绿色矩形 glRectf(250, 100, 350, 200); if (GL_SELECT == nEnum) { glPushName(3); } glColor3f(0.0, 0.0, 1.0); // 蓝色矩形 glRectf(175, 175, 275, 275); if (GL_SELECT == nEnum) { glPushName(4); } glColor3f(1.0, 1.0, 0.0); // 黄色线 glBegin(GL_LINES); glVertex3f(50.0, 300.0, 0.0); glVertex3f(300.0, 300.0, 0.0); glEnd(); glFinish(); glFlush(); } void display() { glClear(GL_COLOR_BUFFER_BIT); draw(GL_RENDER); } void Reshape(int width, int height) { glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(0, 400, 0, 400, 10, -10); return; } void mouseFunc(int button, int state, int x, int y) { if (GLUT_LEFT_BUTTON == button && GLUT_DOWN == state) { GLuint nBuffer[512]; glSelectBuffer(512, nBuffer); glRenderMode(GL_SELECT); glInitNames(); glPushName(0); glPushMatrix(); glMatrixMode(GL_PROJECTION); glLoadIdentity(); GLint nViewport[4]; glGetIntegerv(GL_VIEWPORT, nViewport); gluPickMatrix(x, nViewport[3]-y, 10, 10, nViewport); glOrtho(0, 400, 0, 400, 10, -10); draw(GL_SELECT); glMatrixMode(GL_PROJECTION); glPopMatrix(); int nPicks = glRenderMode(GL_RENDER); printf("\nSelect Num:%d--", nPicks); GLuint* ptr = nBuffer; GLuint name; for (int i = 0; i<nPicks; i++) { name = *ptr; ptr += 3; ptr += name -1; switch(*ptr) { case 1: printf("--red--"); break; case 2: printf("--gree--"); break; case 3: printf("--blue--"); break; case 4: printf("--yellow--"); break; } ptr++; } } } int main() { glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE); glutInitWindowSize(400, 400); glutInitWindowPosition(100, 300); Init(); glutCreateWindow("OpenGL Test Yulinxx"); glutDisplayFunc(display); glutReshapeFunc(Reshape); glutMouseFunc(mouseFunc); glutMainLoop(); return 0; }
在glSelectBuffer(512, nBuffer); 函数中,nBuffer的内存如下:
分别点击红绿蓝矩形,nBuffer的内存:
分别点击黄线,红蓝重叠区,绿蓝重叠处,nBuffer的内存:
这种内存布局,目前有点疑惑
==============================================================
void Init() { glClearColor(0.25f, 0.25f, 0.25f, 0); glEnable(GL_DEPTH_TEST); glShadeModel(GL_FLAT); } void draw(GLenum nEnum) { glMatrixMode(GL_MODELVIEW); glLoadIdentity(); if (GL_SELECT == nEnum) { glLoadName(1); } glColor3f(1.0, 0.0, 0.0); // 红色矩形 glRectf(100, 100, 200, 200); if (GL_SELECT == nEnum) { glLoadName(2); } glColor3f(0.0, 1.0, 0.0); // 绿色矩形 glRectf(250, 100, 350, 200); if (GL_SELECT == nEnum) { glLoadName(3); } glColor3f(0.0, 0.0, 1.0); // 蓝色矩形 glRectf(175, 175, 275, 275); if (GL_SELECT == nEnum) { glLoadName(4); } glColor3f(1.0, 1.0, 0.0); // 黄色线 glBegin(GL_LINES); glVertex3f(50.0, 300.0, 0.0); glVertex3f(300.0, 300.0, 0.0); glEnd(); glFinish(); glFlush(); } void display() { glClear(GL_COLOR_BUFFER_BIT); draw(GL_RENDER); } void Reshape(int width, int height) { glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(0, 400, 0, 400, 10, -10); return; } void mouseFunc(int button, int state, int x, int y) { if (GLUT_LEFT_BUTTON == button && GLUT_DOWN == state) { GLuint nBuffer[512]; glSelectBuffer(512, nBuffer); glRenderMode(GL_SELECT); glInitNames(); glPushName(0); glPushMatrix(); glMatrixMode(GL_PROJECTION); glLoadIdentity(); GLint nViewport[4]; glGetIntegerv(GL_VIEWPORT, nViewport); gluPickMatrix(x, nViewport[3]-y, 10, 10, nViewport); glOrtho(0, 400, 0, 400, 10, -10); draw(GL_SELECT); glMatrixMode(GL_PROJECTION); glPopMatrix(); int nPicks = glRenderMode(GL_RENDER); printf("\nSelect Num:%d-----", nPicks); GLuint* ptr = nBuffer; for (int i = 0; i<nPicks; i++) { ptr += 3; switch(*ptr) { case 1: printf("--red--"); break; case 2: printf("--gree--"); break; case 3: printf("--blue--"); break; case 4: printf("--yellow--"); break; } ptr++; } } } int main() { glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE); glutInitWindowSize(400, 400); glutInitWindowPosition(100, 300); Init(); glutCreateWindow("OpenGL Test Yulinxx"); glutDisplayFunc(display); glutReshapeFunc(Reshape); glutMouseFunc(mouseFunc); glutMainLoop(); return 0; }
下面的代码和上述代码功能一样,代码差异为
上述:名字堆栈均采用glPushName 压入名字堆栈中
上述:名字堆栈均采用glLoadName 取代名字堆栈顶部名字
在glSelectBuffer(512, nBuffer); 函数中,nBuffer的内存如下:
分别点击红绿蓝矩形,nBuffer的内存:
分别点击黄线,红蓝重叠区,绿蓝重叠处,nBuffer的内存:
这种内存方式好理解一些,选中的图形,依次按顺序排列在nBuffer中,每个图元分别占四个位置,
分别为
名字堆栈中的名称数量
最大Z值
最小Z值
命中的ID
----- 为了节省名字堆栈的空间,应该在图元绘制完成后,将其名字从堆栈中弹出。从网上抄来的,还不知道这句话的正确性,以及为什么要这么做,这么做的合理性