1、渲染中的双缓冲:
使用但缓冲的时候,在渲染每一帧的绘图时,会对画板进行擦除然后在慢慢填充绘制,如果绘制时间过长的时候,就会出现闪烁的现象。为解决这个问题,所以引入双缓冲
双缓冲相当于,在显示的画板中重新创建另外一个画板,绘制的过程在另外的画板进行,绘制完成之后,将显示的画板的内容直接替换成另外一个画板的内容。这样呈现的过程中就不会出现闪烁的问题,即使是绘制的过程比较慢,最多就是出现顿的现象
在例子中渲染的RenderScene()函数中,每次渲染结束之后都会调用glutSwapBuffers()进行缓冲区的切换渲染
void RenderScene(){ glClearColor(0.0f, 0.0f, 1.0f, 0.0f); glClear(GL_COLOR_BUFFER_BIT); glClearColor(1.0f,0.0f,0.0f,0.0f); glScissor(100,100,600,400); glEnable(GL_SCISSOR_TEST); glClear(GL_COLOR_BUFFER_BIT); glClearColor(0.0f,1.0f,0.0f,0.0f); glScissor(200,200,400,200); glClear(GL_COLOR_BUFFER_BIT); glDisable(GL_SCISSOR_TEST); glutSwapBuffers(); }
2、绘制过程:
图元最终的呈现其实是通过一个管线的过程,呈现一个图元,我们必定需要顶点数据,而且需要最终填充成像素的着色器。通过这两个着色器渲染成最终像素的过程就是图形的管线。
OpenGL2.0之后使用可编程的管线,也就是渲染图元的时候,我们是需要通过shader程序进行的,一般会分成两个过程,一个是顶点着色器的处理,一个是片段着色器的处理。
顶点着色器处理客户机输入的数据,应用变换,数学计算(光照,颜色,位移),逐顶点处理
片段着色器会输出我们最终在屏幕看到的像素颜色值,逐像素处理。
Shader的数据传递:顶点属性数据,uniform数据,纹理数据
顶点数据:顶点位置,顶点颜色值,纹理坐标,光照法线。这些数据一般都是传入顶点着色器进行处理的。
uniform数据:和属性数据不同的是,片段着色器中也可以有Uniform变量。Uniform变量在改变的时候是逐批次的不是逐顶点的。常用于设置变换矩阵
纹理数据:纹理数据提供给片段着色器进行采样,根据纹理坐标应用于图元的像素中
输出变量:可以将顶点着色器的值传递到片段着色器中
3、坐标系和投影
GLFrustum:使用该类作为投影矩阵的容器
正投影:通过调用GlFrustum::SetOrthographic(xMin,xMax,yMin,yMax,zMin,zMax)的函数来对最终绘制的图像进行投影。该投影一般用于2D绘图。
透视投影:通过调用GLFrustum::SetPerspective(fFov,fAspect,fNear,fFar)的函数来获取一个投影矩阵。
fFov:在垂直方向上的视觉角度
fAspect:窗口宽高的纵横比
fNear:近裁剪面的距离
fFar:远裁剪面的距离
4、一套现成封装好的Shader管理器
我们使用GLTools中的GLShaderManager进行进行渲染。自带了很多预定义的Shader。
在使用之前必须先 初始化:shaderManager.InitializeStockShaders()
顶点数据和Shader的绑定:有16种类型,编号为0-15.预定义类型一般为GLT_ATTRIBUTE_VERTEX...(GLT_ATTRIBUTE_XXX)
Uniform值的设置:GLShaderManager::UseStockShader(GLenum shader,....)
后面带的参数就是shader需要的uniform值
5、基于GLTools的图元绘制
使用GLTools中的GLBatch类可以进行图元的绘制,绘制前需要指定绘制的图元类型,顶点数和顶点数据
GLBatch::Begin(GLenum primitive,GLuint nVerts,GLuint nTextureUnits = 0)
可选的Private包括GL_POINTS,GL_LINES,GL_LINE_STRIP,GL_LINE_LOOP,GL_TRIANGLES,GL_TRIANGLE_STRIP,GL_TRIANGLE_FAN.
需要特别解释的是GL_LINE_STRIP和GL_LINE_LOOP,一个是线带,一个是线环,一个没有闭合一个有闭合
GL_TRIANGLE_STRIP和GL_TRIANGLE_FAN,一个是三角带,一个是三角扇,后者可以连成扇形甚至是圆形
通过CopyXXXData复制顶点各种属性数据之后,调用指定的着色器,调用Batch.Draw便可以绘制图元
6、背面剔除和深度缓冲
1、不开启背面剔除和深度测试的情况下,出现三角形重叠的时候,很难分出哪些三角形应该在前面哪些在后面,绘制顺序一团糟
2、一种优化的测试方法:先渲染远的三角形再渲染近的三角形。
缺点:需要对所有三角形进行排序,消耗大,而且重叠的像素需要进行两次写操作,在存储中进行写操作会是速度变慢
3、开启背面剔除:glEnable(GL_CULL_FACE)默认剔除背面,可以通过glCullFace(mode)来修改剔除正面还是背面。
优点:在渲染的图元装配阶段就抛弃一些三角形,提高性能
缺点:当发生自身重叠的情况,正常的渲染顺序还是会被打乱
注:当我们旋转的时候,原来的背面会变成正面,正面会变成正面,这应该是通过跟摄像机的法线判断来确定三角形的正反面的,也就是说不是一定顺时针环绕的背面永远看不到。(http://bbs.csdn.net/topics/380040702)
4、开启深度测试:glEnable(GL_DEPTH_TEST)开启深度测试,当然在开启之前,应该初始化一个深度缓冲区glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGBA|GLUT_DEPTH);
优点:深度测试将消除那些应该被以存在的像素覆盖的像素,解决背面剔除的问题
缺点:需要更多的内存开销
7、描边的效果:
开启深度测试之后,如果要描边或做贴花的效果,可能会出现Z轴冲突的现象,通过多边形偏移可以解决这个问题
glPolygonOffset(-1.0f,-1.0f)
glEnable(GL_POLYGON_OFFSET_LINE)
8、裁剪:确定最终渲染到窗口的视口大小
开启:glEnable(GL_SCISSOR_TEST)
设置:glScissor(x,y,width,height)
9、混合:Alpha显示以及抗齿锯支持的条件,只有开启混合才会有半透明和抗齿锯的效果
开启:glEnable(GL_BLEND)
常用的颜色混合:glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA):源颜色与自己身的alpha值相乘,加上目标颜色乘以1-源颜色的Alplha值。源颜色的Alpha值越高,添加的源颜色成分就越多,目标颜色保留的成分就越少
10、抗齿锯:
开启:glEnable(GL_BLEND)
glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA) 先开启颜色混合
glEnable(GL_POINT_SMOOTH)
点光滑
glEnable(GL_LINE_SMOOTH)
线光滑
glEnable(GL_POLYGON_SMOOTH)
多边形光滑,少用,一般使用多重采样替代
设置:glHint(GL_POINT_SMOOTH_HINT,GL_NICEST)
指定抗齿锯的算法
11、多重采样:需要多开启一个缓冲区,每次对像素更新的时候,都需要进行采样生成新的值
开启:glutInitDisplayMode(XXX|GLUT_MULTISAMPLE)
glEnable(GLUT_MULTISAMPLE)
设置:默认情况下使用片段的RGB值不包括A值
可以通过glSampleCoverage(value,invert)来修改
GL_SAMPLE_ALPHA_TO_COVERAGE - 使用Alpha值
..