OpenGL超级宝典学习笔记——生成轮廓
有时我们不需要物体的许多细节,而只需要其外围的轮廓来描绘物体大概的形状比如物体的阴影。
如果我们简单的使用线框模式绘制一个立方体如下:
下面介绍OpenGL生成轮廓的两种方式。
多边形偏移
多边形偏移是一个挺有用的技巧,有时会用来解决z-fighting。z-fighting在开启深度测试时,如果两个重叠物体的深度值非常接近,那么就有可能会产生z-fighting(因为在绘制物体时采用插值的方式,而插值会有一定的误差)。
如下图
遇到这种情况,我们就可以使用多变形偏移,对一个多边形的z值进行偏移。
多边形偏移有三种方法,分别对应于不同的光栅化模式:GL_LINE, GL_FILL和GL_POINT.通过 glEnable传参数GL_POLYGON_OFFSET_LINE、GL_POLYGN_OFFSET_FILL和GL_POLYGON_OFFSET_POINT来启用。
通过glPolygonOffset(GLfloat factor, GLfloat units);如果启用了多边形偏移,那么在进行深度测试之前,每个片段的深度值都会加上一个计算出来的偏移值。计算公式如下:
offset = m * factor + r * units;
其中m是多边形的最大深度斜率(在光栅化过程中计算的),r是能够保证产生可解析区别的窗口坐标深度值的最小值。r因OpenGL的实现而异。通过设置factor和units来调整偏移值,来达到你想要的效果。
下面是使用多边形偏移的代码:
//保存之前的矩阵和属性
glPushMatrix();
glPushAttrib(GL_ALL_ATTRIB_BITS);
//往里移动并旋转
glTranslatef(0.0f, 0.0f, -5.0f);
glRotatef(angle, 1.0f, 1.0f, 0.0f);
//画线框立方体,制造轮廓
glColor3f(1.0f, 0.0f, 0.0f);
//设置线的宽度为3
glLineWidth(3.0f);
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
glutSolidCube(1);
//画实心立方体
glColor3f(0.0f, 0.0f, 0.0f);
//设置多边形偏移,往屏幕外靠近观察点进行偏移
glPolygonOffset(-1.5, -1.0f);
glEnable(GL_POLYGON_OFFSET_FILL);
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
glutSolidCube(1);
glPopAttrib();
glPopMatrix();
得到的效果:
使用模板缓冲区
模板缓冲区类似于深度缓冲区,图元在绘制到颜色缓冲区前,需要先经过模板测试。首先我们可以通过绘制一个实心的立方体来创建一个模板(把模板缓冲区对应的值设置为1)。然后再绘制线框立方体,设置模板测试函数为不等于1的才通过测试,这样就能得到一个立方体的轮廓(去除掉了中间的线,因为中间的线不能通过模板测试)。
代码如下:
glPushAttrib(GL_ALL_ATTRIB_BITS);
//清除模板缓冲区
glClearStencil(0);
glClear(GL_STENCIL_BUFFER_BIT);
//一开始设置为总是通过模板测试,建立模板
glStencilFunc(GL_ALWAYS, 1, 0xFFFF);
//模板测试失败时与模板测试通过但深度测试失败时,模板的值保持不修改.
//通过模板测试与深度测试时,使用上面glStencilFunc指定的 ref(1)替换掉
glStencilOp( GL_KEEP, GL_KEEP, GL_REPLACE );
glEnable( GL_STENCIL_TEST );
glTranslatef(0.0f, 0.0f, -5.0f);
glRotatef(angle, 1.0f, 1.0f, 0.0f);
//绘制实体的立方体
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
glColor3f(0.0f, 0.0f, 0.0f);
glutSolidCube(1);
//设置只有模板缓冲区值不为1的,地方才通过模板测试
glStencilFunc(GL_NOTEQUAL, 1, 0xFFFF);
//绘制线框立方体
glLineWidth(3.0f);
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
glColor3f(1.0f, 0.0f, 0.0f);
glutSolidCube(1);
glPopAttrib();
glPopMatrix();
效果: