1.opengl渲染管线(都是在GPU执行的):
以绘制一个sprite为例,传入一个图片和4个顶点,将顶点数据(主要是三个属性)放入缓冲区
顶点处理(vertex shader),对顶点进行坐标转换(矩阵是通过uniform传入的,每个顶点执行一次)
片元组装,点,线,三角形。上面一个spirte可以装成2个三角形(此阶段还负责视景体裁剪和背面剔除)
光栅化,将上面的顶点插值形成计算机可以显示的二维像数
像数处理(fragment shader),通常是采样纹理颜色和顶点颜色叠加
各种测试(深度测试,剪裁测试,alpha测试等),混合,抖动
进入帧缓冲(帧缓冲包含:颜色缓冲,深度缓冲,模板缓冲和累积缓冲)
2.Vertex shader
顶点属性最大数量不少于8个
输入:
Attributes
Uniforms,可支持的最大数量不少于16个
Samplers,特殊的uniform
输出:
内建变量:gl_Position,2个可选变量:gl_FrontFacing,gl_PointSzie
Varying变量,可支持的最大数量不少于8个。会在光栅化的时候被线性插值
3.fragment shader
输入:
varying变量
uniform
Samplers
输出:内建变量gl_fragcolor
4.glfwSwapBuffers:双缓冲机制下交换缓冲区指针,并强制绘制,通常使用双缓冲。
默认是单缓冲,单缓冲通过glFlush强制绘制。
5.glGenBUffers:创建缓冲区
6.glBindBuffer:与缓冲区绑定,激活缓冲区
7.glBufferData:分配和初始化缓冲区对象
8.glClear(CL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);清除颜色缓冲和深度缓冲区
9.glGenTextures(GLsizei n,GLuint *textures);根据传入参数生成纹理索引。
10.bindTexture2D(,GLuint textureId),改变opengl状态,告诉opengl接下来的操作都是针对他所绑定的纹理
11.glTexParameteri,设置纹理过滤。即将图像从纹理空间映射到帧缓冲图像空间,纹理大小和显示的大小不匹配的时候,纹理重新构造的方法。GL_TEXTURE_MAG_FILTER放大过滤,
GL_TEXTURE_MIN_FILTER缩小过滤。
GL_TEXTURE_WRAP_S s方向上的贴图模式
GL_TEXTURE_WRAP_T t方向上的贴图模式
12.glTexImage2D(….)生成纹理,一般会先在内存把纹理数据做好,然后马上送到显存,有的驱动是在draw的时候才推到显存的。
13.shader其实是显卡的功能,就是利用GPU去处理像数处理。是在一开始就设置好的。在draw之前调用glUseProgram(program),加载shader,(glUseProgram(NULL)可以卸载shader)。
14.VBO:顶点缓冲对象,是在显存里面开辟的一段空间,用来缓冲定点
VAO:顶点数组对象,包含一个或多个VBO,记录绘制信息
15.Vertex shader顶点着色器传参过程
首先与缓冲区绑定glBindBuffer
填入数据glBufferData
指定顶点属性,包括顶点坐标,顶点颜色,纹理坐标
16.颜色相加:指的是光的叠加,物理上是光的强度的相加
颜色相乘应该理解为颜色的非等比缩放
另一种说法:不同光源的结果是相加的,而光源作用在材质上就是相乘
17.混合:glDisable(GL_BLEND) glEnable(GL_BLEND)开启或者关闭混合
glBlendFunc()指定混合函数
18.UV动画。UV坐标指的是纹理贴图到片元顶点上面的坐标(就是纹理坐标)。UV动画指的是改变纹理坐标得到的动画。一般可用来做水波纹。(网上的例子是在fragshader里面对坐标进行变化)
19.GluReshapeFunc是窗口改变的时候调用的函数。GluDisplayFunc是显示的时候调用的
20.Rasterize(光栅化):
这个词儿Adobe官方翻译成栅格化或者像素化。没错,就是把矢量图形转化成像素点儿的过程。我们屏幕上显示的画面都是由像素组成,而三维物体都是点线面构成的。要让点线面,变成能在屏幕上显示的像素,就需要Rasterize这个过程。就是从矢量的点线面的描述,变成像素的描述。
21.三次贝塞尔曲线是由4个点控制的,二次贝塞尔曲线是由3个点控制的
22.GL_SCISSOR_TEST:剪裁测试。用于限定绘制区域。我们可以指定一个矩形的绘制窗口,当开启剪裁的时候只有这个矩形区域的才可以被绘制。
glEnable(GL_SCISSOR_TEST);用于开启剪裁测试
glDisable(GL_SCISSOR_TEST);用于禁用剪裁测试
glScissor (GLint x, GLint y, GLsizei width, GLsizei height);用来指定绘制区域
23.背面剔除:一个物体假如是一个立方体,它始终有些面背对着你无法显示(始终有一面对着你),所以你无需绘制那些面,因此称作背面剔除。这是一种避免渲染背对观察者多边形的优化手段。opengl语句是:
glEnable(GL_CULL_FACE)启用剔除功能;
再调用glCullFace(GLenum mode)。mode :GL_FRONT,GL_BACK,GL_FRONT_AND_BACK。
24.深度测试:深度指的是物体距离摄像机的距离。很显然如果离摄像机远的物体先绘制,那么他将遮挡离摄像机近的物体。为了解决这个问题,opengl将像数的深度信息存放到深度缓冲区。如果待绘制的像数深度<老的像数的深度值,那么新的像数会取代老的像数。反之,新的像数和他的深度值将被丢弃。这样,绘制像数的顺序就不那么重要了。在绘制半透明物体的时候,要将深度缓冲区设置为只读,因为,半透明物体绘制要启用混合,这时不能使用深度模式。
25.mipmap用于解决纹理映射时,在不同分辨率下的适应问题。比如同一张纹理显示在10*10或者20*20...的情况下不至于失真。它实现的原理是存储多种纹理尺寸,在映射的时候选择一张最合适的进行映射。这样可解决图像的闪烁,并且解决大纹理显示的效率问题。但由于存储了多份纹理,会造成内存使用变大的问题。
26.Alpha测试
Alpha的值不仅可以用于混合操作,还有一个用途,这就是Alpha测试。当每个像素即将绘制时,如果启动了Alpha测试,OpenGL会检查像素的Alpha值,只有Alpha值满足条件的像素才会进行下面的流程。
27.在进行顶点处理的时候会进行顶点变换。需要将顶点*MVP矩阵。在unity里面是UNITY_MATRIX_MVP,在cocos2d里面是CC_MVPMatrix。在cocos2d里面在draw开始的时候就要先将MVP计算好,并将其传入渲染管道里面的uniform变量。
那么什么是MVP矩阵呢。
World Matrix - Transforms 3D data from Model Space into World Space. You need to set this before rendering every entity in your world.
View Matrix - Transforms from World Space into View Space. You need to set this each time your camera changes position
Projection Matrix - Transforms from View Space into Screen Space. You normally set this just once during initialization
28.贴图、纹理、材质的关系
材质 Material包含贴图 Map,贴图包含纹理 Texture。
纹理是最基本的数据输入单位,游戏领域基本上都用的是位图。此外还有程序化生成的纹理 Procedural Texture。
贴图的英语 Map 其实包含了另一层含义就是“映射”。其功能就是把纹理通过 UV 坐标映射到3D 物体表面。贴图包含了除了纹理以外其他很多信息,比方说 UV 坐标、贴图输入输出控制等等。
材质是一个数据集,主要功能就是给渲染器提供数据和光照算法。贴图就是其中数据的一部分,根据用途不同,贴图也会被分成不同的类型,比方说 Diffuse Map,Specular Map,Normal Map 和 Gloss Map 等等。另外一个重要部分就是光照模型 Shader ,用以实现不同的渲染效果。
链接:http://www.zhihu.com/question/25745472/answer/31484110
29.glGenVertexArrays(NumVaos,VAOs);向opengl申请分配NumVaos个vao到VAOs(vao的数组)。
对于所有缓存对象:使用的方式都是:
glGenBuffers(GLsizei n,GLuint* buffers):产生缓存区的数组,注意数组里面的对象并未真正创建
glBindBuffer(GLenum target,GLunit buffer):将某个缓存区域激活,设置为当前使用的。如果缓存区域未创建,那么先创建它。当第二个参数设置为0 的时候,解绑缓存区。
glBufferData(GLenum target,GLsizeiptr size,const GLvoid* data,GLenum usage):向缓存区域传递数据。如果数据太大,缓存区域不够时,缓存大小将被重设,反之缓存将被收缩。内存分配方案管理基于usage参数。
30.我们通常使用glBufferData将顶点坐标,顶点颜色,纹理坐标放到一个缓存区域。 但是如果要将这三种数据放到不同的缓存区,可以使用glBufferSubData来实现。对buffer data的操作还包括了:glCopyBufferSubData(缓存之间copy),glGetBufferSubData(将缓存的数据复制到应用程序的内存区域)。当然我们还可以通过glMapBuffer来直接访问缓存区域,避免内存的拷贝(其实不一定避免内存拷贝,当你要求映射的缓存区域内存处于无法访问的时候,opengl会自动将数据拷贝到你可以访问的内存,当访问结束的时候再将数据拷贝过去),当然可以通过glUnmapBuffer来解除映射。
31. glDrawArrays和glDrawElements的区别。
glDrawArrays(GL_TRIANGLES, 0, NumVertices):直接将缓存对象中的顶点属性按照自身排列顺序直接取出并使用。
const GLubyte indices[] = {0, 4, 2};
glDrawElements(GL_TRIANGLES, NumVertices, GL_UNSIGNED_BYTE, indices):根据indices指定的顶点顺序来使用。
glDrawElements能够通过较少的函数调用绘制多个几何图元,而不是通过OPENGL函数调用来传递每一个顶点。