回 帖 发 新 帖 刷新版面

主题:openGL选择中遇到问题

void CMiddleView::processSelection(int x , int y)
{
   GLdouble modelview[16];
   GLdouble projection[16];
   GLuint selectBuf[512];
   GLint hits;
   GLint viewport[4];

   
   glGetDoublev(GL_MODELVIEW_MATRIX, modelview);
   glGetDoublev(GL_PROJECTION_MATRIX, projection);
   glGetIntegerv(GL_VIEWPORT, viewport);
   glSelectBuffer(512,selectBuf);
   (void)glRenderMode(GL_SELECT);
   //glInitNames();
   //glPushName(0);

   glMatrixMode(GL_PROJECTION); 
   glPushMatrix();    
   glLoadIdentity();

   gluPickMatrix((GLdouble)(x), (GLdouble)(viewport[3]-y),   3.0, 3.0, viewport);
   glMultMatrixd(projection);

   glMultMatrixd(modelview);
   
   
   //gluPerspective(45,(viewport[2]-viewport[0])/(viewport[3]-viewport[1]),0.1,100);

   glMatrixMode(GL_MODELVIEW);
   Object(GL_SELECT);
  
 
   hits = glRenderMode(GL_RENDER);
   if ( hits > 0 ) 
   { 
    processHits(hits,selectBuf);
   }else printf("未选中");
 
   glMatrixMode(GL_PROJECTION);
   glPopMatrix();   
   glMatrixMode(GL_MODELVIEW);

  
}



结果显示总是hit=0,我做的是一个三维网格,想选其中的某个单元,用gluLookAt控制模型的旋转放大等,求教

回复列表 (共4个回复)

沙发

看不出问题,我的代码与楼主的差不多,但运行正常。
代码如下:
[code=c]#include <GL/glut.h>

// 在四种颜色之间切换
static const int COLOR_COUNT = 4;

// 四种颜色
static GLfloat s_color_table[COLOR_COUNT][3] = {
    {0.5f, 0.0f, 0.0f},
    {0.0f, 0.5f, 0.0f},
    {0.0f, 0.0f, 0.5f},
    {0.5f, 0.5f, 0.0f},
};

// 当前使用的颜色
static int s_color_index = 0;

// 旋转
static GLfloat rotate = 0;

static void draw() {
    glPushMatrix();
    glRotatef(rotate, 0, 1, 0);
    glutSolidTeapot(20);
    glPopMatrix();
}

static void display() {
    // 设置矩阵
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective(45, 1, 0.5, 500);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    gluLookAt(0, 50, 100, 0, 0, 0, 0, 1, 0);

    // 设置颜色
    glColor3fv(s_color_table[s_color_index]);

    // 绘制
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    draw();
    glutSwapBuffers();
    glutPostRedisplay();
    glutReportErrors();

    // 旋转
    rotate += 0.3f;
    if (rotate >= 360.0f) {
        rotate -= 360.0f;
    }
}

