目录
- OpenGL渲染架构
- 投影方式设置
- 固定管线解析
- OpenGL基本图元解析
- 图元绘制
- GLBatch
OpenGL渲染架构
-
渲染管线流程
客户端和服务端
这二者详细的描述可以看我的这一篇文章视觉开发-OpenGL的客户端和服务器模式-
着色器
- 上图中的顶点着色器(Vertex Shader)和片元着色器(Fragment Shader)
- 着⾊器是使用GLSL编写的程序,类似C语言
- 顶点着⾊器处理从客户机输⼊的数据、应⽤变换、进⾏其他的类型的数学运算来计算关照效果、位移、颜⾊值等等。
- 上图中的顶点着色器(Vertex Shader)和片元着色器(Fragment Shader)
-
图元装配(primitive Assembly)
- 客户端无法干预
- 组合在一起的3个顶点->逐个片段进行光栅化->每个片段执行片元着色器
-
要点
- 为着色器传递渲染数据的方法有三种
- 属性(Attributes)
- uniform值
- 纹理(Texture Data)
- 为着色器传递渲染数据的方法有三种
-
属性,uniform,纹理,outputs
-
属性(Attributes)
- 对每一个顶点都要作改变的数据元素。
- 属性还可以是
颜色数据
,顶点数据
,纹理坐标
,光照法线
- 属性会从本地客户机内存中复制存储在图形硬件中的一个缓冲区上。这些属性只提供给顶点着⾊器使用,对于⽚元着⾊器没有太⼤意义
-
Uniform值
-
属性是⼀种对整个批次属性都取统一值的单一值。它是不变的。比如发生旋转(每一个顶点乘以旋转矩阵,顶点着色器),旋转矩阵就是没有太多改变的值;再比如视频颜色空间
YUV
通过转换矩阵转换成RGB
时通过uniform将转换矩阵传进来 - 通过设置uniform变量就紧接着发送⼀个图元批次命令:这⾥的uniform 变量每个批次改变一次,⽽不是每个顶点改变⼀次
- 与属性相同点:可以是浮点值、整数、布尔值
- 与属性不同点:顶点着色器和片元着色器都可以使用uniform变量。uniform变量还可以是标量类型、矢量类型、uniform矩阵。
-
属性是⼀种对整个批次属性都取统一值的单一值。它是不变的。比如发生旋转(每一个顶点乘以旋转矩阵,顶点着色器),旋转矩阵就是没有太多改变的值;再比如视频颜色空间
-
纹理(Texture Data)
什么时候会用到纹理呢,举个例子,
比如滤镜,其实滤镜就是对图片本身做处理,图片其实就是纹理,那么滤镜也就是改变纹理在读取时候的颜色值,比如彩色变灰色滤镜上会用
再比如渲染一个图形,像渲染一个正方体,我们可以用线框,颜色填充,也可以用纹理填充- 在顶点着⾊器、⽚段着色器中都可以对纹理数据进行采样和筛选
- 典型的应用场景: 片元着⾊器对⼀个纹理值进行采样,然后在一个三⻆形表面应用渲染纹理数据
- 纹理数据,不仅表现在图形,很多图形文件格式都是以无符号字节 (每个颜⾊色通道8位)形式对颜色分量进行存储的
-
输出(outs)
客户端代码是无法干预到outs的- 输出数据是作为⼀个阶段着色器的输出定义的,而后续阶段的着⾊器则作为输⼊定义
- 输出数据可以简单的从⼀个阶段传递到下一个阶段,也可以⽤不同的方式插入
- 客户端的代码接触不到这些内部变量我们的OpenGL开发暂时接触不到
投影方式设置
-
正投影
- 这就是一个正投影的例子,在3个轴(X,Y,Z)中,它们的范围都是-100到+100.这个视景体将包括所有的几何图形
- 如果你指定了视景体外的几何图形,就会被裁减掉!(它将沿着视景体的边界进行剪切)
- 在正投影中,所有在这个空间范围内的所有东西都将被呈现在屏幕上。⽽不存在照相机或视点坐标系的概念。
GLFrustum::SetOrthographic(
GLfloat xMin,
GLfloat xMax,
GLfloat yMin,
GLfloat yMax,
GLfloat zMin,
GLfloat zMax);
-
透视投影
透视投影会进行透视除法对距离观察者很远的对象进行缩短和收缩
。在投影到屏幕之后,视景体背⾯与视景体正面的宽度测量标准不同。
/ * GLFrustum类通过setPerspective ⽅方法为我们构建⼀个平截头体。
参数:
fFov:垂直⽅向上的视场⻆度
fAspect:窗口的宽度与高度的纵横比
fNear:近裁剪⾯距离 (视角到近裁剪面距离为fNear)
fFar:远裁剪面距离(视角到远裁剪面距离为fFar)
纵横比 = 宽(w)/⾼(h)
*/
CLFrustum::SetPerspective(
float fFov,
float fAspect,
float fNear ,
float fFar);
固定管线解析
在OpenGL 核⼼框架中,并没有提供任何内建渲染管线,在提交⼀个⼏何图形进行渲染之前,必须实现⼀个着色器。 我们可以去使用存储着⾊器。这些存储着⾊器由GLTools的C++类 GLShaderManager管理。它们能够满足进行基本渲染的基本要求。要求不高的程序员,这些存储着⾊器已经⾜以满⾜他们的需求。但是,随着时间的推移和开发经验的提升,⼤部分开发者可能不满⾜于此。 会开始⾃己着手去写着色器。
-
储存着色器的使用
-
GLShaderManager
初始化
// GLShaderManager 的初始化 GLShaderManager shaderManager; shaderManager.InitializeStockShaders();
-
GLShaderManager
属性
存储着⾊器为每⼀个变量都使⽤一致的内部变量命名规和相同的属性槽。以上就是存储着⾊器的属性列表 -
GLShanderManager
的uniform
值- ⼀般情况,要对⼏何图形进⾏渲染,我们需要给对象递交属性矩阵,⾸先要绑定我们想要使⽤的着⾊程序上,并提供程序的uniform值。但是GLShanderManager 类可以暂时为我们完成工作
- useStockShader 函数会选择⼀个存储着⾊器并提供这个着⾊器的uniform值
GLShaderManager::UserStockShader(GLeunm shader...);
-
OpenGL基本图元解析
-
单位(Identity 着⾊器)
- 单位着⾊器:只是简单地使用默认笛卡尔坐标系(坐标范围(-1.0, 1.0))
- 所有的⽚段都应用同⼀种颜⾊,⼏何图形为实⼼和未渲染的
- 需要设置存储着色器⼀个属性: GLT_ATTRIBUTE_VERTEX(顶点分量)
- 参数2:vColor[4],你需要的颜色
GLShaderManager::UserStockShader(GLT_SHADER_FLAT,GLfloat mvp[16],GLfloat vColor[4]);
-
平面着色器
- GLT_SHADER_FLAT:平面着色器
- mvp[16]:允许变化的4*4矩阵
- 颜色:vColor[4]
- 它将统一着⾊色器器进行了拓展。允许为⼏何图形变换指定一个 4 * 4 变换矩阵。经常被称为
模型视图投影矩阵
GLShaderManager::UserStockShader(GLT_SHADER_FLAT,GLfloat mvp[16],GLfloat vColor[4]);
-
上色着色器
- 在⼏何图形中应用的变换矩阵。需要设置存储着⾊器的 GLT_ATTRIBUTE_VERTEX(顶点分量) 和GLT_ATTRIBUTE_COLOR(颜⾊分量) 2个属性。颜色值将被平滑地插⼊顶点之间(平滑着⾊)
GLShaderManager::UserStockShader(GLT_SHADER_SHADED,GLfloat mvp[16]);
-
默认光源着色器
- GLT_SHADER_DEFAULT_LIGHT: 默认光源着⾊器
- mvMatrix[16]: 模型视图矩阵
- pMatrix[16]: 投影矩阵
- vColor[4]: 颜⾊值
GLShaderManager::UserStockShader(GLT_SHADER_DEFAULT_LIGHT,GLfloat mvMatrix[16],GLfloat pMatrix[16],GLfloat vColor[4]);
-
点光源着⾊器
- 参数1:点光源着⾊器
- 参数2:模型视图矩阵
- 参数3:投影矩阵
- 参数4:视点坐标光源位置
- 参数5:颜⾊值
- 区别:点光源着⾊器和默认光源着⾊器很相似,区别在于:光源位置是特定的。 同样需要设置存储着⾊器的 GLT_ATTRIBUTE_VERTEX(顶点分量) 和GLT_ATTRIBUTE_NORMAL(表⾯法线)
GLShaderManager::UserStockShader(GLT_SHADER_DEFAULT_LIGHT_DIEF,GLfloat mvMatrix[16],GLfloat pMatrix[16],GLfloat vLightPos[3],GLfloat vColor[4]);
-
纹理理替换矩阵
- 着色器通过给定的模型视图投影矩阵,使⽤绑定到 nTextureUnit (纹理单元) 指定纹理单元的纹理对⼏何图形进行变化。片段颜色:是直接从纹理样本中直接获取的。
需要设置存储着⾊器的GLT_ATTRIBUTE_VERTEX(顶点分量)
和
GLT_ATTRIBUTE_NORMAL(表⾯法线)
GLShaderManager::UserStockShader(GLT_SHADER_TEXTURE_REPLACE,GLfloat mvMatrix[16],GLint nTextureUnit);
- 着色器通过给定的模型视图投影矩阵,使⽤绑定到 nTextureUnit (纹理单元) 指定纹理单元的纹理对⼏何图形进行变化。片段颜色:是直接从纹理样本中直接获取的。
-
纹理调整着⾊器
- 将⼀个基本色乘以一个取自纹理单元 nTextureUnit 的纹理。需要设置存储着⾊器的
GLT_ATTRIBUTE_VERTEX(顶点分量)
和
GLT_ATTRIBUTE_TEXTURE0(纹理坐标)
GLShaderManager::UserStockShader(GLT_SHADER_TEXTURE_MODULATE,GLfloat mvMatrix[16],GLfloat vColor[4],GLint nTextureUnit);
- 将⼀个基本色乘以一个取自纹理单元 nTextureUnit 的纹理。需要设置存储着⾊器的
-
纹理光源着⾊器
将⼀个纹理通过漫反射照明计算机进⾏调整(相乘)。光线在视觉空间中 的位置是给定的。需要设置存储着色器的
GLT_ATTRIBUTE_VERTEX(顶点分量)
和
GLT_ATTRIBUTE_TEXTURE0(纹理坐标)
、GLT_ATTRIBUTE_NORMAL(表面法线)
参数1:纹理理光源着⾊器
参数2:投影矩阵
参数3:视觉空间中的光源位置
参数4:⼏何图形的基本色
-
参数5:将要使⽤的纹理单元
GLShaderManager::UserStockShader(GLT_SHADER_TEXTURE_POINT_LIGHT_DIEF,GLfloat mvMatrix[16],GLfloat pMatrix[16],GLfloat vLightPos[3],GLfloat vBaseColor[4],GLint nTextureUnit);
图元绘制
-
点和线
- 点,是最简单的图像
- 修改点大小的方法:
//1.最简单也是最常用的4.0f ,表示点的大小
glPointSize(4.0f) ;
//2.设置点的大小范围和点与点之间的间隔
GLfloat sizes[2] = {2.0f,4.0f};
GLfloat step = 1.0f;
//获取点大小范围和最小步长
glGetFloatv(GL_POINT_SIZE_RANGE,sizes);
glGetFloatv(GL_ POINT_GRAULARITY ,&step);
//3.通过使用程序点大小模式来设置点大小
glEnable (GL_ PROGRAM_ POINT_SIZE) ;
//这种模式下允许我们]通过编程在顶点着器或几何着色器中设置点大小。着色器内建变量: gl_ PointSize,并且可以在器源码直接写
gl_PointSize = 5.0;
-
线
- 一个线段就是2个顶点之间绘制的
- 默认情况下,线段的宽度是一个像素。改变线段唯一的方式通过:
//1.设置独立线段宽度为2.5f;
glLineWidth(2.5f);
-
线环
- 线环是线带的一种简单拓展。在线带的基础上额外增加一条线带闭合的
-
三角形
-
最简单的实体多边形就是三角形,它只有3个边。光栅化硬件最欢迎三角形。并且现在OpenGL已经是OpenGL中支持的唯一种多边形。每3个顶点定义一个新的三角形
-
-
环绕
-
将顺时针方向绘制的三角形用逆时针的方式绘制。在绘制第一个三角形时,线条是按照从VO-V1,再到V2。最后再回到VO的个闭合三角形。这个是沿着顶点顺时针方向。这种顺序与方向结合来指定顶点的方式称为环绕。
上图的2个三角形的缠绕方向完全相反
在默认的情况下,OpenGL认为
具有逆时针方向环绕的多边形是正面的
。而右侧的顺时针方向三角形是三角形的背面这个问题会很重要:
因为我们常常希望为一个多边形的正面和背面分别设置不同的物理特征。我们可以完全隐藏一个多边形的背面,或者给它设置一种不同的颜色和反射属性。纹理图像在背面三角形中也是相反的。在一个场景中,使所有的多边形保持环绕方向的一致,并使用正面多边形来绘制所有实心物体的表面是非常重要的
。
-
//定义前向和背向的多变形:
glF rontFace (mode)
参数: GL_CW | GL_CCW
GL_CCW: 表示传入的mode会选择逆时针为前向
GL_CW: 表示顺时针为前向。
默认: GL_CCW。逆向时针为前向。
-
三角地带
- 对于很多表面和形状来说,我们可能需要绘制几个相连的三角形。我们可以使用GL_TRIANGLE_STRIP图元绘制一串相连的三角形。从而节省大量的时间。使用三角带而不是分别指定每个三角形,这样做的优点:
- 用前3个顶点指定第1个三角形之后,对于接下来的每一个三角形,只需要再指定1个顶点。需要绘制大量的三角形时,采用这种方法可以节省大量的程序代码和数据存储空间
- 提供运算性能和节省带宽。更少的顶点意味着数据从内存传输到图形卡的速度更快,并且顶点着色器需要处理的次数也更少了
- 对于很多表面和形状来说,我们可能需要绘制几个相连的三角形。我们可以使用GL_TRIANGLE_STRIP图元绘制一串相连的三角形。从而节省大量的时间。使用三角带而不是分别指定每个三角形,这样做的优点:
GLBatch
GLTools库中包含额一个简单的容器类,叫做GLBatch。这个类可以作为7种图元的简单批次容器使用。而且它知道在使用GL_ShaderManager 支持的任意存储着色器时如何对图元进行渲染
void GLBatch: :Begain(GLeunm primitive,GLuint nVerts,GLuint nTe
xttureUnints = 0) ;
参数1:图元
参数2:顶点数
参数3:一组或者2组纹理坐标(可选)
// 复制表面法线
void GLBatch:: CopyNormalDataf(GLfloat *vNorms) ;
//复制颜色
void GLBatch:: CopyColorData4f(GLfloat *vColors) ;
//复制纹理坐标
void GLBatch::CopyTexCoordData2f(GLFloat *vTextCoords , GLuint uiTextureLayer);
// 结束绘制
void GLBatch::End(void);