超级宝典&编程指南(红蓝宝书)-读书笔记

学习中and持续更新中……

超级宝典=

客户端:指我们需要执行,存储在CPU中的指令(OpenGLAPI,C和C++代码),客户端会把渲染命令发送给服务器执行。
服务器:接收客户端的指令后调用GPU芯片执行相关操作。
管线停滞:客户端与服务器之间是异步的。当服务器等待客户端的指令,或者客户端等待服务器处理好的结果来执行下一条命令时,就叫管线停滞了。


渲染:将数学和图形数据转换成3D空间图像的操作。计算机创建三维图像时所经历的过程。


光栅化:把顶点信息,以及由顶点组成的图像转换成一个个由像素组成的栅格。
在这里插入图片描述


顶点(Vertex):一个三维立方体,可以由6个二维正方体组成,而这个立方体的每个角就称之为顶点。定时其实就是空间中的特定坐标,把空间中的这些特定坐标(顶点)连起来,就形成我们想要看到的物品。


GLSL:openGL的着色器语言。


openGL变量类型和最小位宽:

在这里插入图片描述


openGL有很多状态模型,我们可以通过简单的设置状态变量来控制其开关。如:
开启深度测试:glEnable(GL_DEPTH_TEST);
关闭深度测试:glDisable(GL_DEPTH_TEST);


:最简单的图元,点的默认大小是1个像素,但我们可以通过调用glPointSize改变默认点的大小。点的大小不会受到透视法影响(距离远点不会变小,距离近点不会变大)。而且点这个图元,他总是正方形像素,无论你把他变多大,所以如果想要让他变成圆点,就需要开启抗锯齿了。


OpenGL几何图元
GL_POINTS: 每个顶点在屏幕上都是一个单独的点。
GL_LINES: 每一对顶点定义了一个线段。
GL_LINE_STRIP: 一个从第一个顶点依次经过每个后续顶点而绘制的线条
GL_LINE_LOOP: 在GL_LINE_STRIP的基础上,把最后一个顶点和第一个顶点连接起来。
GL_TRIANGLES: 每3个顶点定义一个新的三角形。
GL_TRIANGLE_STRIP: 共用一个条带(strip)上的顶点的一组三角形。(v0,v1,v2),(v2,v1,v3),(v3,v2,v4)
GL_TRIANGLE_FAN: 以一个远点为中心呈扇形排列,共用相邻顶点的一组三角形。(以一个点为中心和其他的两个点组成三角形)
GL_QUADS: 每4个顶点定义一个新的四边形。
GL_QUAD_STRIP: 共用一条带上的顶点的一组四边形。(v0,v1,v3,v2)(v2,v3,v5,v4)(v4,v5,v7,v6)
GL_POLYGON: 用一系列的顶点描述简单的凸多边形。(点的个数必须大于3)


默认情况下,逆时针环绕的多边形视为正面,顺时针则为背面。
glFrontFace(GL_CW)可以把顺时针环绕改成正面。
在这里插入图片描述
上图的环绕方式并不是根据下标数字顺序来的,(v0,v1,v2),(v2,v1,v3),(v2,v3,v4)其顺序的目的是为了保证环绕方式为逆时针。
使用GL_TRIANGLE_STRIP,可以大量减少顶点数量,从而减少数据储存空间以及提高运算性能,因为指定了第一个三角形后,之后每增加一个三角形只需要增加一个顶点就可以了。


如果要绘制一个环形的甜甜圈,先绘制的三角形可能会被后绘制的三角形覆盖,当旋转甜甜圈时就会看出问题来了。
可以用“油画法”解决问题,就是对三角形进行排序,再选择较远的三角形进行优先宣言,但这种方法效率十分低下,例如重叠的地方需要进行2次写操作,对那么多三角形排序开销也很高。
背面剔除:检查所有正面朝向观察者的面,渲染他们,而丢弃掉所有背向观察者的面,这样可以大量节省片元着色器的运行。
glEnable(GL_CULL_FACE) 开启背面剔除。
可以通过glCullFace(mode)来设置剔除模式,mode参数具体如下:
GL_BACK:只剔除背向面。
GL_FRONT:只剔除正想面。
GL_FRONT_AND_BACK:剔除正想面和背向面。
深度测试:也是一种高效的消除隐藏表面的技术,在绘制像素时分配一个Z值(离观察者越近,Z值越大)给他,当需要在同一个位置绘制像素时,比较这个Z值,Z值大的放上面,反之则放到原来绘制的像素的下面。
通过glutInitDisplayMode(GLUT_DOUBL | GLUT_RGBA | GLUT_DEPTH) 申请一个颜色缓冲区和深度缓冲区。
之后可以通过glEnable(GL_DEPTH_TEST)开启深度测试。

