客户端是存储在CPU存储器中的,而且在应用程序中执行(或者驱动程序),驱动程序将渲染命令和数据组合起来,发动到服务器执行。
服务器和客户机在功能上是异步的,他们是各自独立的软件模块或者硬件模块。性能优化
数据先传给顶点着色器,而后是片断着色器,几何着色器(可选择)出如今二者之间 服务器
Vertex Shader
) Fragment Shader
) 片断(fragment)不是最后的像素数据,但和像素对应
片断(fragment)须要通过处理,blend,texture,lighting...,才会获得最后的像素。异步
绘图命令指定了一组顶点属性,描述了图元的几何形状和图元类型。顶点着色器使用这些顶点属性计算顶点的位置、颜色以及纹理坐标,这样才能传到片断着色器。
好比为了渲染一个三角形,顶点着色器执行3次,也就是为每一个顶点执行一次。
在目前硬件上有多个执行单元同时运行,因此这3个顶点能够同时进行处理函数
这些着色器处理过的顶点被组装到一个个独立的几何图元中,例如:三角形、线、点
对于每一个图元,必须肯定它是否位于视椎体内(3维空间显示在屏幕上的可见区域)
背面剔除操做也会执行,它根据图元是正面仍是背面,进行背面剔除 oop
光栅化阶段把图元转换成片断集合,以后会提交给片断着色器处理,这些片断集合表示能够被绘制到屏幕的像素。
输出的时每一个片断对应的屏幕坐标,和属性(颜色,纹理坐标)性能
每一个片断执行片断着色器进行填充,片断着色器会输出咱们将在屏幕上看到的颜色
当前的硬件是大规模并行运算的,同时执行上百个甚至更多这种着色器程序并不困难 测试
有3种向OpenGL着色器传递渲染数据的方法: 优化
每一个顶点都要存储的数据元素。
顶点自己就是一种属性,还有纹理坐标,颜色值和用于光照计算的表面法线。
属性会从本地客户机内存中复制存储到图形硬件中得一个缓冲区中。
这些属性只供顶点着色器使用,对片断着色器无心义spa
Uniform可使用屡次,可使用它设置一个应用于整个表面的单个颜色值
顶点着色器和片断着色器都有3d
顶点着色器和片断着色器中均可以对纹理值进行采样和筛选
咱们关心的不是屏幕坐标和像素,而是视景体中的位置属性。将这些点,线和三角形从3D空间投影到计算机屏幕的2D图形则是着色器程序和光栅化所要完成的
GL_TRIANGLE_STRIP
渲染效果图:
GL_TRIANGLE_FAN
渲染效果图
点是最简单的图元,默认点的大小是一个像素,能够经过glPointSize改变
void glPointSize(GLfloat size);
点的大小是存在限制的,咱们能够得到支持的点尺寸的范围
GLfloat sizes[2]; GLfloat step; // 获取支持的点的尺寸范围和步长 glGetFloatv(GL_POINT_SIZE_RANGE, sizes); glGetFloatv(GL_POINT_SIZE_GRANULARITY, &step);
指定的点在范围外并不会发生错误,只是限定到最接近的范围内的值
默认状况下,点和其余图元不一样,它并不会受到透视除法的影响,也就是说不会由于离视点远看上去变小。
另外,点老是正方形的,即便改变了大小点也仍是正方形,为了得到圆点,必须在抗锯齿模式下绘点。
默认状况下线段宽度为一个像素。改变线段宽度的惟一方式是使用glLineWidth
void glLineWidth(GLfloat width);
绘制三角形顶点的顺序就是指定顶点的顺序。
OpenGL默认认为具备逆时针方向环绕的多边形是正面的,反之就是多边形背面。
一个三角形若是是正面的,那么它旋转后可能变成背面(笛卡尔坐标系,绕y轴180度)
可使用下面函数改变
// GL_CW 顺时针环绕的多边形被认为是正面 // GL_CCW glFrontFace(GL_CW)
用前3个顶点指定第一个三角形,对于接下来的每一个三角形,都只须要再指定一个顶点。
优点:
+ 能够建立一组围绕一个中心点得相连三角形。
+ 第一个顶点是扇形的原点。
+ 前3个顶点指定最初的一个三角形,接下来的三角形只需指定一个顶点,它将和它相邻的顶点还有原点组成三角形。
1.开启表面剔除
glEnable(GL_CULL_FACE);
glDisable(GL_CULL_FACE);
2.指定正面仍是背面剔除
void glCullFace(Glenum mode);
绘制一个像素时,将一个表明它到观察者距离的Z值,分配给像素.
而后,当第二次在此位置绘制像素时,比较其Z值,而后决定是否绘制。
这里使用了OpenGL的深度缓冲区,它存储了屏幕上每一个像素的深度值。
启用深度测试:
glEnable(GL_DEPTH_TEST)
若是没有深度缓冲区,那么启用深度测试的命令将被忽略。
深度测试在绘制多个对象时能进一步解决性能问题,此时先绘制离观察者近的对象,那么就不用绘制距离远的对象了。
多边形(含三角形)不必定是实心的。默认下多边形是实心绘制,能够经过下面函数指定多边形渲染模式,实体,轮廓,点。
也能够指定多边形的面,正面,背面,两面
void glPolygonMode(GLeum face, GLenum mode);
有意将多个几何图形绘制到同一位置或在一个图形上绘制另外一个图形称为贴花(decal
),这样会致使深度缓冲区值相同,致使片断深度测试不可预料的经过或失败,称为Z冲突(z-fighting
)
有时为了绘制实体图形,又想在其上绘制线框图形,这是就会出现Z冲突。 这时能够在绘制线框时修改Z的偏移来解决这个问题。
注意:只能沿Z轴向镜头方向移动,偏移量必须大小适中,不然没有效果或者出现缝隙。
下面函数能够调节片断的深度值,这样就能使深度值偏移而并不实际并不改变控件中的物理位置。
void glPolygonOffset(GLfloat factor, GLfloat units);
深度偏移公式:
Depth Offset=(DZ x factor) + (r x units)
其中DZ是深度值相对于多边形屏幕区域的变化量,r 是使深度缓冲区值产生变化的最小值。并无硬性规定可以找到一个万无一失的值。
负值使z轴距离咱们更近,正值相反。
处理设置偏移值,还必须启用多边形单独偏移
// GL_POLYGON_OFFSET_FILL 填充几何图形 // GL_POLYGON_OFFSET_LINE 线 // GL_POLYGON_OFFSET_POINT 点 glEnable(GL_POLYGON_OFFSET_LINE);
裁剪(scissor)
这种提升渲染性能的方法就是只刷新屏幕上发生变化的部分,可能还须要将OpenGL的渲染限制在窗口中一个较小的矩形区域中。
OpenGL容许咱们在将要渲染的窗口中制定一个裁剪框。默认状况下,裁剪框与窗口大小同样,而且不会进行裁剪测试。
开启裁剪测试
glEnable(GL_SCISSOR_TEST);
指定裁剪框,要绘制的区域
void glScissor(GLint x, GLint y, GLsizei width, GLsizei height);
一般OpenGL渲染时会把颜色值放在颜色缓冲区中,每一个片断的深度值放在深度缓冲区中
当打开OpenGL混合功能时,下层颜色不会被清除,而是和已存在的颜色值在颜色缓冲区进行组合,不一样组合方式产生不一样特殊效果
启用混合
glEnable(GL_BLEND);
已经存在颜色缓冲区的颜色值叫目标颜色
做为新输入颜色缓冲区的颜色叫源颜色
颜色包含4个部分,红,绿,蓝,Alpha值,忽略的Alpha默认为1.0
默认混合公式以下:
Cf=(Cs*S)+(Cd*D)
其中,Cf是最终的颜色,Cs是源颜色,Cd是目标颜色,S和D分别是源颜色和目标颜色的混合因子
能够设置混合因子:
glBlendFunc(GLenum S, GLenum D);
还可使用下面函数灵活进行选择
void glBlendFuncSeparate(GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha);
在设定因子的时候,某些带CONSTANT
字样的参数值,须要一个另外的颜色常量来参与计算,这个常量经过下面函数指定的
void glBlendColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha);
改变混合公式:
void glBlendEquation(GLenum mode);
混合功能的另外一个用途是抗锯齿,多数状况,一个独立的渲染片断将会映射到计算机屏幕上的一个像素。
这些像素是正方形的,一般能够至关清楚的看到两种颜色的分界,称为锯齿
。
为了消除图元之间的锯齿状边缘,OpenGL使用混合功能来混合片断颜色,也就是把像素的目标颜色和周围像素的颜色进行混合。
glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // 还须要确保吧混合公式设置为GL_ADD(默认) // 如今对图元分别进行抗锯齿处理 glEnable(GL_POINT_SMOOTH); glEnable(GL_LINE_SMOOTH); glEnable(GL_POLYGON_SMOOTH); // 能够设置抗锯齿质量(GL_FASTEST) glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
点和直线的抗锯齿处理支持较好,可是多边形的平滑处理并无在全部平台上都获得实现。
多重采样就能够解决多边形平滑处理的问题
存在一个缓冲区,全部的图元在每一个像素上都进行屡次采样,结果就存储在这个缓冲区中。每次当某个像素更新时,会对其进行从新采样,并更新到缓冲区中
首先必须存在多重采样缓冲区,这个不一样平台可能不一样
如glut提供的方式
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH | GLUT_MULT I SAMPLE)
打开多重采样。若是没有多重采样缓冲区,那么无效
glEnable(GL_MULTISAMPLE)
注意:若是开启多重采样,那么点,直线和多边形的平滑属性(GL_LINE_SMOOTH
)将无效,意味着若是使用多重采样,就不能同时使用点和直线的平滑处理。
那么咱们能够这样处理:
绘制点和直线时,关闭多重采样,绘制多边形时,开启多重采样。
Tips:
状态排序
打开或关闭状态将会修改驱动程序的内部状态,这种改变可能会对渲染性能形成影响
能够将须要相同状态的图元一块儿绘制,这样就能够提升性能(游戏性能优化)
多重采样的缓冲区默认使用片断的RGB值,并没有alpha值,能够经过下面方法改变这个行为
GL_SAMPLE_ALPHA_TO_COVERAGE |
使用alpha值 |
GL_SAMPLE_ALPHA_TO_ON | 将alpha设置1,并使用它 |
GL_SAMPLE_COVERAGE | 使用glSampleCoverage设置的值 |
当启用GL_SAMPLE_COVERAGE时,glSampleCoverage函数容许指定一个特定值,与片断覆盖值进行位与操做
void glSampleCoverage(GLclampf value, GLboolean invert)