文章过于久远,技术陈旧, 无参考价值
文章过于久远,技术陈旧, 无参考价值
在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