内容简介:了解了OpenGL的渲染流程和常用API后,就可以简单的绘制出图形了。但是在绘制中可能会碰到些意想不到的问题。在默认情况下,我们所渲染的每个点、线或三角形都会在屏幕上进行光栅化,并且会按照在组合图元批次时指定的顺序进行排列,这在某些情况下会产生问题。其中一个可能出现的问题是,如果我们绘制一个由很多个三角形组成的实体对象,那么第一个绘制的三角形可能会被后面绘制的三角形覆盖。图中,圆环上有些三角形在圆环的背面,而另一些则在圆环的正面。我们应该是看不到背面的。
了解了OpenGL的渲染流程和常用API后,就可以简单的绘制出图形了。但是在绘制中可能会碰到些意想不到的问题。
在默认情况下,我们所渲染的每个点、线或三角形都会在屏幕上进行光栅化,并且会按照在组合图元批次时指定的顺序进行排列,这在某些情况下会产生问题。其中一个可能出现的问题是,如果我们绘制一个由很多个三角形组成的实体对象,那么第一个绘制的三角形可能会被后面绘制的三角形覆盖。
图中,圆环上有些三角形在圆环的背面,而另一些则在圆环的正面。我们应该是看不到背面的。
多边形的正面和背面
OpenGL中最简单的实体多边形就是三角形,它只有3个边。光栅化硬件最欢迎三角形,而现在三角形已经是OpenGL中支持的唯一一种多边形了。每3个顶点定义一个新的三角形。下图是两个三角形,它们是用6个顶点进行绘制的,这6个顶点编号依次为V0到V5。
请注意连接顶点的线段上所标示的箭头。在绘制第一个三角形时,线条将按照从V0到V1,再到V2,最后回到V0的顺序来绘制一个闭合的三角形。这个路径是按照顶点被指定的顺序沿着顺时针方向的,这种方向特性也体现在了第二个三角形中。这种顺序与方向结合来指定顶点的方式称为环绕。图中右边的三角形就被称作是顺时针环绕的。如果我们将左边三角形的V4和V5的位置进行交换,我们就得到了逆时针环绕。下图是两个三角形,它们的缠绕方向相反。
在默认情况下,OpenGL认为具有逆时针方向环绕的多边形是正面的。这意味着图3的左侧是三角形的正面,而右侧是三角形的背面。
我们常常希望为一个多边形的正面和背面分别设置不同的物理特征。我们可以完全隐藏一个多边形的背面,或者给它设置-种不同的颜色和反射属性。纹理图像在背面三角形中也是相反的。在一个场景中,使所有的多边形保持环绕方向的一致,并使用正面多边 形来绘制所有实心物体的外表面是非常重要的。
如果想改变OpenGL的这个默认行为,可以调用下面这个函数。
/* GL_CW:顺时针环绕的多边形将为正面 GL_CCW:逆时针环绕的多边形将为正面 */ g1FrontFace(GL_CW) ; 复制代码
油画法
对于这个问题,一个可能的解决办法是,对这些三角形进行排序,并且首先渲染那些较远的三角形,再在它们上方渲染那些较近的三角形。这种方式称为“油画法" ( painters algorithm )。
这种方法在计算机图形处理中是非常低效的,主要原因有两个。
- 必须对任何发生几何图形重叠地方每个像素进行两次写操作,而在存储其中进行写操作会使速度变慢。
- 对独立的三角形进行 排序 的开销会过高。
油画法弊端:如果三个三角形是叠加的情况,油画法将无法处理!
正面和背面剔除
在任何情况下,我们都应该只能看到正面,看不到背面,那为何还要浪费资源绘制背面呢?对三角形的区分正面和背面的原因之一就是为了剔除。背面剔除能够极大的提高性能,并修正图1出现的问题。这种方式是非常高效的,在渲染的图元装配阶段就整体抛弃了一些三角形,并没有执行任何不恰当的光栅化操作。
使用 glEnable
和 glDisable
函数即可设置表面剔除功能。
glEnable(GL_CULL_FACE); //开启 glDisable(GL_CULL_FACE) ; //关闭 复制代码
指明剔除的是正面还是背面调用函数 glCullFace
。
/* mode的可选值: GL_FRONT GL_BACK GL_FRONT_AND_BACK */ void glCullFace(GLenum mode); 复制代码
表面剔除后的效果
深度测试
仔细观察不难发现我们在进行表面剔除后仍然会有一些不现实的画面。
就算背面剔除能够消除位于对象背面的三角形,那么如果是重叠的独立对象又该怎么办呢?我们之前提到过油画法,这种方法是根据一种油画使用的技术而得名的。我们只要先简单地绘制背景,再在上面绘制较近的对象。这样做可能只要在画布上进行次数不多的绘制( 在手工绘制时更加有用),但对于图形硬件来说,这样做会导致在同一个片段区域重复进行绘制,而每一次绘制都会产生性能开销。如果开销过大则导致光栅化过程变慢,我们将这种方式称为“填充受限”。但是将油画法颠倒过来使用,实际上将会加速填充性能。首先绘制那些离观察者较近的对象,然后再绘制那些较远的对象。
深度测试将消除那些应该被已存在像素覆盖的像素,这将节省可观的存储器带宽。
深度测试是另外一种高效消除隐藏表面的技术。它的概念很简单:在绘制一 个像素时,将一个值(称为z值)分配给它,这个值表示它到观察者的距离。然后,当另外一个像素需要在屏幕上的同样位置进行绘制时,新像素的z值将与已经存储的像素的z值进行比较。如果新像素的z值比较大,那么它距离观察者就比较近,这样就在原来的像素上面,所以原来的像素就会被新的像素覆盖。如果新像素的z值更低,那么它 就必须位于原来像素的后面,不能遮住原来的像素。在内部,这个任务是通过深度缓冲区实现的,它存储了屏幕上每个像素的深度值。
我们在使用GLUT设置OpenGL窗口的时候,应该请求一个深度缓冲区并启用深度测试。
//申请一个颜色缓冲区和一个深度缓冲区。 glutInitDisplayMode(GLUT_DOUBLEI_GLUT_RGBA | GLUT_DEPTH); //启用深度测试 glEnable(GL_DEPTH_TEST); 复制代码
如果没有深度缓冲区,那么启用深度测试的命令将被忽略。
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- 仅使用 CSS 就可以提高页面渲染速度的 4 个技巧
- JavaScript是如何工作的:渲染引擎和优化其性能的技巧
- Octane渲染入门-渲染设置图文版
- 通过分析 WPF 的渲染脏区优化渲染性能
- React 服务器端渲染和客户端渲染效果对比
- iOS渲染-将视频原始数据(RGB,YUV)渲染到屏幕上
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Internet与WWW程序设计教程(第三版)
戴特尔 / 电子工业出版社 / 2005-8 / 95.00元
《Internet与WWW程序设计教程》(第3版)以大量生动、实用的示例讲述了如何编写多层的、客户/服务器的、数据密集的、基于Web的应用程序,介绍了如何使用XHTML、JavaScript、DHTML、Flash和XML建立客户端应用程序,也介绍了如何使用Web服务器(IIS、PWS和Apache)、数据库(SQL、MySQL、DBI和ADO)、ASP、Perl、CGI、Python、PHP、J......一起来看看 《Internet与WWW程序设计教程(第三版)》 这本书的介绍吧!