一、OpenGL与着色器
在OpenGL3.0之前,OpenGL包含一个固定功能的管线,它可以在不使用着色器的情况下处理几何和像素数据。在3.1版本之后,固定管线从核心模式中去掉了。因此现在需要使用着色器来完成。
二、基础图形管线
OpenGL 中的图元只不过是顶点的集合以预定的方式结合在一起的。
例如:一个点就是一个图元。
2.1 OpenGL渲染管线流程解析
OpenGL在处理任何图形渲染,都是依据它. 基于OpenGL 封装的框架都是也都是遵循这个图的规则.
客户端(client)、服务端(server)
管线分为上下两个部分,上部分是客户端,下部分是服务端。
客户端是存储在CPU存储器中的,并且在应用程序中执行,或者在系统内存的驱动程序中执行。驱动程序会将渲染命令和数组结合起来,发送给服务端执行(在一台计算机上,服务器实际指的是图形加速卡上的硬件和内存)
服务端和客户机在功能上也是异步执行他们独立的软件和硬件块。我们是希望2个端都尽量的不停的工作。客户端在不断把数据块和命令块组合在一起输送到缓冲区,然后缓冲区就发送到服务器执行。
如果服务器停止工作等待客户机,或者客户机停止工作等待服务器做好接收更多的命令准备,我们把这种情况称为管线停滞
着色器
上图的Vertex Shader(顶点着色器)和Fragment Shader(片段着色器)
着色器是使用GLSL语言编写的。看起来和C语言很相似。着色器必须源代码中编译和链接在一起。最终准备就绪的着色器程序。
顶点着色器(Vertex Shader)-> 处理从客户机输入的数据、应用变换、进行其他的类型数学运算来计算光照效果、位移、颜色值等等。(为了渲染工三个顶点的三角形,顶点着色器意味着将执行三次,也就是每个顶点执行一次),在目前硬件上有多个执行单元同时运行,也就意味着所有的顶点可以同时进行处理。
上图的图元装配(Primitive Assembly)说明的是:3个顶点已经组合在一起,而三角形赢逐个片段的进行光栅化。每个片段通过执行片元着色器进行填充。片元着色器会输出我们将在屏幕上看到的最终颜色值。
我们必须在之前为着色器提供数据,否则将无法实现。
有三种向OpenGL着色器传递渲染数据的方法供我们选择
- 属性(Attributes)
- uniform值
- 纹理(TextureData)
三、属性、uniform、纹理、输出
3.1 属性(Attributes)
属性:就是对每个顶点都要做改变的数据元素。实际上,顶点位置本身就是一个属性。属性值可以是float、int、bool数据
属性总是以思维向量的形式进行内部存储的,即使我们不会使用所有的4个分量。一个顶点可能存储(x,y,z),将占有4个分量的3个。
实际上如果是在平面情况下,只要xy平面上就能绘制,那么z分量就会自动设置为0.
属性可以是:纹理坐标、颜色值、光照计算表面法线
属性会从本地客户机内存中复制存储砸在图形硬件中的一个缓冲区上。这些属性只提供给顶点着色器使用。对于片段着色器意义不大。
3.2 Uniform值
属性是一种对整个批次属性都取统一值得单一值。它是不变的。通过uniform变量就紧接着发送一个图元批次命令,Uniform变量实践上可以无数次限制的使用,设置一个应用于整个表面的单个颜色值,还可以设置一个时间值,在每次渲染某种类型的顶点动画时修改它。
- 注意:这里的uniform变量每个批次改变一次,而不是每个顶点改变一次。
- uniform变量最常见的应用是在顶点渲染中设置变换矩阵。
- 与属性相同的:可以是float、int、Bool
- 与属性不同点:顶点着色器和片元着色器都可以直接使用uniform变量。uniform变量还可以是标量类型、矢量类型、uniform矩阵。
3.2 纹理(Texture)
传递给着色器的第三种数据类型:纹理数据(Texture Data)
- 在顶点着色器、片段着色器都可以对纹理数据进行采样和筛选。
- 典型的应用场景:片段着色器对一个纹理值进行采样,然后在一个三角形表面应用渲染纹理数据。
- 纹理数据,不仅仅表现在图形,很多图形文件格式都是以无符合字节(每个颜色通道8位)形式对颜色分量进行存储的。
四、坐标系
4.1 正投影
这就是一个正投影的 ,在所在3个轴(X,Y,Z)中,它们的范围都是从-100到+100。这个视景体将包括所有的 何图形。
如果你指定了视景体外的几何图形,就会被裁减掉!(它将沿着视景体的边界进行剪切)
在正投影中,所有在这个空间范围内的所有东西都将被呈现在屏幕上。而不存在照相机或视点坐标系的概念。
4.2 透视投影
透视投影会进行透视除法对距离观察者很远的对象进行缩短和收缩。在投影到屏幕之后,视景体背面与视景体正面的宽度测量标准不同。
上图所示:平截头体(frustum)的几何体,它的观察方向是从金字塔的尖端到宽阔端。观察者的视点与金字塔的尖端拉开一定距离。
GLFrustum类通过setPerspective 方法为我们构建一个平截头体。
CLFrustum::SetPerspective(float fFov,float fAspect,float fNear,float fFar);
参数:
fFov:垂直方向上的视场角度
fAspect:窗口的宽度与高度的纵横比 ( 纵横比 = 宽(w)/ (h) )
fNear:近裁剪面距离
fFar:远裁剪面距离
存储着色器
5.1 使用背景
在OpenGL 核心框架中,并没有提供任何内建渲染管线,在提交一个几何图形进行渲染之前,必须实现一个着色器。
5.2 存储着色器的使用
1.1 GLShaderManger的初始化
// GLShaderManger
GLShaderManger shaderManger;
shaderManger.initializeStockShaders()
1.2 GLShaderManger
标识符 | 描述 |
---|---|
GLT_ATTRIBUTE_VERTEX | 3分量(x,y,z)顶点位置 |
GLT_ATTRIBUTE_COLOR | 4分量(r,g,b,a)顶点位置 |
GLT_ATTRIBUTE_NORMAL | 3分量(x,y,z)表面法线 |
GLT_ATTRIBUTE_TEXTURE0 | 第一对2分量坐标(s,t)纹理坐标 |
GLT_ATTRIBUTE_TEXTURE1 | 第一对2分量坐标(s,t)纹理坐标 |
存储着色器位每个变量都使用一致的内部变量命名规则和相同的属性槽。以上就是存储着色器的属性列表。
1.3 GLShaderManger的uniform值
一般情况,要对几何图形进行渲染,我们需要给对象递交属性矩阵,首先要绑定我们想要使用的着色器程序上,并提供程序的uniform值。但是GLShanderManager 类可以暂时为我们完成工作。
1)useStockShader 函数会选择一个存储着色器并提供这个着色器的uniform值。
GLShaderManager::UserStockShader(GLEnum shader...);
5.3 单元(Indentity着色器)
GLShaderManager::UserStockShader(GLT_ATTRIBUTE_VERTEX, GLfloat vColor[4]);
参数1:GLT_ATTRIBUTE_VERTEX(顶点分量)
参数2:vColor[4],你需要的颜色
单元着色器:只是简单的使用默认笛卡尔坐标系(坐标范围(-1.0,1.0))。所有的片段都应用于同一种颜色,几何图形位实心和未渲染的。
5.4 平面着色器
GLShaderManager::UserStockShader(GLT_SHADER_FLAT, GLfloat mvp[16], GLFloat cColor[4]);
参数1:平面着色器
参数2:允许变化的4*4矩阵
参数3:颜色
5.5 上色着色器
GLShaderManager::UserStockShader(GLT_SHADER_SHADED, GLfloat mvp[16]);
参数1:平面着色器
参数2:允许变化的4*4矩阵
颜色颜色值将被平滑的插入顶点之间(平滑着色器)
5.6 默认光源着色器
GLShaderManager::UserStockShader(GLT_SHADER_DEFAULT_LIGHT, GLfloat mvMatrix[16], GLfloat Matrix[16], GLfloat vColor[4]);
参数1:默认光源
参数2:模型视图矩阵
参数3:投影矩阵
参数4:颜色值
点光源着色器和默认光源着色器很相似,区别在于:光源位置是特定的。同样需要设置存储着色器的GLT_ATTRIBUTE_VERTEX(顶点分量)和GLT_ATTRIBUTE_NORMAL(表面法线)
5.7
点光源着色器 GLShaderManager::UserStockShader(GLT_SHADER_DEFAULT_LIGHT_DIEF,GLfloat mvMatrix[16], GLfloat pMatrix[16],GLfloat vLightPos[3],GLfloat vColor[4]);
参数1:点光源着色器
参数2:模型视图矩阵
参数3:投影矩阵
参数4:视点坐标光源位置
参数5:颜色值
点光源着色器和默认光源着色器很相似,区别在于: 光源位置是特定的。同样需要设置存储着色器的 GLT_ATTRIBUTE_VERTEX(顶点分量) 和 GLT_ATTRIBUTE_NORMAL(表面法线)
5.8 纹理替换矩阵
GLShaderManager::UserStockShader(GLT_SHADER_TEXTURE_REPLACE,GLfloat mvMatrix[16],GLint nTextureUnit);
着色器通过给定的模型视图投影矩阵,使用绑定到 nTextureUnit (纹理单元) 指定纹理里单元的纹理对几何图形进行变化。
片段颜色 :是直接从纹理样本中直接获取的。
需要设置存储着色器的GLT_ATTRIBUTE_VERTEX(顶点分量) 和 GLT_ATTRIBUTE_NORMAL(表面法线)
5.9 纹理调整着色器
讲一个基本色乘以一个取自纹理单元 nTextureUnit 的纹理。 需要设置存储着色器的 GLT_ATTRIBUTE_VERTEX(顶点分量) 和 GLT_ATTRIBUTE_TEXTURE0(纹理坐标)
GLShaderManager::UserStockShader(GLT_SHADER_TEXTURE_MODULATE,GLfloat mvMatrix[16],GLfloat vColor[4],GLint nTextureUnit);
5.10 纹理光源着色器
将一个纹理通过漫反射照明计算机进行调整(相乘)。光线在视觉空间中的位置是给定的。需要设置存储着色器的 GLT_ATTRIBUTE_VERTEX(顶点分量) 和GLT_ATTRIBUTE_TEXTURE0(纹理坐标)、GLT_ATTRIBUTE_NORMAL(表面法线)
GLShaderManager::UserStockShader(GLT_SHADER_TEXTURE_POINT_LIGHT_DIEF,GLfloat mvMatrix[16],GLfloat pMatrix[16],GLfloat vLightPos[3],GLfloat vBaseColor[4],GLint nTextureUnit);
参数1:纹 光源着色器
参数2:投影矩阵
参数3:视觉空间中的光源位置
参数4: 几何图形的基本
参数5:将要使用的纹理单元
五、图元
OpenGL 基本7种基本图元
图元 | 描述 |
---|---|
GL_POINTS | 每个顶点在屏幕上都是单独点 |
GL_LINES | 每一对顶点定义⼀个线段 |
GL_LINE_STRIP | ⼀个从第一个顶点依次经过每⼀个后续顶点⽽绘制的线条 |
GL_LINE_LOOP | 和GL_LINE_STRIP相同,但是最后⼀个顶点和第⼀个顶点连接起来了. |
GL_TRIANGLES | 每3个顶点定义⼀个新的三角形 |
GL_TRIANGLE_STRIP | 共⽤⼀个条带(strip)上的顶点的一组三角形 |
GL_TRIANGLE_FAN | 以一个圆点为中心呈扇形排列,共⽤相邻顶点的⼀组三角形 |
- OpenGL 点/线
- OpenGL 三角形 默认逆时针环绕为正三角,顺时针环绕为逆三角
- OpenGL 三角形环绕方式
- OpenGL 三角形带
- OpenGL 三角形扇
- OpenGL 工具类 GLBatch
- OpenGL 图形绘制的3种填充方式 1、线框填充 2、颜色填充 3、纹理填充