OpenGL基础渲染
一、OpenGL 与 着色器
在OpenGL 3.0之前,OpenGL包含一个固定功能的管线,它可以在不使用着色器的情况下处理几何与像素数据。在3.1版本开始,固定管线从核心模式去掉。因此现在需要使用着色器来完成工作。
使用OpenGL来说,我们会使用GLSL(OpenGL Shading Language,它是在OpenGL 2.0版本发布的)。语法与C/C++类似。
二、基础图形管线
OpenGL 中的图元只不过是顶点的集合以预定的方式结合在一起。
例如:一个单独的点就是一个图元。它只需要一个顶点
2.1 OpenGL 渲染管线简化版本
客户机(Client)、服务器(Server)
1、管线分上下两个部分,上部分是客户端,下半部是服务端
2、客户端是存储在CPU存储器中的,并且在应用程序中执行,或者在主系统内存的驱动程序中执行。驱动程序会将渲染命令和数组组合起来,并发送给服务器执行!(在一台典型的个人计算机上,服务器实际上就是图形加速卡上的硬件和内存)
3、服务器和客户机在功能上也是异步的它们各自独立的软件或者硬件块。我们是希望它们2个端都尽量在不停的工作。客户端不断把数据块和命令块组合在一起输送到缓冲区,然后缓冲区就会发送到服务器执行。
4、如果服务器停止工作等待客户机,或者客户机停止工作来等待服务器做好接收更多的命令和准备,我们把这种情况称为管线停滞。
着色器
上图的Vertex Shader(顶点着色器) 和 Fragment Shader(片段着色器)
1、着色器是使用GLSL编写的程序,看起来与C语言非常类似。着色器必须从源代码中编译和链接在一起。最终准备就绪的着色器程序
2、顶点着色器(Vertex Shader)-->处理从客户机输入的数据、应用变换、进行其他的类型数学运算来计算光照效果、位移、颜色值等等。(为了渲染共三个顶点的三角形,顶点着色器将执行三次,也就是每个顶点执行一次),在目前的硬件上有多个执行单元同时运行,就意味着所有的3个顶点可以同时进行处理。
3、上图的图元装配(Primitive Assembly) 说明的是:3个顶点已经组合在一起,而三角形已经逐个片段的进行了光栅化。每个片段通过执行片元着色器进行填充。片元着色器会输出我们将在屏幕看到的最终颜色值。
重点!
我们必须在这之前为着色器提供数据,否则什么都无法实现!
有3种向OpenGL着色器传递渲染数据的方法可提供我们选择
1、属性(Attributes)
2、uniform值
3、纹理(TextureData)
三、属性、uniform值、纹理、输出
3.1 属性
属性:就是对每一个顶点都要作改变的数据元素。实际上,顶点位置本身就是一个属性。属性值可以是浮点数、整数、布尔数据。
1、属性总是以四维向量的形式进行内部存储的,即使我们不会使用所有的4个分 。一个顶点位置可能存储(x,y,z),将占有4个分量中的3个。
2、实际上如果是在平面情况下:只要在xy平面上就能绘制,那么Z分量就会自动设置为0;
3、属性还可以是:纹理坐标、颜色值、关照计算表面法线
4、在顶点程序(shader渲染)可以代表你想要的任何意义。因为都是你设定的。
5、属性会从本地客户机内存中复制存储在图形硬件中的一个缓冲区上。这些属性只提供给顶点着色器使用 ,对于片元着色器没有太大意义。
6、声明:这些属性对每个顶点都要做改变,但并不意味着它们的值不能重复。通常情况下,它们都是不一样的,但有可能整个数组都是同一值的情况。
3.2 Uniform值
属性是一种对整个批次属性都取统一值的单一值。它是不变的。通过设置uniform变量就紧接着发送一个图元批次命令,Uniform变量实际上可以无数次限制地使用,设置一个应用于整个表面的单个颜色值,还可以设置个时间值。在每次渲染某种类型的顶点动画时修改它。
1、注意:这里的uniform 变量每个批次改变一次,而不是每个顶点改变一次。
2、uniform变量最常见的应用是在顶点渲染中设置变换矩阵
3、与属性相同点:可以是浮点值、整数、布尔值
4、与属性不同点:顶点着色器和片元着色器都可以使用uniform变量。uniform 变量还可以是标量类型、矢量类型、uniform矩阵。
3.3 纹理
传递给着色器的第三种数据类型:纹理数据
1、在顶点着色器、片段着色器中都可以对纹理数据进行采样和筛选。
2、典型的应用场景: 段着色器对一个纹理值进行采样,然后在一个三角形表面应用渲染纹理数据。
3、纹理数据,不仅仅表现在图形,很多图图形文件格式都是以无符号字节(每个颜色通道8位)形式对颜色分量进行存储的。
3.4 输出
在图表中第四种数据类型是输出(out);输出数据是作为一个阶段着色器的输出定义的,后续阶段的着色器则作为输入定义。
1、输出数据可以简单的从一个阶段传递到下一个阶段,也可以用不同的方式插入。
2、客户端的代码接触不到这些内部变量,我们的OpenGL开发暂时接触不到。
四、创建坐标系
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 GLShaderManager 的初始化
// GLShaderManager 的初始化
GLShaderManager shaderManager;
shaderManager.InitializeStockShaders();
1.2 GLShaderManager 属性
存储着色器为每一个变量都使用一致的内部变量命名规则和相同的属性槽。以上就是存储着色器的属性列表
1.3 GLShanderManager 的 uniform值
一般情况,要对几何图形进行渲染,我们需要给对象递交属性矩阵,首先要绑定我们想要使用的着色器程序上,并提供程序的uniform值。但是GLShanderManager 类可以暂时为我们完成工作。
1)useStockShader 函数会选择一个存储着色器并提供这个着色器的uniform值。
GLShaderManager::UserStockShader(GLeunm shader...);
5.3 单位(Identity 着色器)
GLShaderManager::UserStockShader(GLT_ATTRIBUTE_VERTEX,GLfloat vColor[4]);
单位着色器:只是简单地使用默认笛卡尔坐标系(坐标范围(-1.0,1.0))。所有的片段都应用同一种颜 ,几何图形为实心和未渲染的。
需要设置存储着色器一个属性:
GLT_ATTRIBUTE_VERTEX(顶点分量)
参数2:vColor[4],你需要的颜
5.4 平面着色器
GLShaderManager::UserStockShader(GLT_SHADER_FLAT,GLfloat mvp[16],GLfloat vColor[4]);
参数1:平面着色器
参数2:允许变化的4*4矩阵
参数3:颜色
它将统一着色器进行了扩展。允许为几何图形变换指定一个 4 * 4 变换矩阵。经常被称为“模型视图投影矩阵”
5.5 上色着色器
GLShaderManager::UserStockShader(GLT_SHADER_SHADED,GLfloat mvp[16]);
在几何图形中应用的变换矩阵。
需要设置存储着色器的GLT_ATTRIBUTE_VERTEX(顶点分量) 和GLT_ATTRIBUTE_COLOR(颜色分量) 2个属性。颜色值将被平滑地插入顶点之间(平滑着色器)
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 纹理替换矩阵
着色器通过给定的模型视图投影矩阵,使用绑定到 nTextureUnit (纹理单元) 指定理里单元的纹理对几何图形进行变化。
片段颜色 :是直接从纹理样本中直接获取的。
需要设置存储着色器的GLT_ATTRIBUTE_VERTEX(顶点分量) 和 GLT_ATTRIBUTE_NORMAL(表面法线)
GLShaderManager::UserStockShader(GLT_SHADER_TEXTURE_REPLACE,GLfloat mvMatrix[16],GLint nTextureUnit);
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:将要使用的纹理单元