射线拾取--进阶

时间:2021-10-04 17:11:20
下面是我射线拾取的核心代码:我参考的理论:http://www.chinaitpower.com/A/2003-01-12/46848.html

#define  BUFFER_LENGTH 64
void CPipeLineView::pick(GLfloat xpos,GLfloat ypos)
{
// Space for selection buffer  定义拣选缓冲区
GLuint selectBuff[BUFFER_LENGTH];
//xpos,ypos;
GLint viewport[4];
GLdouble mvmatrix[16],projmatrix[16];
GLint realy;
double wx1,wy1,wz1;
double wx2,wy2,wz2;


// Setup selection buffer 
glSelectBuffer(BUFFER_LENGTH, selectBuff);


glGetDoublev(GL_MODELVIEW_MATRIX,mvmatrix);
glGetDoublev(GL_PROJECTION_MATRIX,projmatrix);
glGetIntegerv(GL_VIEWPORT,viewport);


realy = viewport[3]-(GLint)ypos -1;// 左下角为坐标原点
gluUnProject((GLdouble)xpos,(GLdouble)realy,0.0,mvmatrix,projmatrix,viewport,&wx1,&wy1,&wz1);


gluUnProject((GLdouble)xpos,(GLdouble)realy,1.0,mvmatrix,projmatrix,viewport,&wx2,&wy2,&wz2);

rayStart.x =wx1;
rayStart.y =wy1;
rayStart.z =wz1;
rayEnd.x =wx2;
rayEnd.y =wy2;
rayEnd.z =wz2;

    g_color = 0.0f;
char strName[50];
if (IntersectTriangle())
{
strcpy(strName,"you have selected the triangle");
//g_color=1.0f;
}
else
{
strcpy(strName,"you haven't selected the triangle");
}
AfxMessageBox(strName);
}

bool CPipeLineView::IntersectTriangle()
{
GLfloat edge1[3];
GLfloat edge2[3];

edge1[0]=V1[0]-V0[0];
edge1[1]=V1[1]-V0[1];
edge1[2]=V1[2]-V0[2];
edge2[0]=V2[0]-V0[0];
edge2[1]=V2[1]-V0[1];
edge2[2]=V2[2]-V0[2];

float dir[3];
dir[0]=rayEnd.x-rayStart.x;
dir[1]=rayEnd.y-rayStart.y;
dir[2]=rayEnd.z-rayStart.z;
    
GLfloat w = sqrt(pow(dir[0],2)+pow(dir[1],2)+pow(dir[2],2));
dir[0] /= w;
dir[1] /= w;
dir[2] /= w;

GLfloat pvec[3];
pvec[0]= dir[1]*edge2[2] - dir[2]*edge2[1];
pvec[1]= dir[2]*edge2[0] - dir[0]*edge2[2];
pvec[2]= dir[0]*edge2[1] - dir[1]*edge2[0];

GLfloat det ;
det = edge1[0]*pvec[0]+edge1[1]*pvec[1]+edge1[2]*pvec[2];

GLfloat tvec[3];

if( det > 0 )
{

tvec[0] =rayStart.x-V0[0];
tvec[1] =rayStart.y-V0[1];
tvec[2] =rayStart.z-V0[2];
}
else
{

tvec[0] =V0[0] -rayStart.x;
tvec[1] =V0[1] -rayStart.y;
tvec[2] =V0[2] -rayStart.z;

det = -det ;

}

if( det < 0.0001f )    return false;


GLfloat u ;
u = tvec[0]*pvec[0]+ tvec[1]*pvec[1]+ tvec[2]*pvec[2];

if( u < 0.0f || u > det )   return false;

GLfloat qvec[3];
qvec[0]= tvec[1]*edge1[2] - tvec[2]*edge1[1];
qvec[1]= tvec[2]*edge1[0] - tvec[0]*edge1[2];
qvec[2]= tvec[0]*edge1[1] - tvec[1]*edge1[0];


GLfloat v;
v = dir[0]*qvec[0]+dir[1]*qvec[1]+dir[2]*qvec[2];
if( v < 0.0f || u + v > det )      return false;

GLfloat t = edge2[0]*qvec[0]+edge2[1]*qvec[1]+edge2[2]*qvec[2];
GLfloat fInvDet = 1.0f / det;
t *= fInvDet;
u *= fInvDet;
v *= fInvDet;
return true;
}

