OpenGL 挑选模式 gluPickMatrix

文章过于久远,技术陈旧, 无参考价值

文章过于久远,技术陈旧, 无参考价值

在OpenGL中也不建议使用这些选择模式,

推荐使用四叉树,RTree等空间索引

模型:

在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

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


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

评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值