OpenGL(3)——渲染架构

566 阅读8分钟

1. 架构图

渲染架构.jpg 架够分为两部分:clientserverclient指的是OC代码OpenGL apiserver指的是OpenGL的底层代码。 client端的工作由CPU完成,server端的代码由GPU完成。
client端到server端,有三种通道AttributeUniformsTexture
我们由上图可以看到上面三种通道都通往顶点着色器。但是Attribute并没有通到片元着色器,也就是说一些数据只能通过顶点着色器间接传递到片元着色器当中去。

1.1.Attributes

Attributes 一般传递顶点数据、光照坐标、投影矩阵、模型矩阵、纹理坐标(图片映射坐标)等数据。顶点着色器并不能处理像素点,所以只需要传递纹理坐标就可以了,顶点着色器在将数据桥接给片元着色器。

1.2.Uniform

Uniform是一个统一的批次,传递一些不经常改变的数据,比如时间、变换矩阵、颜色值等。Uniform可以将数据传递到顶点着色器也可以传递到片元着色器。

1.3.Texture Data

Texture Data传递一些纹理数据,可以传递到顶点着色器和片元着色器,但是传递到顶点着色器并有没有什么意义。

2. 投影

2.1正投影

GLFrumstum::SetOrthographic(
GLfloat xMin, GLfloat xMax, GLFloat yMin,
GLFloat yMax, GLFloat zMin, GLFloat zMax);

GLFrumstum通过SetOrthographic方法构建一个立方体盒子,物体放在里面显示。如果物体的大小超过了盒子的大小,我们就看不到了。物体的大小与盒子的大小无关,盒子的位置也和投影坐标没有关系。
当我们显示一个2D图像的时候可以正投影。

2.2透视投影

CLFrustum::SetPerspective(
float fFov, float fAspect, float fNear, float fFar);
参数:
fFov:垂直方向上的视场⻆度
fAspect:窗⼝的宽度与⾼度的纵横⽐
fNear:近裁剪面距离
fFar:远裁剪面距离

GLFrustum类通过setPerspective方法为我们构建⼀个平截头体。
这个平截体首先需要一个角度,也就是相当于人的视角,具体数值可以通过fFov参数来设置。一个参数是纵横比fAspect,也就是窗口的宽高比。也有两个参数分别是fNearfFar,分别代表到远近两个截面的距离。
当我们显示一个3D图像的时候可以透视投影,因为它会有一个远小近大的效果,3D效果更好。

3. 着色器

GLShaderManager的初始化:

GLShaderManager shaderManager;
shaderManager.InitializeStockShaders();

下面介绍8种固定管线着色器。

3.1单元着色器

GLShaderManager::UserStockShader
(GLT_SHADER_IDENTITY, GLfloat vColor[4]);

参数1: 存储着色器种类-单元着⾊器  
参数2: 颜⾊

使用场景: 绘制默认OpenGL 坐标系(-1,1)下图形. 图形所有⽚段都会以一种颜色填充。不能应用其他变化比如:旋转、缩放、平移等。

3.2平面着色器

GLShaderManager::UserStockShader(
GLT_SHADER_FLAT, GLfloat mvp[16], GLfloat vColor[4]);

参数1: 存储着色器种类-平⾯着⾊器
参数2: 允许变化的4*4矩阵
参数3: 颜⾊

使⽤场景: 在绘制图形时, 可以应⽤变换(模型/投影变化)。

3.3上⾊着⾊器

GLShaderManager::UserStockShader(
GLT_SHADER_SHADED, GLfloat mvp[16]);

参数1: 存储着⾊器种类-上⾊着⾊器
参数2: 允许变化的4*4矩阵

使⽤场景: 在绘制图形时, 可以应⽤变换(模型/投影变化) 颜⾊将会平滑地插入到顶点之间

3.4 默认光源着色器

GLShaderManager::UserStockShader(
GLT_SHADER_LIGHT, CLFloat mvMatrix[16], 
CGFloat pMatrix[16], GLFloat vColor[4]);

参数1: 存储着⾊器种类-默认光源着⾊器
参数2: 模型4*4矩阵
参数3: 投影4*4矩阵
参数4: 颜⾊值

使用场景:在绘制图形时,可以应用变换(模型/变化),这种着色器会使绘制的图形产生阴影和光照的效果。默认有一个太阳光

3.5 点光源着色器

GLShaderManager::UserStockShader(
GLT_SHADER_POINT_LIGHT_DIEF, GLfloat mvMatrix[16], 
GLfloat pMatrix[16], GLfloat vLightPos[3], GLfloat vColor[4]);

参数1: 存储着⾊器种类-点光源着⾊器
参数2: 模型4*4矩阵
参数3: 投影4*4矩阵
参数4: 点光源的位置
参数5: 颜⾊值

使⽤场景: 在绘制图形时, 可以应⽤变换(模型/投影变化) 这种着⾊器会使绘制的图形产⽣阴影和光照的效果。它与默认光源着⾊器⾮常类似, 区别只是光源位置可能是特定的。

3.6 纹理替换矩阵着⾊器

GLShaderManager::UserStockShader(
GLT_SHADER_TEXTURE_REPLACE, GLfloat mvMatrix[16], GLint nTextureUnit);

参数1: 存储着⾊器种类-纹理替换矩阵着⾊器
参数2: 模型4*4矩阵
参数3: 纹理单元

使⽤场景: 在绘制图形时, 可以应⽤变换(模型/投影变化),这种着⾊器通过给定的模型视图投影矩阵,使⽤纹理单元来进行颜⾊填充。其中每个像素点的颜⾊是从纹理中获取。

3.7 纹理调整着⾊器