static void mouse(int button, int state, int x, int y) {
    // 只响应鼠标左键按下的消息,其它一律略过
    if (button != GLUT_LEFT_BUTTON || state != GLUT_DOWN) {
        return;
    }

    // 纵向坐标需要反转
    // 因为GLUT把左上角作为坐标原点,而OpenGL把左下角作为坐标原点
    int windowWidth = glutGet(GLUT_WINDOW_WIDTH);
    int windowHeight = glutGet(GLUT_WINDOW_HEIGHT);
    y = windowHeight - y;

    // 取得viewport和projectionMatrix
    GLint viewport[4];
    glGetIntegerv(GL_VIEWPORT, viewport);

    GLfloat modelviewMatrix[16];
    GLfloat projectionMatrix[16];
    glGetFloatv(GL_MODELVIEW_MATRIX, modelviewMatrix);
    glGetFloatv(GL_PROJECTION_MATRIX, projectionMatrix);

    const int SELECT_BUFFER_SIZE = 256;
    GLuint arrSelectBuffer[SELECT_BUFFER_SIZE];

    // OpenGL选择模式,代码
    glSelectBuffer(SELECT_BUFFER_SIZE, arrSelectBuffer);
    glRenderMode(GL_SELECT);

    glMatrixMode(GL_PROJECTION);
    glPushMatrix();
    glLoadIdentity();
    gluPickMatrix(x, y, 1, 1, viewport);
    glMultMatrixf(projectionMatrix);
    glMultMatrixf(modelviewMatrix);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();

    // glInitNames();
    // glPushName(0);
    draw();

    GLint r = glRenderMode(GL_RENDER);

    // 如果鼠标点中了物体,修改物体颜色
    if (r != 0) {
        ++s_color_index;
        if (s_color_index >= COLOR_COUNT) {
            s_color_index = 0;
        }
    }

    glMatrixMode(GL_PROJECTION);
    glPopMatrix();
    glMatrixMode(GL_MODELVIEW);
}

int main(int argc, char* argv[]) {
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH);
    glutInitWindowSize(640, 480);
    glutInitWindowPosition(100, 100);
    glutCreateWindow("test");

    glutDisplayFunc(&display);
    glutMouseFunc(&mouse);

    glEnable(GL_DEPTH_TEST);
    glEnable(GL_LIGHTING);
    glEnable(GL_LIGHT0);
    glEnable(GL_COLOR_MATERIAL);
    glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE);

    glutMainLoop();
    return 0;
}[/code]

但我更喜欢不要修改model view矩阵,像这样做:
    glSelectBuffer(SELECT_BUFFER_SIZE, arrSelectBuffer);
    glRenderMode(GL_SELECT);

    glMatrixMode(GL_PROJECTION);
    glPushMatrix();
    glLoadIdentity();
    gluPickMatrix(x, y, 1, 1, viewport);
    glMultMatrixf(projectionMatrix);
    glMatrixMode(GL_MODELVIEW);
    glPushMatrix();

    // glInitNames();
    // glPushName(0);
    draw();

    GLint r = glRenderMode(GL_RENDER);

    // 如果鼠标点中了物体,修改物体颜色
    if (r != 0) {
        ++s_color_index;
        if (s_color_index >= COLOR_COUNT) {
            s_color_index = 0;
        }
    }

    glMatrixMode(GL_PROJECTION);
    glPopMatrix();
    glMatrixMode(GL_MODELVIEW);
    glPopMatrix();

这样可以避免取回model view矩阵。并且由于使用push/pop,完成之后model view矩阵可以维持不变。

板凳

我不是用glRotatef这些函数来控制,而是用gluLookAt,是不是在改变视角的时候也要push/pop?

3 楼

[quote]我不是用glRotatef这些函数来控制,而是用gluLookAt,是不是在改变视角的时候也要push/pop?[/quote]
用什么函数来控制都无所谓,反正都是操作model view矩阵。这个应该不是重点。
我觉得最关键的一点是,各个矩阵之间应该满足这个关系:选择时所用矩阵,正好就是gluPickMatrix所得矩阵乘以渲染时所用矩阵。
所有需要进行选择的图形,全部都要满足这个关系才行。楼主可以针对这一点进行检查。

楼主的代码中,把原来的model view矩阵乘到projection矩阵里面去了,这时如果绘制物体的代码里还有对projection矩阵的操作的话,就无法满足上述关系(因为矩阵乘法只有结合律,没有交换律),导致选择失败。还有就是model view矩阵,如果执行glGetDoublev(GL_MODELVIEW_MATRIX, modelview);之时它就已经乘过gluLookAt的矩阵,在绘制之时如果再乘一次,也会造成上述关系无法满足。
总之,多多的检查矩阵处理吧。楼主加油。

4 楼


谢了,再仔细检查下

我来回复

您尚未登录,请登录后再回复。点此登录或注册