计算机图形学学习(3)—— 基础篇:可编程渲染管线
3.1 渲染管线的发展历程
-
图形编程的发展
- 早期的图形编程:调用硬件供货商提供的函数库(用来绘制图元及其属性的函数库不存在)
- 图形标准的产生:硬件供货商提供标准图形数据库,使得能够在设备无关的方式下生成图像
- GKS(Graphical Kernel System, 图形核心系统)
- PHISS(Programmer's Hierarchical Interactive Graphics System, 程序员层次式交互图形系统)
- OpenGL
- 固定管线
- 图形API提供了一个对硬件进行操作的标准接口;从内部实现上来说,API对程序员提出的各种绘制图元或属性的请求都采用固定的方式来处理
- 这种内部实现方式通常称为固定功能渲染流水线
- 固定到可编程
- 钩函数hooks的出现:突破固定功能流水线的限制,使用可编程着色器修改流水线中某些特定步骤的行为
- 可编程流水线
-
基于GPU的可编程渲染管线
-
功能:决定在给定虚拟相机、三维物体、光源、照明模式,以及纹理等诸多条件情况下生成或绘制一幅二维图像的过程
-
流水线中的三个概念阶段
- 应用阶段:将需要在屏幕上显示出来绘制的几何体,也就是绘制图元,比如点、线、矩形等,输入到绘制管线的下一个阶段。具体包括图元的顶点数据、摄像机位置、光照纹理等参数。
- 集合阶段:将顶点数据进行屏幕映射。需要:
- 将各个图元放入到世界坐标系中,也就是进行模型变换
- 根据光照纹理等计算顶点处材质的光照着色效果
- 根据摄像机的位置、取景范围进行观察变换和裁剪
- 最后进行屏幕映射,也就是把三维模型转换到屏幕坐标系中
- 光栅化阶段:给每个像素正确配色,以便绘制整幅图形
-
3.2 可编程渲染管线
-
GPU渲染管线工作过程
-
几何阶段
- 顶点着色器:
- 模型变换:建模坐标系——>世界坐标系,将所有模型移入一个坐标系中
- 视图变换:建立观察坐标系
- 顶点着色:确定顶点上材质上的光照效果
- 几何、曲面细分着色器
- 裁剪:规范化的观察空间
- 屏幕映射:转换为二维数据
- 顶点着色器:
-
光栅化阶段
- 三角形设置
- 三角形遍历
- 片元着色器
- 片元操作
- 片元——>模板测试——>深度测试——>颜色混合——>帧缓存
- 片元——>模板测试——>深度测试——>颜色混合——>帧缓存
3.3 着色器编程
-
着色器语言 Shading Language
-
GLSL(OpenGL Shading Language)OpenGL的着色器语言
-
顶点着色器Vertex Shader、几何着色器Geometry Shader、曲面细分着色器Tessellation Shader、片元着色器Fragment Shader
-
在OpenGL中使用着色器的流程:
- 创建着色器对象
- 源码关联到着色器对象
- 编译着色器
- 创建一个程序对象
- 将着色器对象关联到程序对象
-
与OpenGL的通信
- OpenGL通过一组uniform全局变量将所有的数据传递到着色器
-
数据类型
-
标量:整数(int)、无符号整型(uint)、布尔类型(bool)及浮点型(float)
-
矢量:一个矢量可以有2、3、4个分量
vec4 a=vec4(1.0,2.0,3.0,4.0);
-
矩阵
mat2 m mat2(1.0,2.0,3.0,4.0);
-
结构和数组:结构体的成员或者数组的基类型可以为任意的数据类型
//lightsource为光源
struct lightsource{
vec3 color; //颜色
vec3 position; //位置
}
lightsource spotlight[10]; //10个光源
-
-
控制结构
- 循环结构:for、while和do-while
- 选择循环:if-then、if-then-else,GLGL3.0版本引入了switch结构
- 注意:goto语句和标签是不允许使用的
-
-
EBO、VBO和VAO
- EBO
- Element Buffer Object,也叫IBO:Index Buffer Object,索引缓冲区对象
- 主要用来存储顶点的索引信息
- VBO
- Vertex Buffer Object,顶点缓冲区对象,主要用来存储顶点的各种信息
- 好处:模型的顶点信息放进VBO,这样每次画模型时,数据不用再从CPU的势力范围内存里取,而是直接从GPU的显存里取,从而提高效率
- VAO
- Vertex Array Object,顶点数组对象
- VAO是一个保存了所有顶点数据属性的状态结合,它存储了顶点数据的格式以及顶点数据所需的VBO对象的引用
- EBO
Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it.