我做一个鼠标拾取的程序,但总是拾取错误。问题简单描述下,我用的Win32做的一个图形程序,我的绘制图形的函数代码如下void OpenGL::Draw(GLfloat position_x,GLfloat position_y,GLfloat position_z,GLfloat angle,GLfloat angle_xz,GLfloat distance,GLfloat jump){ //这个结构是主显示渲染过程 { glClearColor(0.5f,0.5f,0.5f,1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //glLoadIdentity(); glMatrixMode(GL_MODELVIEW); glPushMatrix(); glInitNames(); glPushName(0);glRotatef(angle_xz,1.0f,0.0f,0.0f); glRotatef(angle,0.0f,1.0f,0.0f); glTranslatef(0.0f,0.0f-jump,0); glTranslatef(position_x+0.0f,position_y-1.0f,position_z);//glPushMatrix(); //glTranslatef(5.0f,0.0f,0.0f); //zhuzi(1.0f,1.0f,10.0f,10,10); //glPopMatrix(); //地面绘制 glBindTexture(GL_TEXTURE_2D, texture[0]); glBegin(GL_QUADS); glTexCoord2f(100,100); glVertex3f(50.0f,0.0f,50.0f); glTexCoord2f(-100,100); glVertex3f(-50.0f,0.0f,50.0f); glTexCoord2f(-100,-100); glVertex3f(-50.0f,0.0f, -50.0f); glTexCoord2f(100,-100); glVertex3f(50.0f,0.0f, -50.0f); glEnd();glPushMatrix(); glLoadName(1); glBegin(GL_TRIANGLES); glVertex3f(0.0f,0.0f,0.0f); glVertex3f(1.0f,1.0f,0.0f); glVertex3f(1.0f,0.0f,0.0f); glEnd(); glPopMatrix(); glPopMatrix(); //恢复最初模型矩阵 }SwapBuffers(hDC);}我在响应了一个鼠标左键的电击事件,事件代码如下 GLuint selectBuff[1024];GLint hits, viewport[4];glSelectBuffer(1024, selectBuff);glGetIntegerv(GL_VIEWPORT, viewport);glMatrixMode(GL_PROJECTION); glPushMatrix();glRenderMode(GL_SELECT);glLoadIdentity(); gluPickMatrix(x, viewport[3] - y, 2,2, viewport); gluPerspective(45.0f,(GLfloat)800/(GLfloat)600,0.1f,200.0f);gl.Draw(camera.x,camera.y,camera.z,camera.angle,camera.angle_xz,camera.distance,camera.jump);hits = glRenderMode(GL_RENDER);if(hits == 1) { int i = hits; //这里出问题 } // Restore the projection matrix glMatrixMode(GL_PROJECTION); glPopMatrix(); // Go back to modelview for normal rendering glMatrixMode(GL_MODELVIEW);我设置了断点,发现每次拾取的时候总是拾取一个命名为0的图元,我并没有命名0号图元啊,我想拾取我绘图函数中最后一个三角形,但总不成功,我还找不到问题的所在,希望达人指点下,不胜感激~~我想知道我程序哪里出问题了,拾取的例子我有很多,但我的程序哪里出问题了我总找不到答案,希望有人能找到我程序的问题,谢谢了
这是一个关于拾取的 程序我想要鼠标移动到 每个方块时方块改变颜色 移开时颜色在回复原来的样子可是这个 程序只是在移动到方块上时改变颜色 而移动开时没有任何的变化想了 很久不知道该如何解决这个问题 希望各位路过的哥哥 可以帮我看看 给我个解决的方法 谢谢#include <stdio.h>#include <stdlib.h>#include <GL/glut.h>int board[3][3];void init(void){ int i,j; for(i=0;i<3;i++) for(j=0;j<3;j++) board[i][j] = 0; glClearColor(0.0, 0.0, 0.0, 0.0);}void drawSquares(GLenum mode){ GLuint i,j; for (i=0;i<3;i++){ if(mode == GL_SELECT) glLoadName(i); for(j=0;j<3;j++){ if(mode == GL_SELECT) glPushName(j); glColor3f((GLfloat)i/3.0, (GLfloat)j/3.0, (GLfloat)board[i][j]/3.0); glRecti(i,j,i+1,j+1); if(mode == GL_SELECT) glPopName(); } }}void processHits(GLint hits,GLuint buffer[]){ GLint i,j; GLuint ii = 0,jj = 0,names,*ptr; printf("hits = %d\n",hits); ptr = (GLuint *) buffer; for(i=0;i < hits;i++) names = *ptr; printf(" number of names for this hit = %d\n", names); ptr++; ptr++; ptr++;printf(" names are "); for (j =0;j<names;j++){ printf("%d ", *ptr); if (j==0) ii = *ptr; else if (j == 1) jj = *ptr; ptr++; } printf("\n"); board[ii][jj] = 1;}#define BUFSIZE 512void pickSquares(int x,int y){ GLuint selectBuf[BUFSIZE]; GLuint hits; GLint viewport[4]; //if(hits >= 10) // return; glGetIntegerv(GL_VIEWPORT, viewport); glSelectBuffer(BUFSIZE,selectBuf); (void) glRenderMode(GL_SELECT); glInitNames(); glPushName(0); glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); gluPickMatrix((GLdouble) x,(GLdouble)(viewport[3]-y), 5.0,5.0, viewport); gluOrtho2D(0.0,3.0,0.0,3.0); drawSquares(GL_SELECT); glMatrixMode(GL_PROJECTION); glPopMatrix(); glFlush(); hits = glRenderMode(GL_RENDER); processHits(hits,selectBuf); glutPostRedisplay();} void display(void){ glClear(GL_COLOR_BUFFER_BIT); drawSquares(GL_RENDER); glFlush();}void reshape(int w,int h){ glViewport(0,0,w,h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluOrtho2D(0.0,3.0,0.0,3.0); glMatrixMode(GL_MODELVIEW); glLoadIdentity();}int main(int argc,char** argv){ glutInit(&argc,argv); glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB); glutInitWindowSize(200,200); glutInitWindowPosition(100,100); glutCreateWindow(argv[0]); init(); glutPassiveMotionFunc(pickSquares); glutReshapeFunc(reshape); glutDisplayFunc(display); glutMainLoop(); return 0;} 作者:eastcowboy 发表时间:2008-9-22 22:10:00 第1楼 /*OpenGL演示程序使用到的技术1. 多窗口显示2. OpenGL选择功能3. 根据二维的窗口坐标计算出三维坐标操作步骤1. 程序运行后可以看到左边的“工具栏”和右边的“主窗口”2. 在工具栏中用鼠标点击任意物体,即可选择该物体。3. 在主窗口中移动鼠标,如果有物体被选择,则将该物体的“预览”绘制到鼠标处4. 在主窗口中按下鼠标,如果有物体被选择,则在鼠标处添加一个与选择物体相同的物体5. 最多可以添加MAX_OBJECT个物体编程语言:C语言调试环境:软件 -- Windows XP SP2 + Visual Studio 2005 SP1英文 + GLUT工具包3.7版 硬件 -- 奔腾4 3.0G + DDR 2G + IBM945G集成显卡*///============================================================================// 所需要的头文件//============================================================================#include <gl/glut.h>#include <stdio.h>//============================================================================// 常量定义//============================================================================// 最大可以添加的物体数#define MAX_OBJECT 10//============================================================================// 类型定义//============================================================================// “物体”数据,保存了物体的类型和位置typedef struct _tag_Object { int type; // 1 - 茶壶, 2 - 球, 3 - 圆锥 GLdouble pos_x; GLdouble pos_y; GLdouble pos_z;} Object;//============================================================================// 全局变量//============================================================================// 当前已经添加的物体(数组)Object object_list[MAX_OBJECT];// 当前已经添加的物体数量int object_count = 0;// 主窗口中鼠标的位置(x, y)int mouseX_AtMain = 0;int mouseY_AtMain = 0;// 当前选择的物体类型(0 - 未选择, 1 - 茶壶, 2 - 球, 3 - 圆锥)int select_object_type = 0; 作者:eastcowboy 发表时间:2008-9-22 22:11:00 第2楼 //============================================================================// 左边“菜单栏”所需要的函数//============================================================================// 画出三个可以选择的物体// 注意本函数有两个地方会用到。一是正常的绘制,二是用于OpenGL选择模式。// 因此会用glLoadName这样的函数void __left_display() { static const GLfloat color_selected[] = {0.75f, 0.75f, 0.95f}; static const GLfloat color_unselected[] = {0.4f, 0.4f, 0.4f}; // 画一个茶壶 glLoadName(1); glColor3fv( (select_object_type==1) ? color_selected : color_unselected ); glPushMatrix(); glTranslatef(75.0f, 470.0f*3/4, 0); glutSolidTeapot(30); glPopMatrix(); // 画一个球 glLoadName(2); glColor3fv( (select_object_type==2) ? color_selected : color_unselected ); glPushMatrix(); glTranslatef(75.0f, 470.0f/2, 0); glutSolidSphere(30.0, 20, 20); glPopMatrix(); // 画一个圆锥 glLoadName(3); glColor3fv( (select_object_type==3) ? color_selected : color_unselected ); glPushMatrix(); glTranslatef(75.0f, 470.0f/4, 0); glRotatef(-90.0f, 1.0f, 0.0f, 0.0f); glutSolidCone(30.0, 50.0, 30, 1); glPopMatrix();}// 菜单栏需要绘制时调用此函数void left_display(void) { glClear(GL_COLOR_BUFFER_BIT); __left_display(); glutSwapBuffers(); glutReportErrors();}// 在鼠标点击菜单栏时调用此函数// 函数中会使用OpenGL的选择功能来判断哪个物体被选中void left_mouse(int button, int state, int x, int y) { GLdouble saved_projection_matrix[16]; GLint viewport[4]; GLuint select_buffer[512]; GLint buffer_count; if( state != GLUT_DOWN ) return; glGetDoublev(GL_PROJECTION_MATRIX, saved_projection_matrix); glGetIntegerv(GL_VIEWPORT, viewport); y = viewport[3] - y; glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); gluPickMatrix(x, y, 1, 1, viewport); glMultMatrixd(saved_projection_matrix); glMatrixMode(GL_MODELVIEW); glSelectBuffer( sizeof(select_buffer)/sizeof(select_buffer[0]), select_buffer); glRenderMode(GL_SELECT); glInitNames(); glPushName(0); __left_display(); buffer_count = glRenderMode(GL_RENDER); if( buffer_count < 0 ) { printf("OpenGL 选择缓冲区溢出\n"); } else if( buffer_count == 0 ) { select_object_type = 0; printf("未选择任何物体\n"); } else { int i; GLuint* ptr = select_buffer; for(i=0; i<buffer_count; ++i) { int name = select_buffer[i*4+3]; switch(name) { case 1: printf("选择了茶壶\n"); select_object_type = 1; break; case 2: printf("选择了球\n"); select_object_type = 2; break; case 3: printf("选择了圆锥\n"); select_object_type = 3; break; } } } glMatrixMode(GL_PROJECTION); glPopMatrix(); glMatrixMode(GL_MODELVIEW); glutPostRedisplay();} 作者:eastcowboy 发表时间:2008-9-22 22:11:00 第3楼 //============================================================================// 左边“菜单栏”所需要的函数//============================================================================// 根据二维的窗口坐标计算出三维坐标,// 计算结果放到pObj->pos_x, pObj->pos_y, pObj->pos_z中// 注意:要正确使用本函数,必须开启深度测试。// 即必须分配深度缓冲区,并且使用glEnable(GL_DEPTH_TEST)void calc_xyz(int winx, int winy, Object* pObj) { GLdouble modelview_matrix[16]; GLdouble projection_matrix[16]; GLint viewport[4]; GLfloat winz; glGetDoublev(GL_MODELVIEW_MATRIX, modelview_matrix); glGetDoublev(GL_PROJECTION_MATRIX, projection_matrix); glGetIntegerv(GL_VIEWPORT, viewport); glReadPixels(winx, winy, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &winz); gluUnProject(winx, winy, winz, modelview_matrix, projection_matrix, viewport, &(pObj->pos_x), &(pObj->pos_y), &(pObj->pos_z));}// 根据物体类型的不同,绘制出不同的物体// 1 - 茶壶, 2 - 球, 3 - 圆锥void draw_object(int type) { switch( type ) { case 1: glColor3f(0.2f, 0.7f, 0.5f); glTranslatef(0.0f, 0.3f, 0.0f); glutSolidTeapot(0.3); break; case 2: glColor3f(0.3f, 0.6f, 0.8f); glTranslatef(0.0f, 0.3f, 0.0f); glutSolidSphere(0.3, 20, 20); break; case 3: glColor3f(0.6f, 0.6f, 0.3f); glRotatef(-90.0f, 1.0f, 0.0f, 0.0f); glutSolidCone(0.3, 0.4, 30, 1); break; }}// 鼠标在主窗口中移动时,记录鼠标的位置// 如果选择了物体类型,则通过glutPostRedisplay重新绘制主窗口,// 绘制时会把所选的物体绘制在鼠标位置处void main_passiveMotion(int x, int y) { mouseX_AtMain = x; mouseY_AtMain = 470 - y; if( select_object_type != 0 ) glutPostRedisplay();}// 鼠标点击主窗口,尝试添加物体// 若添加成功则调用glutPostRedisplay重新绘制,以便让添加的物体被绘制出来void main_mouse(int button, int state, int x, int y) { if( state != GLUT_DOWN ) return; if( !select_object_type ) return; if( object_count >= MAX_OBJECT ) { printf("物体数量达到最大,无法再添加\n"); return; } object_list[object_count].type = select_object_type; calc_xyz(x, 470 - y, &object_list[object_count]); printf("在(%f, %f, %f)处增加物体。\n", object_list[object_count].pos_x, object_list[object_count].pos_y, object_list[object_count].pos_z); ++object_count; glutPostRedisplay();}// 主窗口需要绘制时调用本函数void main_display(void) { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // disable lighting glDisable(GL_LIGHTING); // ground glColor3f(0.4f, 0.2f, 0.2f); glBegin(GL_QUADS); glVertex3f(-2.0f, 0.0f, -2.0f); glVertex3f(-2.0f, 0.0f, 2.0f); glVertex3f( 2.0f, 0.0f, 2.0f); glVertex3f( 2.0f, 0.0f, -2.0f); glEnd(); // mouse object if( select_object_type != 0 ) { Object dummy; calc_xyz(mouseX_AtMain, mouseY_AtMain, &dummy); glPushMatrix(); glTranslated(dummy.pos_x, dummy.pos_y, dummy.pos_z); draw_object(select_object_type); glPopMatrix(); } // enable lighting glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); glEnable(GL_COLOR_MATERIAL); glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE); // objects { int i; glColor3f(1.0f, 1.0f, 0); for(i=0; i<object_count; ++i) { glPushMatrix(); glTranslated(object_list[i].pos_x, object_list[i].pos_y, object_list[i].pos_z); draw_object(object_list[i].type); glPopMatrix(); } } glutSwapBuffers(); glutReportErrors();}// 最大的窗口在需要绘制时调用本函数void display(void) { glClearColor(0.5f, 0.5f, 0.5f, 1.0f); glClear(GL_COLOR_BUFFER_BIT); glutSwapBuffers();} 作者:eastcowboy 发表时间:2008-9-22 22:12:00 第4楼 // main函数int main(int argc, char* argv[]) { int window, left_window, main_window; glutInit(&argc, argv); glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH); glutInitWindowPosition(100, 100); glutInitWindowSize(640, 480); // 父窗口 window = glutCreateWindow("OpenGL"); glutDisplayFunc(&display); // 左边的子窗口 left_window = glutCreateSubWindow(window, 5, 5, 150, 470); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(0.0, 150.0, 0.0, 470.0, 100.0, -100.0); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glTranslatef(0.375f, 0.375f, 0.0f); glutDisplayFunc(&left_display); glutMouseFunc(&left_mouse); // 主体的子窗口 main_window = glutCreateSubWindow(window, 165, 5, 470, 470); glEnable(GL_DEPTH_TEST); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(60.0, 1.0, 0.5, 10.0); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); gluLookAt(4.0, 3.0, 3.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0); glutDisplayFunc(&main_display); glutMouseFunc(&main_mouse); glutPassiveMotionFunc(&main_passiveMotion); glutMainLoop();}