glPolygonMode(GLenum face, GLenum mode)可以把目标(甜甜圈)渲染成实体GL_FILL(默认),轮廓-用线连起来(GL_LINE),或者只有点(GL_POINT)


glEnable(GL_SCISSOR_TEST)
void glScissor(GLint x, GLint y, GLsizei width, GLsizei height)
对窗口的部分区域进行裁剪,裁剪后,只会在裁剪的区域进行渲染,渲染区域变小了,性能自然提高了。


glEnable(GL_BLEND)
混合: 开启深度测试后,上层的颜色会替换掉下层的颜色,而如果开了混合后,会保留所有层级的颜色,让颜色叠加组合。
openGL混合因子:
在这里插入图片描述
根据上表,使用glBlendFunc设置混合因子,以达到不同的混合效果。

在这里插入图片描述
根据上表,使用glBlendEquation修改混合方程式,也能达到不同的混合效果。

使用glBlendFuncSeparate(GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha)可以高度自由的根据你实际情况设置混合。


锯齿:因为最小的像素点,其实是一个矩形来点(而非圆形点),所以一般在图片的边缘就会经常会看到锯齿了。所以我们通常把最边缘的地方和背景的颜色进行混合以达到像素自然过渡的”抗锯齿“效果。实现此效果也非常简单。
glEnable(GL_BLEND) // 开启抗锯齿
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) // 混合因子
glBlendEquation(GL_FUNC_ADD) // 设置混合方程式(这步可有可无,因为默认方程式就是ADD的)
剩下的就是设置点、线、多边形进行抗锯齿处理。
glEnable(GL_POINT_SMOOTH)
glEnable(GL_LINE_SMOOTH)
glEnable(GL_POLYGON_SMOOTH)


向量:在空间坐标上的一个点,可以视为一个顶点,同样也可以视作一个向量。向量简单的理解就是方向与数量,方向即从坐标原点到这个点的一个方向,数量即坐标原点到这个点的长度。
标准化:长度为1的向量称为单位向量,把一个向量的长度缩放到1就是对其进行标准化。
点乘:两个(三分量)单位向量进行点乘会得到一个标量,它表示两个向量之间的夹角(余弦值)。两个计算的向量一定要是单位向量,返回结果在-1.0~1.0之间。
叉乘:两个向量之间进行叉乘,会得到一个垂直于两个向量所在平面的新向量。两向量进行叉乘的顺序很重要,先后顺序不同,得到新的向量的指向也不同,顺序调转会让新的向量指向相反方向。


由于没保存,到4.8章的笔记丢失=。=!!!


在我们看来,镜头移动时会看到不同的景色,光照效果也不一样,其实可以反过来思考,动的不是摄像头,而是摄像头对着的那些物体。 点光源其实也一样,看着点光源应该是固定不动的,其实如果摄像头不动而是点光源在移动,看着就像镜头在移动一样。


载入纹理方法:
glTexImage1D (GLenum target, GLint level, GLint internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const void *pixels);
glTexImage2D (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void *pixels);
glTexImage2D (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void *pixels);

