OpenGL生成轮廓

有时我们不需要物体的许多细节,而只需要其外围的轮廓来描绘物体大概的形状比如物体的阴影。

如果我们简单的使用线框模式绘制一个立方体如下:

image

下面介绍OpenGL生成轮廓的两种方式。

多边形偏移

多边形偏移是一个挺有用的技巧,有时会用来解决z-fighting。z-fighting在开启深度测试时,如果两个重叠物体的深度值非常接近,那么就有可能会产生z-fighting(因为在绘制物体时采用插值的方式,而插值会有一定的误差)。

如下图

image

遇到这种情况,我们就可以使用多变形偏移,对一个多边形的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();

得到的效果:

image

使用模板缓冲区

模板缓冲区类似于深度缓冲区,图元在绘制到颜色缓冲区前,需要先经过模板测试。首先我们可以通过绘制一个实心的立方体来创建一个模板(把模板缓冲区对应的值设置为1)。然后再绘制线框立方体,设置模板测试函数为不等于1的才通过测试,这样就能得到一个立方体的轮廓(去除掉了中间的线,因为中间的线不能通过模板测试)。

代码如下:

  glPushMatrix();
  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();

效果:

image

参考: http://www.codeproject.com/Articles/8499/Generating-Outlines-in-OpenGL

你可能感兴趣的:(OpenGL)