华科_图形学笔记_03_可编程渲染管线

计算机图形学_华中科技大学_中国大学MOOC(慕课)


3.1_从固定到可编程

提纲

 

图形编程的发展

标准图形函数库越来越常见

固定功能渲染流水线

渲染流水线的起点是CPU,在应用程序阶段,需要CPU把数据从硬盘加载到系统内存中,然后网格和纹理数据又到加载到显卡的存储空间,也就是显存中,之后当GPU从CPU那里得到渲染命令后,会执行一系列的渲染工作,也就是说有一系列的工序.

流水线的概念

通过引入流水线可以有效的提高单位时间的效率,因此GPU在渲染的时候也采用了流水线的做法

开始流水线是固定的,就好比一个电路,对于固定流水线,程序员只能固定改变其中几个开关的状态,无法改变整个电路的结构,可是由于图形硬件的新功能不断出现,为了充分利用更加强大的新功能,程序员开始通过各种方式来突破固定流水线的限制

固定到可编程 钩函数hooks的出现

为了实现这个目标,API的开发者在渲染流水线中提供了钩函数,通过钩函数可以使用可编程着色器,修改流水线中某些特定步骤的行为,这些着色器替代了这些步骤原有的固定实现方式,可以产生程序员想要的任何效果,而这些效果常常是原有固定功能流水线所无法实现的,这样一来就出现了可编程着色器,

而之后则是将整个流水线变为可编程的.

这个时候程序员就可以"改变整个电路的结构了"

CPU渲染管线

左边这幅图,其中有三维物体以及在空间的摆放,而虚拟相机就是视点的位置,这是可变的,另外还有光源,照明模式,纹理也是可以调整的,总之,我们需要在二维的屏幕上得到一个显式,这其中图形的位置,形状是由他们的几何形状,环境特性和摄像机的位置决定的,而物体的外观,则是由材质的特性,光源和纹理来确定,实现这个功能就是渲染管线的工作.

渲染流水线的三个阶段

应用程序阶段 >> 几何阶段 >> 光栅化阶段

应用程序阶段

几何阶段

光栅化阶段

现代GPU渲染管线的流程

应用程序阶段是有CPU完成的

几何阶段和光栅化阶段是有GPU完成的


3.2_探秘CPU渲染管线

提纲

浅绿部分表示可编程的

深绿部分表示可选的

蓝色部分表示可配置

黑色部分表示是固定的,程序员不能修改

几何阶段的细节

观察空间 就是摄像机Camera,也就是人眼的视角

顶点着色

确定顶点上材质上的光照效果.这个着色过程是涉及对象上各个点对着色方程的计算

可在每个顶点处储存各种材料数据.比如点的位置,法线,颜色,或者是计算着色方程所需要的的其他任何数字信息

顶点着色的结果形式也是多种多样的.可以是颜色,向量,纹理坐标等着色数据

这些计算完成后,会被发送到光栅化阶段进行插值操作

几何,曲面细分着色器

是一个可选的着色器,它的输入是顶点数据,它可以对图元的顶点进行操作,它可以高效的创建和删除几何图元,也可以通过增加顶点,让现有的多边形网格更加逼近曲面,也就是进行所谓的曲面细分

图中从左到右就是进行曲面细分

1.这里的曲面细分可以分离出来,成为曲面细分着色器

2.在没有几何着色器或者曲面细分着色器的时候,这部分工作是由应用程序阶段来完成的,也就是有由CPU来进行计算的,CPU本来可以进行计算,但是GPU的计算效率更高

裁剪

在刚才的模型视图变换之后,已经将模型变换到观察空间

如果图是一个透视投影的观察空间,它的形状是一个四棱台,由于观察方式的不同,观察空间的形状和大小也就各有不同,这样一来,后期进行裁剪和屏幕映射就比较麻烦,因此需要进行规范化的投影变换,将观察空间变换到一个规范化的观察空间中,不同的图形标准中,这个规范化的观察空间是不一样的,比如在OpenGL中,这个Z分量取值通常是-1到1之间,这样一来便于进行后续的工作,当然首先就是进行裁剪,也是就是判断可见性 