GLShaderManager::UserStockShader(
GLT_SHADER_TEXTURE_MODULATE, GLfloat mvMatrix[16], 
GLfloat vColor[4], GLint nTextureUnit);

参数1: 存储着⾊器种类-纹理调整着⾊器
参数2: 模型4*4矩阵
参数3: 颜色值
参数4: 纹理单元

使⽤场景: 在绘制图形时, 可以应⽤变换(模型/投影变化),这种着⾊器通过给定的模型视图投影矩阵。 着⾊器将⼀个基本⾊乘以⼀个取⾃纹理单元nTextureUnit 的纹理。将颜⾊与纹理进行颜⾊混合后才填充到⽚段中。

3.8 纹理光源着色器

GLShaderManager::UserStockShader(
GLT_SHADER_TEXTURE_POINT_LIGHT_DIEF, GLfloat mvMatrix[16],
GLfloat pMatrix[16], GLfloat vLightPos[3],
GLfloat vBaseColor[4], GLint nTextureUnit);

参数1: 存储着⾊器种类-纹理光源着色器
参数2: 模型4*4矩阵
参数3: 投影4*4矩阵
参数4: 点光源位置
参数5: 颜⾊色值(⼏几何图形的基本⾊色)
参数6: 纹理单元

使⽤场景: 在绘制图形时, 可以应⽤变换(模型/投影变化),这种着⾊器器通过给定的模型视图投影矩阵. 将一个纹理通过漫反射照明计算进行调整(相乘)。

4. 基本图元连接方式

图元描述
GL_POINTS每个顶点在屏幕上都是单独点
GL_LINES每一对顶点定义一个线段
GL_LINE_STRIP一个从的第一个顶点依次经过每一个后续顶点而绘制的线条
GL_LINE_LOOP和GL_LINE_STRIP相同,但是最后一个顶点和第一个顶点连起来了
GL_TRIANGLES每3个顶点定义⼀个新的三⻆形
GL_TRIANGLE_STRIP共用一个条带(strip)上的顶点的一组三角形
GL_TRIANGLE_FAN以一个圆点为中心呈扇形排列,共用相邻顶点的一组三角形
GL_POLYGON有多个顶点的通用多边形
GL_QUADS每4个顶点定义⼀个新的新四边形
GLQUAS_STRIP共用一个条带上顶点的一组四边形

5. OpenGL 点和线

/1.最简单也是最常⽤的 4.0f,表示点的⼤小 
glPointSize(4.0f);

//2.设置点的⼤小范围和点与点之间的间隔 
GLfloat sizes[2] = {2.0f,4.0f};
GLfloat step = 1.0f;

//3.获取点⼤小范围和最⼩步⻓
glGetFloatv(GL_POINT_SIZE_RANGE ,sizes);
glGetFloatv(GL_POINT_GRAULARITY ,&step);

//4.通过使⽤程序点⼤小模式来设置点⼤小
glEnable(GL_PROGRAM_POINT_SIZE);

//5.这种模式下允许我们通过编程在顶点着⾊器或⼏何着⾊器中设置点⼤小。
着色器内建变量: gl_PointSize(内建变量),并且可以在着⾊器源码直接写
gl_PointSize = 5.0

//6. 设置线段宽度 
glLineWidth(2.5f);

6. OpenGL 三角形

6.1 三角形环绕方式

在默认情况下,OpenGL 认为具有逆时针方向环绕的多边形为正面。 这就意味着上图左边是正面,右边是反面。 当然也可以修改正面的定义,但是不建议

glFrontFace(GL_CW);
GL_CW:告诉OpenGL 顺时针环绕的多边形为正面;
GL_CCW:告诉OpenGL 逆时针环绕的多边形为反面;

6.2 三角形带

对于很多表面或形状而言,我们会需要绘制几个相连的三角形。这是我们可以使用GL_TRANGLE_STRIP图元绘制一串相连的三角形,从而节省大量的时间。 优点:

  1. ⽤前3个顶点指定第1个三角形之后,对于接下来的每⼀个三角形,只需 要再指定1个顶点。需要绘制⼤量的三⻆形时,采⽤这种⽅法可以节省⼤量 的程序代码和数据存储空间
  2. 提供运算性能和节省带宽。更少的顶点意味着数据从内存传输到图形卡 的速度更快,并且顶点着⾊器需要处理的次数也更少了。

6.3 三角形扇

对于很多表⾯或者形状⽽言,我们会需要绘制⼏个相连的三角形。 这时我们可以使⽤GL_TRIANGLE_FAN 图元绘制⼀组围绕一 个中心点相连的三⻆形。始终共用顶点V0.

7. ⼯具类 GLBatch

GLBatch帮助我们把数据传递到顶点着色器和片元着色器,只要我们将数据复制到GLBatch,它就会自动帮我们传递数据。

//开始填充数据
void GLBatch::Begain(
              GLeunm primitive, GLuint nVerts,
              GLuint nTexttureUnints = 0);
参数1:图元枚举值
参数2:顶点数 
参数3:⼀组或者2组纹理理坐标(可选)

//复制顶点数据(⼀个由3分量x,y,z顶点组成的数组) 
void GLBatch::CopyVerterxData3f(GLfloat *vVerts);
//复制表⾯面法线数据
void GLBatch::CopyNormalDataf(GLfloat *vNorms);
//复制颜⾊色数据
void GLBatch::CopyColorData4f(GLfloat *vColors);
//复制纹理理坐标数据
void GLBatch::CopyTexCoordData2f(GLFloat *vTextCoords, GLuint uiTextureLayer);
//结束数据复制
void GLBatch::End(void);
//绘制图形
void GLBatch::Draw(void);