参数说明:
GLenum target:GL_TEXTURE_1D,GL_TEXTURE_2D,GL_TEXTURE_3D。也可以指定Proxy Texture。
GLint level:加载的mip贴图层次。如果是旧式普通贴图,可以把值设置为0.
GLint internalformat:每个纹理单元中存储的颜色成分。
GLsizei width, GLsizei height, GLsizei depth:被加载纹理的长、宽和深度。这个值一般设置为2的整数次幂。 虽然新版openGL支持非2的整数次幂的处理,就怕部分硬件底层不支持。
GLint border:纹理贴图的边界宽度。
GLenum format, GLenum type, const void *pixels:用于把图像数据放入颜色缓冲区的glDrawPixels函数的对应参数相同。


从颜色缓冲区中复制纹理:
glCopyTexImage1D (GLenum target, GLint level, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLint border);
glCopyTexImage2D (GLenum target, GLint level, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border);
参数X,Y指定从颜色缓冲区开始读取纹理的位置,因为是从二维颜色缓冲区里读取纹理,所以没有glCopyTexImage3D这方法。


更新纹理:
glCopyTexSubImage1D (GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width);
glCopyTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height);
glCopyTexSubImage3D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset GLint x, GLint y, GLsizei width, GLsizei height);
重新加载一个新的纹理会远比替换一个已经没有的纹理消耗更大。 所以我们可以把一些已经加载了且已经没用的纹理替换成我们需要的新的纹理。


分配纹理对象:
void glGenTextures(GLsizei n, GLuint *textures)
GLsizei n:分配纹理对象的数量
GLuint *textures:指向纹理对象数组头部的指针。


绑定纹理对象状态:
void glBindTexture(GLenum target, GLuint texture)
GLenum target:GL_TEXTURE_1D,GL_TEXTURE_2D,GL_TEXTURE_3D这三种参数的其中一种。
GLuint texture:要绑定的纹理对象。


删除纹理对象:
void glDeleteTextures(GLsizei n, GLuint *textures)
GLsizei n:要删除的纹理的数量。
GLuint *textures:要删除的纹理数组。
删除纹理会带来较大的开销,所以同时删除多个纹理可能会导致有点卡。


检查纹理是否存在:
GLboolean glIsTexture(GLuint texture)


采样:通过纹理坐标获取像素颜色信息的过程就是采样。
glTextureParameter接口可以设置纹理参数。
基本过滤:
GL_TEXTURE_MAG_FILTER 放大过滤器
GL_TEXTURE_MIN_FILTER 缩小过滤器
过滤参数:
GL_NEAREST 邻近过滤,运算效率比较高,但需要出现大幅拉伸时,会出现斑驳,效果相对比较差。
GL_LINEAR 线性过滤,运算相对复杂,会对纹理坐标周围进行加权平均,再应用到这个纹理坐标上(线性插值)。所以效果也好点。
GL_NEAREST_MIPMAP_NEAREST:选择最邻近的mip层,并使用最邻近过滤。(mipmaps贴图才生效)
GL_NEAREST_MIPMAP_LINEAR:对两个mip层使用最邻近过滤后的采样结果进行加权平均。(mipmaps贴图才生效)
GL_LINEAR_MIPMAP_NEAREST:选择最邻近的mip层,使用线性插值算法进行过滤。(mipmaps贴图才生效)
GL_LINEAR_MIPMAP_LINEAR:对两个mip层使用线性插值过滤后的采样结果进行加权平均,又称三线性mipmap。(mipmaps贴图才生效)

纹理环绕:
纹理坐标系是一个空间直角坐标系,横轴是S,纵轴是T,垂直于屏幕的是R轴。
GL_TEXTURE_WRAP_S 横轴环绕
GL_TEXTURE_WRAP_T 纵轴环绕
环绕参数:
GL_REPEAT:在纹理坐标值超过1.0的方向进行重复。
GL_CLAMP_TO_EDGE:对边界最后一行进行采样,范围以外的地方直接使用边界最后一行。
GL_CLAMP_TO_BORDER:对超出范围之外的纹理,直接使用边界纹理。
在这里插入图片描述


