OpenGL 挑选模式 gluPickMatrix

模型:

在AutoCAD中绘制一个 400x400大小的方框,并分别绘制红绿蓝三个矩形以及一根黄色线

且三个矩形有重叠的地方


OpenGL 挑选模式 gluPickMatrix_第1张图片


实现鼠标进行点击的时候,打印出四个图元中命中的图元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的内存:

OpenGL 挑选模式 gluPickMatrix_第2张图片


分别点击黄线,红蓝重叠区,绿蓝重叠处,nBuffer的内存:


OpenGL 挑选模式 gluPickMatrix_第3张图片


这种内存布局,目前有点疑惑 


==============================================================


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的内存:



OpenGL 挑选模式 gluPickMatrix_第4张图片



分别点击黄线,红蓝重叠区,绿蓝重叠处,nBuffer的内存:


OpenGL 挑选模式 gluPickMatrix_第5张图片




这种内存方式好理解一些,选中的图形,依次按顺序排列在nBuffer中,每个图元分别占四个位置,

分别为

名字堆栈中的名称数量

最大Z值

最小Z值

命中的ID



----- 为了节省名字堆栈的空间,应该在图元绘制完成后,将其名字从堆栈中弹出。从网上抄来的,还不知道这句话的正确性,以及为什么要这么做,这么做的合理性





http://hi.baidu.com/yulinxx_/item/791684fcf27a531284d2782d




你可能感兴趣的:(OpenGL 挑选模式 gluPickMatrix)