在裁剪空间中,如图,蓝色图元是看不见的,红色图元完全可见,绿色图元部分可见

对于CPU来说,和顶点着色器不同,裁剪工作这个部分属于可配置部分,也就是程序员对观察方式进行指定,裁剪工作就由GPU自动完成了,之后的屏幕映射则完全属于固定部分

刚才裁剪的形体仍然是三维的,现在需要在二维的显示设备上显示,很显然需要把三维转变成二维,也就是把刚才规范化空间中图元的X和Y坐标转换到屏幕坐标系中

每个点的Z坐标,也就是屏幕的深度值哪去了?...当然不会丢

除了刚才屏幕坐标系的顶点位置,外加一些额外信息,比如说深度值,法线信息,纹理坐标,这些数据都会输送给光栅化阶段

到这里几何阶段经历了 >> 模型变换 >> 视图变换 >> 投影变换 >> 屏幕映射 >>...几个部分

也经历从建模坐标系,世界坐标系,观察坐标系,到屏幕坐标系的转换

光栅化阶段

由于是输入三角网格的顶点,而而之后需要得到这个三角网格对像素的覆盖情况,因此,我们需要得到三角形边界的表示方式,就好比把顶点连接成三角网格,这个三角网格的计算过程,就叫做三角形设定

三角形遍历阶段的输入就是三角形设定的结果,以网格中的一个三角为例,需要根据顶点信息,最终计算得到覆盖三角形网格的像素位置,对应的这些像素就生成一个片元,而片元中每个像素的状态都是通过对三个顶点信息进行插值而得到的

以深度值为例,可以通过插值,得到每一个像素点的深度值

其余的法线,纹理坐标也是通过插值计算出来的

另外,三角变设置和三角形遍历都是属于管线的固定部分,由管线自动来完成

片元着色

这是一个非常重要的可编程着色阶段,其实之前的光栅化阶段并不会影响屏幕上每个像素的颜色值,而是会产生一系列的数据信息,用来描述一个三角网格是怎样覆盖每个像素的,每个片元就负责存储这样一个数据,那么片元着色就可以根据这些输入的数据,计算每个片元的着色值,这个阶段可以完成很多重要的渲染技术,比如纹理贴图 

但是直到这里,片元着色都没有真正影响到颜色值,真正要影响到像素的颜色值,必须经过逐片元操作,这里的逐片元操作有的书中也就做输出合并阶段或者是融合阶段

这是将每个片元的深度和颜色与帧缓存结合在一起的地方,其实刚才的片元着色,已经算出了每一个像素着色点的颜色值,可是为什么还需要这样一个融合阶段呢?

有时.物体有前后的遮挡

有时有的物体是透明或者半透明的,那么对应的像素点是否要进行相应的融合计算?

融合过程还是很复杂的,总之直到逐片元进行了融合之后,才会得到帧缓存中每个像素点最终的颜色值

光栅化阶段


3.03_着色器编程

提纲

应用程序由CPU来完成,而之后的过程则由GPU来完成,那么这两者如何来协作?

如果要开发者直接来访问GPU,是一件十分麻烦的事情,我们需要和各种寄存器,显存打交道

而图形编程接口则在这些硬件上进行了一层抽象,也就是我们所说图形标准

而现在事实上的工业标准则是OpenGl和DirectX

因此,应用程序可以调用OpenGL或者DirectX的图形接口,将渲染所用的数据传递给CPU,之后调用相应的渲染命令进行图形渲染,而显卡的驱动,则需要将这些命令成CPU理解的代码进行真正的回执,因此现在一个显卡的制造商一般都会提供DX或者OPENGL的驱动,如果DX或者OPENGL更新了版本,相应的CPU厂家也会提供新的驱动

四个着色器

着色树

GLSL

EBO,VBO和VAO

VAO本身并没有存储顶点的相关属性数据,这些信息还是在VBO中,而VAO相当于是对多个VBO的引用,也就是这些VBO组合在一起,作为一个对象来统一管理

例子_四边形的绘制