Mip贴图纹理的生成方式:
先把图片的X和Y分别缩小一半(图片大小就会缩成1/4),然后就生成了一张新贴图,在这基础上继续缩小,直到缩成1*1的基础单元为止。
如果其中一个轴已经缩到1了,就只缩小另外一个轴。这样做会额外消耗接近1/3的内存,但会极大的提高采样效率和采样质量。
正常情况下,我们应该加载所有的mip贴图,但我们可以通过设置GL_TEXTURE_BASE_LEVEL和GL_TEXTURE_MAX_LEVEL来设置使用的基层和最大层。如现在想设置只加载0到4层:
glTexparameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
glTexparameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 4);


纹理压缩:
如果简单的使用压缩软件压缩图片的质量,很多时候只是减少图片的大小(占用磁盘空间的大小),而对加载到硬件中的内存影响不大。而对纹理进行压缩,就可以很有效的减少占用图形硬件的内容。通用的纹理压缩格式如下:
在这里插入图片描述
可以通过glHint来设置压缩方式
glHint(GL_TEXTURE_COMPRESSION_HINT,GL_FASTEST); 选择速度最快的处理方式
glHint(GL_TEXTURE_COMPRESSION_HINT,GL_NICEST); 选择质量最高的处理方式
glHint(GL_TEXTURE_COMPRESSION_HINT,GL_DONT_CARE); 对选项不做考虑

可以使用下面的API对压缩的纹理进行解压:
void glCompressedTexImage1D(GLenum target, GLint level, GLenum internalFormat, GLsizei width, GLint border, GLsizei imageSize, void *data);
void glCompressedTexImage2D(GLenum target, GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, void *data);
void glCompressedTexImage3D(GLenum target, GLint level, GLenum internalFormat, GLint width, GLint height, GLint depth, GLint border, GLint imageSize, void *data);
参数其实与前面的glTexImage基本一致,就是必须制定一种受支持的纹理压缩格式。
还有glCompressedTexSubImage函数,和前面的glTexSubImage功能相当,替换更新压缩过的纹理图像。


GLSL的向量数据类型不是类,可以和一个向量进行加法,也可以用一个标量进行乘法(缩放)等。
GLSL的变量存储限定符:
在这里插入图片描述


创建与加载着色器的流程如下:
1.创建着色器: glCreateShader
2.对着色器对象加载着色器程序: gltLoadShaderFile
3.编译着色器对象: glCompileShader
4. 对顶点着色器检查编译错误: glGetShaderiv
5.创建程序对象函数 glCreateProgram
5. 把程序连接着色器对象 glAttachShader
6. 连接程序 glLinkProgram
7. 检验链接程序是否正确glGetShaderiv


uniform(统一值):设置了这个值后就不能再修改,所以也不需要(不能)标记为in或者out。
获取uniform值:GLint glGetUniformLocation(GLuint shaderID, const GLchar* varName)
如果声明了uniform而不使用他,编译器也会有可能把uniform给丢弃掉。

normalMatrix(法向矩阵)只包含模型视图矩阵的旋转分量,用法向矩阵×法向量就可以获得视觉坐标。


ADS光照模型: 环境光A(Ambient), 漫射光D(Diffuse),镜面光S(Specular)
环境光:不来自任何特定的方向,所有环境光没有方向一说。这种光照射到物体的所有方向的表面都是均匀照亮的。物体最终的颜色值由环境光的值来决定。(个人感觉这种光是附近无数个物体所反射出来的光)
uniform vec3 vAmbientMaterial;
uniform vec3 vAmbientLight;
vec3 vAmbientColor = vAmbientMaterial * vAmbientLight;

漫射光:漫反射材质和光照值相乘,再用表面法线和光照向量的点乘进行缩放。(个人感觉就是光照射在物体上,由于物体表面和粗糙,导致最终光源射到物体上后分散了,没有高光点)
uniform vec3 vDiffuseMaterial;
uniform vec3 vDiffuseLight;
float fDotProduct = max(0.0, dot(vNormal, vLightDir));
vec3 vDiffuseColor = vDiffuseMaterial * vDiffuseLight * fDotProduct;