void CPipeLineView::OnLButtonDown(UINT nFlags, CPoint point) 
{
// TODO: Add your message handler code here and/or call default
pick(point.x,point.y);
DrawScene(GL_RENDER);

CView::OnLButtonDown(nFlags, point);

void CPipeLineView::DrawScene(GLint mode)
{
glMatrixMode(GL_MODELVIEW);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 
glPushMatrix();
    glTranslatef(0.0f,0.0f,-6.0f);
    glBegin(GL_TRIANGLES);
glColor3f(g_color,0.0,1.0);
glVertex3fv(V0);// 如果加了glTranslatef之类的变换函数,射线应该反向变化
glVertex3fv(V1);
glVertex3fv(V2);
glEnd();

glTranslatef(2.0f,0.0f,-6.0f);
glBegin(GL_TRIANGLES);
glColor3f(1.0,g_color,0.0);
glVertex3fv(V1);
glVertex3fv(V0);
glVertex3fv(V2);
glEnd();


glPopMatrix();
SwapBuffers(wglGetCurrentDC());
}

实现的结果如图所示[img=http://bbs.csdn.net/][/img]
如图所示:右边的黄色圆圈的地方明明不是三角形区域,但是点击过后,却显示“你已经选中了三角形”,不知道这个问题,有没有大侠遇到过,谢谢指点!

9 个解决方案

#1


图呢?

#2


这里

void CPipeLineView::OnLButtonDown(UINT nFlags, CPoint point) 
{
// TODO: Add your message handler code here and/or call default
pick(point.x,point.y);
DrawScene(GL_RENDER);

CView::OnLButtonDown(nFlags, point);
}  

pick 和 DrawScene 的调用顺序得掉换一下吧。pick 里面的
glGetDoublev(GL_MODELVIEW_MATRIX,mvmatrix);
glGetDoublev(GL_PROJECTION_MATRIX,projmatrix);
都是获得当前矩阵的,DrawScene 负责设置这些矩阵,先调用 pick 的话,这些矩阵还没设置好呢,计算结果当然有问题。

#3


引用 2 楼  的回复:
这里

C/C++ code


void CPipeLineView::OnLButtonDown(UINT nFlags, CPoint point) 
{
// TODO: Add your message handler code here and/or call default
pick(point.x,point.y);
DrawScene(GL_RENDER);
……
[img=http://bbs.csdn.net/][/img]

图片显示不出来,网址:http://bbs.csdn.net/

#4


图片显示不出来,网址:http://bbs.csdn.net/

引用 1 楼  的回复:
图呢?

#5


你好,我试着调用了两者的顺序,还是不对,不知道大侠可否给出一点建议或者指点,谢谢!
引用 2 楼  的回复:
这里

C/C++ code


void CPipeLineView::OnLButtonDown(UINT nFlags, CPoint point) 
{
// TODO: Add your message handler code here and/or call default
pick(point.x,point.y);
DrawScene(GL_RENDER);
……

#6


引用 5 楼  的回复:
你好,我试着调用了两者的顺序,还是不对,不知道大侠可否给出一点建议或者指点,谢谢!引用 2 楼  的回复:
这里

C/C++ code


void CPipeLineView::OnLButtonDown(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call d……

一时半会没了,得有完整的代码调试一下可能能发现问题,毕竟这里面数学比较多,得看看真正的计算结果才能搞明白。

#7


您好,您的邮箱是多少,我把程序发到您邮箱吧。
引用 6 楼  的回复:
引用 5 楼 的回复:

你好,我试着调用了两者的顺序,还是不对,不知道大侠可否给出一点建议或者指点,谢谢!引用 2 楼 的回复:
这里

C/C++ code


void CPipeLineView::OnLButtonDown(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here ……

#8


引用 7 楼  的回复:
您好,您的邮箱是多少,我把程序发到您邮箱吧。引用 6 楼  的回复:
引用 5 楼 的回复:

你好,我试着调用了两者的顺序,还是不对,不知道大侠可否给出一点建议或者指点,谢谢!引用 2 楼 的回复:
这里

C/C++ code


void CPipeLineView::OnLButtonDown(UINT nFlags, CPoint point)
{
// TODO……

我可以帮你调一下,不过你得先整一个能在 ubuntu 下能够用 g++ 独立编译并运行的程序。我看你的代码,应该是 MFC 的,我都没有 Windows。要是这样,我还得重新分区,再装系统,再装 VS,和其他你可能用到的类库,至少也得搞一整天,完事以后还得再删了,太费劲了。你把程序搞好以后,可以在这里通知我。

#9


真的很感谢您!
引用 8 楼  的回复:
引用 7 楼 的回复:

您好,您的邮箱是多少,我把程序发到您邮箱吧。引用 6 楼 的回复:
引用 5 楼 的回复:

你好,我试着调用了两者的顺序,还是不对,不知道大侠可否给出一点建议或者指点,谢谢!引用 2 楼 的回复:
这里

C/C++ code


void CPipeLineView::OnLButtonDown(UINT nFlags, CPoint point……

#1


图呢?

#2


这里

void CPipeLineView::OnLButtonDown(UINT nFlags, CPoint point) 
{
// TODO: Add your message handler code here and/or call default
pick(point.x,point.y);
DrawScene(GL_RENDER);

CView::OnLButtonDown(nFlags, point);
}  

pick 和 DrawScene 的调用顺序得掉换一下吧。pick 里面的
glGetDoublev(GL_MODELVIEW_MATRIX,mvmatrix);
glGetDoublev(GL_PROJECTION_MATRIX,projmatrix);
都是获得当前矩阵的,DrawScene 负责设置这些矩阵,先调用 pick 的话,这些矩阵还没设置好呢,计算结果当然有问题。

#3


引用 2 楼  的回复:
这里

C/C++ code


void CPipeLineView::OnLButtonDown(UINT nFlags, CPoint point) 
{
// TODO: Add your message handler code here and/or call default
pick(point.x,point.y);
DrawScene(GL_RENDER);
……
[img=http://bbs.csdn.net/][/img]

图片显示不出来,网址:http://bbs.csdn.net/

#4


图片显示不出来,网址:http://bbs.csdn.net/

引用 1 楼  的回复:
图呢?

#5


你好,我试着调用了两者的顺序,还是不对,不知道大侠可否给出一点建议或者指点,谢谢!
引用 2 楼  的回复:
这里

C/C++ code


void CPipeLineView::OnLButtonDown(UINT nFlags, CPoint point) 
{
// TODO: Add your message handler code here and/or call default
pick(point.x,point.y);
DrawScene(GL_RENDER);
……

#6


引用 5 楼  的回复:
你好,我试着调用了两者的顺序,还是不对,不知道大侠可否给出一点建议或者指点,谢谢!引用 2 楼  的回复:
这里

C/C++ code


void CPipeLineView::OnLButtonDown(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call d……

一时半会没了,得有完整的代码调试一下可能能发现问题,毕竟这里面数学比较多,得看看真正的计算结果才能搞明白。

#7


您好,您的邮箱是多少,我把程序发到您邮箱吧。
引用 6 楼  的回复:
引用 5 楼 的回复:

你好,我试着调用了两者的顺序,还是不对,不知道大侠可否给出一点建议或者指点,谢谢!引用 2 楼 的回复:
这里

C/C++ code


void CPipeLineView::OnLButtonDown(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here ……

#8


引用 7 楼  的回复:
您好,您的邮箱是多少,我把程序发到您邮箱吧。引用 6 楼  的回复:
引用 5 楼 的回复:

你好,我试着调用了两者的顺序,还是不对,不知道大侠可否给出一点建议或者指点,谢谢!引用 2 楼 的回复:
这里

C/C++ code


void CPipeLineView::OnLButtonDown(UINT nFlags, CPoint point)
{
// TODO……

我可以帮你调一下,不过你得先整一个能在 ubuntu 下能够用 g++ 独立编译并运行的程序。我看你的代码,应该是 MFC 的,我都没有 Windows。要是这样,我还得重新分区,再装系统,再装 VS,和其他你可能用到的类库,至少也得搞一整天,完事以后还得再删了,太费劲了。你把程序搞好以后,可以在这里通知我。

#9


真的很感谢您!
引用 8 楼  的回复:
引用 7 楼 的回复:

您好,您的邮箱是多少,我把程序发到您邮箱吧。引用 6 楼 的回复:
引用 5 楼 的回复:

你好,我试着调用了两者的顺序,还是不对,不知道大侠可否给出一点建议或者指点,谢谢!引用 2 楼 的回复:
这里

C/C++ code


void CPipeLineView::OnLButtonDown(UINT nFlags, CPoint point……