高质量实时渲染 Recap of CG Basics
Recap of CG Basics
先放上games202的自己的手写笔记,非常感谢闫令琪老师的课程
Graphics (Hardware) Pipeline

渲染管线的整个过程
- 得到应用发来的3维空间的顶点位置和拓扑信息
- 根据相机,对顶点位置进行MVP变换(model、view、prohection transforms),并投影到屏幕空间
- 投影不改变顶点的拓扑关系,所以得到了屏幕上的一系列三角形
- 再将三角形进行光栅化操作,转换为一个个 Fragement(一堆像素),测试(深度等)
- 对 Fragement 进行着色
- 输出
可抽象为:
- 顶点处理:变换
- 三角形处理:连接
- 光栅化:深度、三角形设置、三角形遍历等
- 片元处理:片元着色器、逐片元操作
- 帧缓存操作
《Unity Shader入门精要》中的渲染管线
应用阶段:
- 硬盘>内存(RAM)>显存
- cpu调用内存,设置渲染状态(draw call)给GPU
几何阶段
- 顶点着色器:MVP变换 and 顶点着色(高洛德着色)
- 裁剪:去除视野外的物体,不可编程(硬件固定操作)
- 屏幕映射(有些资料归类于光栅化操作):将图元坐标转换到屏幕坐标系(Z轴作为深度信息作后续计算)
光栅化阶段
- 设置三角形:将传入的顶点信息转变为三角形信息
- 遍历三角形:即检查每个像素是否被三角形网格所覆盖
- 片元着色器:完成多种的渲染技术(纹理采样等)
- 逐片元操作:测试阶段(模板测试、深度测试)、混合阶段(Alpha混合)。逐片元操作阶段是高度可配置的
OpenGL

what?
opengl是一系列在cpu端上负责调动gpu的api,也就是在CPU端写的,我们可以知道opengl用什么语言写是没有关系。
OpenGL 是操作 CPU 去控制 GPU 管线的工具,但我们更关心的是GPU怎么去执行,而不是CPU如何让GPU去执行。
特点:
- 跨平台
缺陷:
- 版本过于碎片化
- c风格语言,不是很好用
- 以前不好debug,现在方便很多

以画油画类比Opengl操作流

摆好物体和模型
我们需要告诉GPU我们要用什么样的模型
通过VBO我们可以把需要渲染的图元的顶点信息,直接上传存储在GPU的显存中。通常类似于 .obj 文件是一堆顶点坐标、法线坐标、三角形关系。存在 GPU 的一块特定缓存区,作为 VBO(Vertex buffer object)
模型该如何摆放
OpenGL 提供了很多函数,可以直接得到各种需要用的转换矩阵

架好画架
接着设置帧缓存区,再设置摄像机的方位
view transformation(视图变换)
首先放置相机,视图变换就是相机选用的是透视投影还是正交投影,在101中仍是我们自己去推导和写的矩阵,而opengl的api简化了摄像机的视图变化,让一切变得简单了许多.
我们只需要规定相机的一些属性就可以了,比如说:
fov(可视角度),aspect(长宽比),zNear(近平面),zFar(远平面).
creat / use a framebuffer(建立画架)
要建立opengl的画架,就是framebuffer,为了要使用一个画架,我们一定要在上面贴一块画布的。

申明对此帧缓存进行渲染
在画架上贴上一块画布
frambuffer对场景渲染一次,可以用渲染出好几张不同性质的纹理,(也解释了第5点画好一张后换张画布可以继续画),最后由fragment shader 告诉你要写到哪一个纹理上去。

根据 顶点 Shader 进行关于顶点的处理