镜面光:
像聚光灯、太阳等较强的光源射到镜面材质上,光会进行反射,所以在特定的角度可以看到反射光,其他角度可能就只会看到强光源照射到镜面材质上的镜面亮点,而看不到反射光。
这种光计算比前2种更复杂,要先找到表面法线反射的向量和反向的光线向量,把两向量乘积的结果再 取“反光度”次幂,反光度越大,镜面反射的高亮区越小,反光越强。
uniform vec3 vSpecularMaterial;
uniform vec3 vSpecularLight;
float shininess = 128.0;
vec3 vReflection = reflect(-vLightDir, vEyeNormal);
float EyeReflectionAngle = max(0,0 dot(vEyeNormal, vReflection));
fSpec = pow(EyeReflectionAngle, shininess);
vec3 vSpecularColor = vSpecularLight * vSpecularMaterial * fSpec;

所以ADS着色器最终顶点颜色:
vVertexColor = vAmbientColor + vDiffuseColor + vSpecularColor;


着色器的性能优化原则是:把尽可能多的计算过程从片元着色器移到顶点着色器中进行计算。 如果运行的设备性能较好,运算能力较强,放在片元着色器上计算也可以获得较好的显示效果(比较高质量的渲染)。


立方体贴图:把六张图贴到立方体的六面,可以用于立方体内部,例如创建天空盒子。


点精灵(点块纹理):可以用于实现粒子效果。当你要做的东西需要由很多粒子组成时,用点精灵的效果远远比绘制大量四边形(三角形带)的效率要高好多,开销少很多。开启店精灵模式方式如下:
glEnable(GL_PROGRAM_POINT_SIZE)


纹理代理:纹理代理不能创建真正的纹理,只是用来做一些纹理的测试。例如查看一下是否支持4096的纹理高度。
glTexImage2D(GL_PROXY_TEXTURE_2D, 0, GL_RGBA, 2048, 4096, 0, GL_BGRA, GL_UNSIGNED_BYTE, NULL);
void glGetTexLevelParameter(GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &height);


PBO(像素缓冲区):
1.生成新缓存对象:
void glGenBuffers(GLsizei n, GLuint* buffers)
n:创建缓存的数量。
buffers:存储ID的GLuint变量数组地址。

2.绑定缓存对象:
void glBindBuffer(GLenum target, GLuint buffer)
target:保存该缓存对象的类型。

3.初始化缓存对象:
void glBufferData(GLenum target,GLsizeiptr size, const GLvoid* data, GLenum usage);
target:缓存对象的类型。
size:需要拷贝对象的字节大小。
data:数据的指针。(如果值为NULL则只预留给定数据大小的内存空间)
usage:对象的使用方式。(如:static表示不会被改变。dynamic表示会频繁改变等)

4.把数据写入到缓存对象:
void glReadPixels (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void *pixels);
前4个参数:需要获取像素的起点和长宽(就是一个矩形啦)
format:格式,例如GL_ALPHA,GL_RGB和GL_RGBA。
type:像素数据的数据类型,如:GL_UNSIGNED_BYTE,GL_UNSIGNED_SHORT_5_6_5,GL_UNSIGNED_SHORT_4_4_4_4或GL_UNSIGNED_SHORT_5_5_5_1。
pixels:如果有传此参数,像素数据会被保存到指针所在的地址(所以一定要保证传入的指针有足够的内存空间)。

5.替换缓冲区中的数据:
void glBufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid* data);
从offset位置开始,替换掉缓冲区的数据。

6.删除不需要使用的缓冲区:
void glDeleteBuffers(GLsizei n, const GLenum* bufs);
和创建缓冲区参数一样。

例子如下(伪代码):

GLuint pixBuffObjs[1];
void *pixelData;
GLuint pixelDataSize;

// 计算缓冲区空间需要的大小,且根据其大小动态申请内存
pixelDataSize = screenWidth*screenHeight*3*sizeof(unsigned int);
pixelData = (void*)malloc(pixelDataSize);

//-----------------------------初始化缓冲区-----------------------------
// 创建一个缓冲区
glGenBuffers(1, pixBuffObjs);
// 绑定缓冲区
glBindBuffer(GL_PIXEL_PACK_BUFFER, pixBuffObjs[0]);
// 初始化缓冲区
glBufferData(GL_PIXEL_PACK_BUFFER, pixelDataSize, pixelData, GL_DYNAMIC_COPY);
// 解除绑定
glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);

