我使用选择缓冲区使用OpenGL的Picking机制相当困难。具体来说,我希望能够在所选对象中进行子选择。我的测试世界散布着多个对象,每个对象呈现四个"面孔",如下所示:
void drawObject(int i)
{
renderFace0(i);
renderFace1(i);
renderFace2(i);
renderFace3(i);
}
到目前为止一切都很顺利。参数i
只是说出索引是什么,因为我的"对象"只是存储在数组中的数据。每个对象都是根据它的索引唯一标识的。然后我添加了pick功能,它更新当前指向的对象(我使用屏幕中心作为拾取对象的点):
void pickObject()
{
unsigned int selectBuffer[200];
int viewport[4];
int hits;
glGetIntegerv(GL_VIEWPORT, viewport);
glSelectBuffer(200, selectBuffer);
glRenderMode(GL_SELECT);
glInitNames();
glPushName(0);
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
gluPerspective(45.0f, (double)width / (double)height, 0.05f, 100.0f);
double centerX = (double)width / 2.0;
double centerY = (double)height / 2.0;
gluPickMatrix(centerX, centerY, 5.0f, 5.0f, viewport);
transformWorld();
int i;
for(i = 0; i < NUM_OBJECTS; i ++)
{
glLoadName(i + 1);
drawObject(i);
}
hits = glRenderMode(GL_RENDER);
if(hits > 0)
{
int znear;
znear = selectBuffer[2];
selected = selectBuffer[3];
for(i = 1; i < hits; i ++)
{
if(selectBuffer[4 * i + 2] > znear)
{
znear = selectBuffer[4 * i + 2];
selected = selectBuffer[4 * i + 3];
}
}
} else selected = -1;
glPopName();
glPopMatrix();
glFlush();
}
此时我应该注意到我完全在C中工作。再次,这一切都很好。正确选择了最近的对象(我知道这是因为我在渲染函数中使用selected
变量为当前选中的红色对象着色)。但这真的不够信息,因为仅仅基于此,屏幕中心的指针可以指向该对象的任何一个面。我希望能够在对象上选择单个面,同时还能够识别对象本身已被选中。到目前为止,我尝试过的两件事情是:1)使用glPushName
和glPopName
代替glLoadName
来绘制pickObject
函数中的每个对象,然后使用{{1 }}和glPushName
为glPopName
函数中的每个单独的face,但是没有产生我想要的结果,以及2)创建一个名为drawObject
的完全独立的函数,我运行正确在pickFace
函数之后。它做同样的事情,但只渲染当前选出的对象并设置变量pickObject
而不是selectedFace
。我的猜测是,这是实现我想要的最低效的方式,但是,尽管它有效,但我想知道是否有更好的选择。
答案 0 :(得分:0)
嗯,这个答案实际上让我发布费用相当愚蠢,因为这是一个简单的解决方案,我不知何故一直在忽视。如果我已经纠正了之后从选择缓冲区中检索id的方式,那么对每个对象使用glPushName
和glPopName
,因为我们每个面都会有效。所以drawObject
函数变成了这个:
void drawObject(int i)
{
glPushName(0);
renderFace0(i);
glPopName();
glPushName(1);
renderFace1(i);
glPopName();
glPushName(2);
renderFace2(i);
glPopName();
glPushName(3);
renderFace3(i);
glPopName();
}
&#39; pickObject&#39;的更正功能是:
int i;
for(i = 0; i < NUM_OBJECTS; i ++)
{
glPushName(i);
drawObject(i);
glPopName();
}
hits = glRenderMode(GL_RENDER);
if(hits > 0)
{
int znear;
znear = selectBuffer[2];
selected = selectBuffer[3];
selectedFace = selectBuffer[4];
for(i = 1; i < hits; i ++)
{
if(selectBuffer[5 * i + 2] > znear)
{
znear = selectBuffer[5 * i + 2];
selected = selectBuffer[5 * i + 3];
selectedFace = selectBuffer[5 * i + 4];
}
}
} else selected = -1;
我错过的一个重大变化是将索引中的i * 4
更改为i * 5
,因为我在每个选择中都要查找两个名称,所以选择缓冲区的布局如下: {number of names hit, far value, near value, first name, second name, ...}
然后重复该模式。所以我的步长必须从4改为5,因为每次命中有两个名称,现在每次命中选择缓冲区中有5个数据值,而不是4个。