3.4_课程中试验的设置和图形编程的基本框架介绍

提纲

实验体系

扩展实验

实验环境

不同的思路对应得实验环境要求也是不同的.

图形编程思路

OpenGL 3.3

GLSL 对应的是 330版本

GLFW是一个OpenGL的C语言库,它对渲染物体提供了一些接口

GLAD的作用是需要管理OpenGL的函数指针,因此在使用任何OpenGl函数之前,都需要先初始化GLAD

Shader的翻译是由GPU来完成的

计算机上的GPU就决定了它能支持OpenGL的最高版本

目前绝大多数的GPU来说,对OpenGL支持的版本都超过了3.3,那么对应的GLSL也就超过了GLSL-330版本


3.5_对绘制三角形实验进行讲解

提纲

第一个实验:绘制一个三角形

程序流程

在窗口中绘制一个三角形

初始化GLFW和GLAD

1.用GLFW自带的函数进行GLFW的初始化

2.指定GLFW的主次版本号

5.使用的OpenGL的核心模式

6.如果使用的是Mac OS X系统,需加上这行

7.指定是否可以改变窗口大小,如果不加这一行,默认是可以改变窗口大小的

创建窗口

标红的这一行

当指定了窗口的宽和高之后,第三个参数表示窗口的标题

后面两个参数分别表示是否使用全屏模式和共享上下文的窗口,这里可以暂时不用管,可以直接设置为null

创建窗口之后,还可以判断当前窗口是否创建成功

最后将窗口的上下文设置为当前线程的主上下文

上下文的概念

由于OpenGL本身就是一个大的状态机,我们将OpenGL的状态就称为OpenGL的上下文,因此,我们设置过后,就是用当前的上下文来完成渲染

初始化GLAD部分

由于GLAD是用来管理OpenGL的函数的指针的,所以在调用任何OpenGL的函数之前,我们必须要初始化GLAD

初始化的最后一部就是指定当前的视口尺寸

前面两个参数是左下角的位置,后面两个位置是渲染窗口的宽高

很显然,我们现在让视口和窗口相同大小

到这里为止,初始化的部分就全都结束了

初始化过后,我们需要给出三角形的顶点数据,并且对数据做出一些处理

包括生成和绑定VAO,VBO和属性设置,最后将其解绑

由于我们绘制的是一个三角形,因此我们的顶点数据是由三个点组成

这里的顶点数据是在规范化的空间中的,也就是说X,Y,Z轴的坐标都要映射到-1到1之间

我们有了顶点数据,接下来就将其发送到GPU中去处理

这里我们生成了一个顶点缓冲对象VBO,并且将其绑定到顶点缓冲对象上

使用这个顶点缓冲对象的好处,是我们不用将顶点数据一个一个的发送到GPU,而是可以借助VBO一次性发送一大批的数据过去,然后使用glBufferData将顶点数据绑定到当前的缓冲上

GL_STATIC_DRAW代表我们的三角形位置数据不会被改变

在这里,我们还生成了一个顶点数组对象VAO

使用VAO的原因是:

1.首先我们使用的是核心模式,它要求我们需要使用VAO;

2.其次使用VAO的好处在于,我们在渲染的时候,只需要调用一次VAO就可以了,之前的数据都对应存在了VAO中,不在调用VBO,那么VAO的生成过程也跟VBO一样,需要先生成,再绑定,等到这些操作都完毕了,我们就可以将VAO,VBO进行解绑

发送到GPU之后,我们还需要告诉OpenGL,我们如何解释这些顶点数据,因此我们用这个函数告诉OpenGL我们如何解释这些顶点数据

第一个参数0:表示是我们后面会用到的顶点着色器的位置值

第二个参数3:表示顶点属性是一个三分量的向量

第三个参数GL_FLOAT:表示顶点属性的类型

第四个参数GL_FALSE:表示我们是否希望数据被标准化,就是映射到0-1之间

第五个参数3*sizeof(float):叫"步长",表示连续顶点属性之间的间隔,因为我们这里只有顶点的位置,所以我们将步长设置成为这个,表示下一组的数据在3个float变量之后