//-----------------------------保存数据到缓冲区-----------------------------
// 绑定缓冲区
glBindBuffer(GL_PIXEL_PACK_BUFFER, pixBuffObjs[0]);
// 把屏幕上的内容保存到像素缓冲区
glReadPixels(0, 0, screenWidth, screenHeight, GL_RGB, GL_UNSIGNED_BYTE, NULL);
// 解除绑定
glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);

//-----------------------------使用缓冲区数据-----------------------------
// 绑定缓冲区(注意以下内容的target是GL_PIXEL_UNPACK_BUFFER)
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pixBuffObjs[0]);
// 获取默认纹理单元
glActiveTexture(GL_TEXTURE0)
// 这里比较特别的是,此函数会判断GL_PIXEL_UNPACK_BUFFER有没绑定缓冲区,如果有,就冲缓冲区里读取数据。
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, screenWidth, screenHeight, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
// 解除绑定
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);

//-----------------------------清除缓冲区-----------------------------
glDeleteBuffers(1, pixBuffObjs);


FBO(帧缓冲区对象)&RBO(渲染缓冲区对象)
单独创建一个FBO,其实本身作用并不大,想要让他更有效地被利用,我们可以往FBO中加入多个RBO,例如深度渲染缓存、颜色渲染缓存等。

例子如下(伪代码):

GLuint fboName;
GLuint depthBufferName;
GLuint renderBufferNames[2];

// 创建1个帧缓冲区
glGenFramebuffers(1, &fboName);

// 创建深度渲染缓存
glGenRenderbuffers(1, &depthBufferName);
// 绑定缓存
glBindRenderbuffer(GL_RENDERBUFFER, depthBufferName);
// 为缓存分配空间
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT32, screenWidth, screenHeight);

// 创建两个颜色渲染缓存
glGenRenderbuffers(2, renderBufferNames);
glBindRenderbuffer(GL_RENDERBUFFER, GL_RGBA8, screenWidth, screenHeight);
glRenderbufferStorage(GL_RENDERBUFFER, renderBufferNames[0]);
glBindRenderbuffer(GL_RENDERBUFFER, GL_RGBA8, screenWidth, screenHeight);
glRenderbufferStorage(GL_RENDERBUFFER, renderBufferNames[1]);

// 把上面创建的三个RBO(渲染缓冲)都绑定到FBO中
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fboName);
glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENNDERBUFFER, depthBufferName);
glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, renderBufferNames[0]);
glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, renderBufferNames[1]);

//---------------------------------------使用完缓冲区后
// 清除RBOs
glDeleteRenderbuffers(2, renderBufferNames);
glDeleteRenderbuffers(1, &depthBufferName);

// 清除FBO
glDeleteFramebuffers(1, &fboName);

//-----------------------------逐片段操作-----------------------------
经过顶点着色,片段着色后,最后这些片段会经过逐片段操作,最终才到达缓冲区或者窗口中。
1.裁剪测试:
我们可以设置一个矩形区域,在区域内的片段会留在管道中。而在区域之外的片段则会被抛弃。简单来说,就是把几何图形切割到我们希望的大小。
2.多重采样操作:
通过在一个像素上进行多次采样(同一个像素上会得出多个颜色,深度等数值)并最终汇总,可以使绘制的图像边缘更加平滑,这种绘制方式制作出来的图片质量更高,更真实,但相对的也会更消耗性能。
3.模板测试:
我们可以通过设置模板函数来显示一些我们想要显示的像素,抛弃一些我们不想显示的像素。 模板测试也可以做到轮廓、镜面、阴影等效果。
4.深度缓冲测试:
其实深度测试就是对在一个像素点上同时存在的多个像素,根据Z值的前后关系进行排序。如果片段通过了深度测试,openGL会在深度缓冲中存储该片段的Z值,否则,就会丢弃该片段。
5.混合:
可以使用不同的混合方程式,对输入的源颜色和已经存在于颜色缓冲区的颜色进行混合。
6.逻辑操作:
功能上有点类似混合…… 开启了逻辑操作,系统会忽略混合效果。 逻辑操作会把源颜色和目标颜色根据你选择的操作方式方式,进行位操作。
7.抖动:
已经到达管道处理的重点了。把管道数据输出到渲染窗口时,可能渲染窗口只支持每通道8位,这时就需要对最终输出的颜色进行转换,而转换的过程中,颜色可能就会介乎于两个数值的中间(如82.5,在82~83之间),这时无论选82还是83处理结果都会感觉颜色是一层一层的在变化,而开了抖动后硬件会对过渡的颜色进行混合,让颜色在过渡中显得更加自然,而不是分层地从一个颜色直接跳到另外一个颜色。 抖动是默认开启的。
8.遮罩输出:
一般片段着色器可写入3种数据类型(颜色、深度和模板)。我们可以根据3种类型来做遮罩。颜色:可以设置RGB某一颜色通道进行屏蔽。深度:可以痛殴过glDepthMask()函数设置开启或者关闭深度遮罩。 模板:可以指定模板缓冲区的一段位置不进行写入。

