代码改变世界
[登录 · 注册]
  • opengl中拾取操作的实现
  • opengl采用一种比较复杂的方式来实现拾取操作,即选择模式。选择模式是一种绘制模式,它的基本思想是在一次拾取操作时,系统会根据拾取操作的参数(如鼠标位置)生成一个特定视景体,然后又系统重新绘制场景中的所有图元,但这些图元并不会绘制到颜色缓存中,系统跟踪有哪些图元绘制到了这个特定的视景体中,并将这些对象的标识符保存到拾取缓冲区数组中。

    步骤:

    1、设置拾取缓冲区:void glSelectBuffer(GLsizei n,GLunint *buff);

    2、进入选择模式:指定选择模式采用函数:GLint glRenderMode(GLenum mode);

    3、名字堆栈操作:

    初始化名字堆栈:void glInitNames();

    压栈:void glPushNmae(GLuint name);

    弹栈:void glLoadName(GLuint name);

    出栈:void glPopNmae();

    4、设置合适的变换过程:矩形拾取窗口来实现拾取:gluPickMatrix(xPick,yPick,widthPick,heightPick,*vp);

    5、位每个图元分配名字并绘制

    6、切换回渲染模式

    7、分析选择缓冲区中的数据

    程序如下:

    #include"gl/glut.h"
    #include"stdio.h"
    #include"iostream"
    using namespace std;
    const GLint pickSize=32;//拾取缓冲区的大小
    int winWidth=400,winHeight=300;
    void Initial(void)
    {
        glClearColor(1.0f,1.0f,1.0f,1.0f);
    }
    //按照指定的模式绘制矩形对象
    void DrawRect(GLenum mode)
    {
        if(mode==GL_SELECT)glPushName(1);//将名字1压入堆栈
        glColor3f(1.0f,0.0f,0.0f);
        glRectf(60.0f,50.0f,150.0f,150.0f);//绘制红色矩形
        if(mode==GL_SELECT)glPushName(2);//将名字2压入堆栈
        glColor3f(0.0f,1.0f,0.0f);
        glRectf(230.0f,50.0f,330.0f,150.0f);//绘制绿色矩形
        if(mode==GL_SELECT)glPushName(3);//将名字3压入堆栈
        glColor3f(0.0f,0.0f,1.0f);
        glRectf(140.0f,140.0f,240.0f,240.0f);//绘制蓝色矩形
    }
    void ProcessPicks(GLint nPicks,GLuint pickBuffer[])
    {
        GLint i;
        GLuint name,*ptr;
        printf("选中的数目为%d个
    ",nPicks);
        ptr=pickBuffer;
        for(i=0;i<nPicks;i++)
        {
            name=*ptr;//选中图元在堆栈中的位置
            ptr+=3;//跳过名字和深度信息
            ptr+=name-1;//根据位置信息获得选中的图元名字
            if(*ptr==1)printf("你选择了红色图元
    ");
            if(*ptr==2)printf("你选择了绿色图元
    ");
            if(*ptr==3)printf("你选择了蓝色图元
    ");
            ptr++;
        }
        printf("
    
    ");
    }
    
    void ChangeSize(int w,int h)
    {
        winWidth=w;
        winHeight=h;
        glViewport(0,0,w,h);//指定视区,即指定窗口中用于图形显示的区域
        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();
        gluOrtho2D(0.0,winWidth,0.0,winHeight);
    }
    void Display(void)
    {
        glClear(GL_COLOR_BUFFER_BIT);
        DrawRect(GL_RENDER);//用渲染模式绘制图形
        glFlush();
    }
    void MousePlot(GLint button,GLint action,GLint xMouse,GLint yMouse)
    {
        GLuint pickBuffer[pickSize];
        GLint nPicks,vp[4];
        if(button==GLUT_LEFT_BUTTON&&action==GLUT_DOWN)
        {
            glSelectBuffer(pickSize,pickBuffer);//设置选择缓冲区
            glRenderMode(GL_SELECT);//激活选择模式
            glInitNames();//初始化名字堆栈
            glMatrixMode(GL_PROJECTION);
            glPushMatrix();//将当前的投影矩阵复制一个并压入堆栈
            glLoadIdentity();
            glGetIntegerv(GL_VIEWPORT,vp);//获得当前窗口显示区域的参数
            //定义一个10*10的选择区域
            gluPickMatrix(GLdouble(xMouse),GLdouble(vp[3]-yMouse),10.0,10.0,vp);
            gluOrtho2D(0.0,winWidth,0.0,winHeight);
            DrawRect(GL_SELECT);//用选择模式绘制图形
            //恢复投影变换
            glMatrixMode(GL_PROJECTION);
            glPopMatrix();//将投影矩阵堆栈中的栈顶元素删除
            glFlush();
            //获得选择集并输出
            nPicks=glRenderMode(GL_RENDER);
            ProcessPicks(nPicks,pickBuffer);//输出选择结果
            glutPostRedisplay();
    
    
        }
    }
    int main(int argc,char *argv[])
    {
        glutInit(&argc,argv);
        glutInitDisplayMode(GLUT_SINGLE|GLUT_RGB);
        glutInitWindowSize(400,300);
        glutInitWindowPosition(100,100);
        glutCreateWindow("拾取操作");
        glutDisplayFunc(Display);
        glutReshapeFunc(ChangeSize);
        glutMouseFunc(MousePlot);
        Initial();
        glutMainLoop();
        return 0;
    }
    View Code
  • 【推广】 阿里云小站-上云优惠聚集地(新老客户同享)更有每天限时秒杀!
    【推广】 云服务器低至0.95折 1核2G ECS云服务器8.1元/月
    【推广】 阿里云老用户升级四重礼遇享6.5折限时折扣!
  • 原文:https://www.cnblogs.com/acm-jing/p/4374331.html
Copyright 2008-2020 晋ICP备12007731号-1