最后一个(void*)0: 表示数据的偏移量,这里我们的位置属性是在数组的开头,因此这里是0,并且由于参数类型的限制,我们需要将其进行强制的类型转换

而下面Enable函数表示我们要开启0这个通道,因为默认状态是关闭的,因此我们需要在这里开启一下

等到属性设置指针完成之后,我们就要解绑VAO和VBO

为什么要解绑VAO和VBO?

1.是因为我们需要防止之后在继续绑定VAO的时候,会影响到当前的VAO

2.是为了使代码更加灵活规范,我们要养成一个习惯,就是在需要渲染的时候,就绑VAO然后再来绘制

我们已经通过VAO,VBO将顶点数据储存在显卡的GPU上,接下来,我们就会创建顶点和片段着色器,来真正的处理这些数据,这里我们会给出着色器的源码,然后生成并编译着色器,最后将顶点和片段着色器链接到一个着色器程序,在之后的渲染流程中,我们就会使用这个着色器程序,使用之后,再将这个着色器删除

顶点和片段着色器的源码

这个是用GLSL语言来编写的

第一行表示的是使用3.3的核心模式

第二行就是之前所说的位置值

main函数之中的部分就是将我们之前的顶点数据直接输出到GLSL已经定义好的一个内建变量GLvision中,这个就是顶点着色器的输出

也就是说,其实在这个程序中,我们的顶点着色器里其实什么也没有做,只是将顶点的位置作为顶点着色器的输出而已

接下来的片段着色器就要做一些事情了,前面两行是类似的,而Out表示输出变量,就像之前的In表示输入变量一样,然后我们这里的四分向量,就是我们之前看到的三角形红色的来源,它是一个四分量的表示RGB的值,我们也可以将其更改,那么输出的三角形的颜色就会发生变化

有了顶点和片段着色器的源码,我们还要生成可编译着色器,这里我们先生成了顶点着色器,并且附加上了之前的源码,将其进行编译,然后我们这里对其进行检测,看是否编译成功,如果编译不成功,会打印出相应的错误信息,同样片段着色器也是一样的

最后我们将顶点和片段着色器连接到一个着色器程序中,这样我们在渲染的时候,只需要调用一个着色器程序就可以了,同样这里我们也需要检测一下是否链接成功

之后,我们就删除顶点和片段着色器,因为在后面渲染的时候,我们只需要用链接好的着色器程序即可,就不在需要顶点和片段着色器了

进入渲染阶段

当窗口没有关闭的时候,其实一直正在进行渲染,也就是在一个循环中

1.首选,清空颜色缓冲,我们这里用一个黑色的背景色来清空屏幕颜色缓冲,当然也可以使用别的颜色

2.使用已经链接好了的着色器程序和VAO来绘制这个三角形,绘制三角形只要一句话,就是这里的glDraw_Arrays,当然还有其它的绘制方式,我们这里采用这种绘制方式

第一个参数表示我们要绘制三角形

第二个参数表示顶点数组的起始索引值

第三个参数表示我们要绘制的顶点数量

绘制结束以后就可以解除绑定

最后我们会交换一下缓冲,我们通常采用的是一个双缓冲的做法,前置缓冲保存输出着的图像,而渲染指令其实都在后置缓冲和李平缓冲中进行,当指令执行完毕之后,我们再来交换前后缓冲,最后我们还会检测,是否还会出发一些其它的回调函数

当我们的窗口关闭之后,我们还会进行一些善后工作,这里包括删除我们之前创建的VAO和VBO,以及调用GLFW的函数来清理所有的资源并正确退出程序,那么整个绘制三角形的程序就到此为止

梳理过程

1.先初始化OpenGL

2.对数据进行处理,通过VAO和VBO将其发送到GPU中,并且设置属性指针,告诉GPU我们会如何解释这些数据

3.然后在着色器中,通过顶点和片段着色器对数据进行处理

4.最后进行渲染,渲染之后还行进行善后工作

这样一来,一个三角形的绘制就成功了

程序演示

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值