这次我们在上次深度测试的基础上继续添加代码;
对应知识点,教程讲的很详细了,下面我在代码里面再注释下:
这次需要额外添加一个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的片段则无法通过测试,此时这部分的片段将会被舍弃,而边缘部分,因为我们的边框比箱子要大,这部分的模板测试得以通过,因此能够绘制出来;
以上就是物体边框的主要实现步骤了;
来源:oschina
链接:https://my.oschina.net/u/2009228/blog/4914762