编程指南=
着色器语言GLSL:
1.和C++很像,具有很多C++和java的特性。
2.以main函数作为入口函数。
3.强类型语言,甚至比C++更注重安全,因为它支持的隐式转换更少。
4.GLSL的向量与矩阵的类型

在这里插入图片描述
5.opengl的矩阵是以列主序的原则! 如:3*4的矩阵,代表的是3列4行。
6.向量分量的访问符:
在这里插入图片描述


uniform:
可以在着色器里声明,并设置一个默认值(之后在着色器中不可修改)。可以在不同的着色器阶段使用这个值,他是统一不变的。而且在着色器之外,你的主程序中,可以通过OpenGl的API去获取,并且设置这些值。如:
GLint glGetUniformLocation(GLuint program,const GLchar* name);
通过上述API获取变量的位置后,就可以通过变量的位置设置uniform的值了,如:
GLint iLocation = glGetUniformLocation(myProgram, “vColorValue”);
GLfloat fValue = 45.2f;
glUniform1fv(iLocation, 1, &fValue);


buffer块:
功能比uniform强大,buffer的内容也可以在所有着色器中访问,而且它还能在着色器中被修改,而且它是在渲染前才决定大小的(uniform是在编译链接时就可以确定大小了)。但如果不需要进行写操作,其实使用uniform也可以了(相比较uniform更容易获取资源空间,更大概率会发生buffer块申请不到足够的空间)。

渲染流程:【顶点数据】 -> 【顶点着色】 -> 【图元装配】 -> 【几何着色】 -> 【细分着色】 -> 【光栅化】 -> 【片段着色】 -> 【测试与混合(逐片段操作)】

常用词汇:
法向量:normal
法向矩阵:normalMatrix
GLSL:OpenGL Shading Language(openGL的着色语言,openGL本身是跨平台的编程接口,与平台没关,IOS相关的设备可以使用openGl)
HLSL:High Level Shader Language(Direct3D的着色语言,DX是微软的编程接口,所以在WINDOWS上使用DX效果会更好)
CG:C for Graphic(NVIDIA公司出品,在openGL和DX之上封装的高级语言,但更推荐使用GLSL或HLSL)
模型视图矩阵:mvMatrix(ModelViewMatrix)
模型视图投影矩阵:mvpMatrix(ModelViewProjectionMatrix)
像素缓存对象:PBO(pixel_buffer_object)
顶点缓存对象:VBO(vertex_buffer_object)
顶点数组对象:VAO(vertex_array_object)
纹理缓冲区对象:texBO 或 TBO(texture_buffer_object)
帧缓冲区对象:FBO(frame_buffer_object)
渲染缓冲对象:RBO(render_buffer_object)
顶点着色器:vertex shading stage
细分着色器:tessellation shading stage
几何着色器:geometry shading stage
片段着色器:fragment shading stage
pass:一次pass其实就是完成一次完整的绘制的意思,走完一遍完成的渲染管道流程(VS->TS->GS->光栅化->PS)。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值