基于QT的OpenGL教程学习11 -模板测试

不想你离开。 提交于 2021-01-20 02:15:39

教程

这次我们在上次深度测试的基础上继续添加代码;

对应知识点,教程讲的很详细了,下面我在代码里面再注释下:

这次需要额外添加一个cubeframe类,用来渲染箱子的边框;其主要内容和cube一致,但是它并不需要纹理,这只是一个纯色的物体;

下面我们着重说下渲染部分的代码:

void MyGLWidget::initializeGL()
{
    // 为当前环境初始化OpenGL函数
    initializeOpenGLFunctions();

    Cube* cub=new Cube(width(),height());
    cubevec.append(cub);
    cub->ShapeCamera=m_camera;
    cub->SetTranslateVec(QVector3D(-1.0f, 0.0f, -1.0f));

    CubeFrame* frame1=new CubeFrame(width(),height());
    framevec.append(frame1);
    frame1->ShapeCamera=m_camera;
    frame1->SetTranslateVec(QVector3D(-1.0f, 0.0f, -1.0f));
    frame1->SetScale(1.1f);

    Cube* cub2=new Cube(width(),height());
    cubevec.append(cub2);
    cub2->ShapeCamera=m_camera;
    cub2->SetTranslateVec(QVector3D(2.0f, 0.0f, 0.0f));

    CubeFrame* frame2=new CubeFrame(width(),height());
    framevec.append(frame2);
    frame2->ShapeCamera=m_camera;
    frame2->SetTranslateVec(QVector3D(2.0f, 0.0f, 0.0f));
    frame2->SetScale(1.1f);

    plane=new Plane(width(),height());
    // cubevec.append(plane);
    plane->ShapeCamera=m_camera;
    plane->ChangeVisible(true);
    // plane->SetTranslateVec(QVector3D(0.0f, 0.0f, 0.0f));
    //glEnable(GL_DEPTH_TEST);
    glEnable(GL_DEPTH_TEST);
    glEnable(GL_STENCIL_TEST);
    glStencilFunc(GL_NOTEQUAL, 1, 0xFF);
    glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
    //*模板测试和深度测试都通过时将模板纸设置为glStencilFunc函数设置的ref值
}

在我们的GLwidget中将地板平面从容器中单独抽离出来,并添加一个用于储存边框的vector,和cubevec中一样添加对应的实例,只不过边框都要进行放大,这样才能在箱子(cube)的边缘添加框;

同时,在初始函数的最后要记得设置更新缓冲的方式:

glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);

下面再说一下渲染函数:

void MyGLWidget::paintGL()
{

    /*清空颜色缓存,深度缓存,模板缓存*/
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
    //此时所有片段的模板缓冲内都是0
    glEnable(GL_STENCIL_BUFFER_BIT);

    switch (curdepthfunc) {
    case DEPTHFUNC::LESS:
    {
        glDepthFunc(GL_LESS);
        break;
    }
    case DEPTHFUNC::ALWAYS:
    {
        glDepthFunc(GL_ALWAYS);
        qDebug()<<"always";
        break;
    }
    case DEPTHFUNC::NEVER:
    {
        glDepthFunc(GL_NEVER);
        qDebug()<<"never";
        break;
    }
    case DEPTHFUNC::EQUAL:
    {
        glDepthFunc(GL_EQUAL);
        break;
    }
    case DEPTHFUNC::LEQUAL:
    {
        glDepthFunc(GL_LEQUAL);
        break;
    }
    case DEPTHFUNC::GREATER:
    {
        glDepthFunc(GL_GREATER);
        break;
    }
    case DEPTHFUNC::NOTEQUAL:
    {
        glDepthFunc(GL_NOTEQUAL);
        break;
    }
    case DEPTHFUNC::GEQUAL:
    {
        glDepthFunc(GEQUAL);
        break;
    }

    }
    glStencilMask(0x00);//1.1禁止写入模板缓冲
    plane->Render();//1.2绘制地板平面,此时不会影响模板缓冲,测试总是通过

    glStencilFunc(GL_ALWAYS, 1, 0xFF);//2.1设置模板测试函数,当前总是通过测试,并将对应片段的模板缓冲设置为1
    glStencilMask(0xFF);//2.2 开启模板缓冲

    QVector<Shape*>::iterator i;
    for(i=cubevec.begin();i!=cubevec.end();++i)
    {
        //2.2绘制箱子,此时其对应的片段的模板缓冲是1 ,其余部分仍旧为0
        (*i)->Render();
    }

    glStencilFunc(GL_NOTEQUAL, 1, 0xFF);  //3.1 模板测试的通过条件是不等于1
    glStencilMask(0x00);//3.2禁止此后的操作写入模板缓冲
    glDisable(GL_DEPTH_TEST);
    for(i=framevec.begin();i!=framevec.end();++i)
    {
        //3.3绘制单色边框,此时片段中模板缓冲为1(也就是2.2中绘制箱子部分对应的片段)无法通过模板测试,因此将不会绘制
        (*i)->Render();
    }

    glStencilMask(0xFF);
    glStencilFunc(GL_ALWAYS, 0, 0xFF);
    glEnable(GL_DEPTH_TEST);
}

第一步,在渲染函数最初的位置,清空各个缓存,此时模板缓存中的值全部为0:

第二步,在步骤注释1处禁止写入模板缓冲,也就是说紧跟其后的渲染代码产生的片段更新不会影响到模板值,此时我们绘制地板;

第三步,我们开始绘制箱子,在代码注释2处,首先我们设置模板测试函数,当前总是通过,并将对应片段的模板值设置为1,其余不受影响的则依旧是0

第四步,我们开始绘制边框,在代码注释3处,我们设置模板测试函数的通过条件是不等于1,那么先前绘制箱子时,模板值已经为1的片段则无法通过测试,此时这部分的片段将会被舍弃,而边缘部分,因为我们的边框比箱子要大,这部分的模板测试得以通过,因此能够绘制出来;

以上就是物体边框的主要实现步骤了;

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!