根据 片元 Shader 对 片元进行处理
在画布上绘画
我们要把场景给画在画布上,那么无论如何我们肯定要进行shading,那么:
顶点着色的话,每个顶点的要在顶点着色器操作,首先要进行mvp的投影,之后我们将需要做插值的值进行插值得到结果后,再将结果传递到像素着色器。
那么像素着色器得到的输入就是顶点着色器的输出在一个顶点上的属性,接着就会被插值到任何一个像素上的属性.
opengl会将三角形打成一堆像素,然后对每个像素着色。
总结
Opengl就是告诉GPU在每一趟渲染中需要:
- -指定物体,相机,mvp矩阵等
- -指定Framebuffer和输/出纹理
- -指定顶点、fragment着色器
- -(当在gpu里确定了一切)渲染
OpenGL Shading Language(GLSL)

Shading 语言最早集成在 GPU 上,需要用 Shading 汇编语言,使用非常困难。
后来有斯坦福的实时渲染语言
再后来有 NVIDIA 提供的 Cg 语言
再后来有 DirectX 的 HLSL 语言和 OpenGL 的 GLSL 语言

Shader 的使用过程,写shader可以近似于在cpu上编程,二者十分相似。

Shader 的初始化代码,负责载入和编译 shader

Shader 的链接代码

Phong 渲染模型的顶点 Shader 代码
- attribute(顶点属性关键字只在vertex shader出现)
- vec3(3维向量)
- aVertexPosition(获取顶点位置)
- vec4(aVertexPosition,1.0)定于一个4维向量只要3维向量后面跟一个数
- varying(需要传递到fragment shader)
- high(定义计算精度)
- uniform(全局变量)


Phong 渲染模型的片元 Shader 代码
color =pow(texture2D(uSampler,vTextureCoord).rgb,vec3(2.2)(伽马矫正))

渲染管线由于在硬件层面是封闭的,导致调试比较困难
早年debug只有NVIDA Nsight能调试glsl,hlsl只能在软件上运行来debug
Now
- Nsight Graphics,跨平台,但只支持NVIDA。
- RenderDoc,对显卡品牌没要求。
RGB 调试法

当然,还有类似于 printf 一样的简单粗暴调试手段,即输出为一幅图,再用 Color Pick 工具查看对应像素的 RGB 值
The Rendering Equation

Rendering Equation 是一个正确的用来描述光线传播的等式,讲的是:
看到的任何一个点p反射到眼中的 radiance = 这个点p本身发出的radiance + 其他打到这个点的radiance * brdf * cos


指brdf时候可能指原始brdf,也可能指cosine-weighted brdf
Visibility是在实时渲染中我们需要考虑 到物体会不会被光源找到,比如在一点p往一方向去看,我们知道这一方向有光源发出光线的,但是光线能否打到p上,因此 引入Visibility 的概念。
real time rendering会显式的考虑visibility,他与原先的理解是等价的,之所以这么理解是为了能够更好理解环境光照,要比不写visilibity项更加直观.
环境光照
任何一方向过来的光的强度由一张图来决定,可以一个是cube box也可以是定义在球上的一张图,这两种表示都有不同的问题,在本课中会介绍一种新的表示,以八面体来表示.
此时只需要考虑说,从任何一个shading point往那个方向去,看这个visility是否可见,等于将实际上的光源和能否看到他,把这两项拆开考虑了,就很方便.
GAMES 202 课堂答疑
1.问:怎么定义哪些点连接成三角形? 答:比如obj格式是先编号一系列点,再定义面,每个面都带着三个点的编号的下标。
2.问:有无适合全局光照的管线?答:无,但光线追踪渲染管线很完善。
3.问:纹理坐标怎么参数化的?答:可以理解成物体外面有个盒子,把盒子挤压到物体上,盒子上的uv是好确定的。
4.问:几个光源就需要几个shadowmap吗?光源也需要深度测试吗?答:是
5.问:opengl支持optix吗?答:可以,但不要指望shader能调用一个光线一个场景怎么运作。
6.问:纹理是不是是个buffer?答:opengl里两者定义不一样,但也可以这样理解,都是显存里的一块缓存区域。
7.问:一个pass就是一个frambuffer渲染一次吗?答:一个场景渲染一次
8.问:不同shader里定义里的变量会通用吗?答:不是



浙公网安备 33010602011771号