Shader笔记——2.渲染管线

渲染流水线基础

直接对GPU进行访问是一件非常麻烦的事,因为开发者要自己去面对各种寄存器及显存等,所以有了OpenGL、DirectX等图形编程接口,这些图形接口在显卡硬件基础上实现一层抽象,架起上层的应用程序和下层GPU之间沟通的桥梁

  • 应用程序调用图形编程接口将渲染所需的数据加载至显存中的特定区域

  • 应用程序调用图形接口对将要渲染的网格进行渲染状态的设置SetPass,发出渲染调用Draw Call,图形接口将渲染命令传递给显卡驱动,被显卡驱动翻译成GPU可以理解的代码进行真正的绘制

渲染流水线

渲染流程分为三个阶段,应用阶段、几何阶段、光栅化阶段

应用阶段

第一阶段,应用阶段由应用程序主要负责,主要分三个小任务:
加载渲染数据到显存设置渲染状态SetPass调用Draw Call

1.加载渲染数据到显存

应用程序首先要调用OpenGL、Direct3D等图形接口将渲染所需数据如顶点数据、纹理数据等加载到显卡的显存VRAM

在应用程序在加载数据到显存VRAM之前,首先要将数据从硬盘HDD中加载到系统内存RAM,再由内存加载至显存中,当场景数据成功加载至VRAM之后,RAM中的部分数据就可以移除了,因为因为从硬盘加载数据到内存也是件非常耗时的操作,所以那些之后工作仍需要进行一些如碰撞检测的网格之类的数据暂不进行移除

2.设置渲染状态SetPass

渲染状态Render State,定义场景中的网格应该被怎么渲染,例如使用什么纹理、Shader来进行渲染,在Unity3D、3DMax等其他3D软件中渲染状态指的就是材质球Material,在游戏运行时资源材质的变更伴随着着色器的变更,就需要重新构建渲染状态,设置渲染状态的处理称之为SetPass

当渲染状态设置后,CPU就可以发出一个渲染调用的命令来命令GPU按照设置进行渲染,这个命令就是Draw Call

CPU与GPU之间有个叫做命令缓冲区Command Buffer的命令队列,使CPU与GPU可以并行工作,CPU可以向其中依次加入Draw Call渲染命令或者改变渲染状态命令

  • 调用大量的较小Draw Call渲染命令会造成CPU的性能瓶颈,CPU会花费大量的时间在准备Draw Call的工作上,所以我们一般要尽量的减少Draw Call,最常见的处理方法就是批处理,在Unity3D中有动态批处理Dynamic Batching和静态批处理Static Batching
  • 改变渲染状态命令SetPass在GPU中执行起来也是比较耗时的操作,如果能合理管理渲染状态,避免多余的状态切换,减少SetPass次数,可以提升图形程序性能

3.调用Draw Call

Draw Call就是由CPU向GPU发出的一个渲染调用命令,Draw Call命令指定一个需要被渲染的渲染图元列表,GPU收到Draw Call就会将Draw Call指定的由CPU传入的渲染图元数据结合CPU设置的渲染状态进入GPU流水线进行渲染计算

GPUAssemblyLine

几何阶段

第二阶段,几何阶段负责对Draw Call指定的图元进行处理,完成顶点坐标变换到屏幕空间,最终输出屏幕空间的二维顶点坐标每个顶点对应的深度值、着色等相关信息,将其传递给下一阶段

光栅化阶段

第三阶段,光栅化阶段完成对几何阶段传递的顶点屏幕坐标及对应深度值等信息进行逐像素处理最后生成屏幕上的像素,渲染出最终的图像

GPU流水线

接收到Draw Call后,GPU就会经过几何阶段、光栅化阶段的流水线操作,最终将图元渲染到屏幕上,这个过程称之为GPU流水线

GPU几何阶段处理

顶点着色器Vertex Shader

vertexshader

顶点着色器是几何阶段的第一步,主要任务是对指定图元的顶点数据进行坐标变换逐顶点光照,以及为后序阶段提供所需的数据,顶点着色器的处理单位是顶点,输入的每个顶点都会调用一次顶点着色器,因为顶点着色器并不创建或者销毁顶点,也无法获得顶点之间的关系,所以GPU可以快速的并行处理每一个顶点

NormalizedDeviceCoordinates

坐标变换,无论在顶点着色器中怎么改变顶点的位置,一个最基本的任务是将顶点坐标从模型空间转换到齐次剪裁空间变换到齐次剪裁空间后再由硬件做做透视除法得到归一化的设备坐标(Normalized Device Coordinates NDC)

裁剪Clipping

clipping
裁剪步骤我们无法控制,为硬件上的固定操作,在单位立方体之外的图元会被舍弃,在单位立方体之内的图元会被保留,与单位立方体相交的图元会被剪裁,新的顶点生成,外部的顶点舍弃

屏幕投射Screen Mapping

screenmapping
屏幕投射的任务是将每个图元的x、y坐标转换到屏幕坐标系Screen Coordinates,屏幕坐标系与我们用于显示画面的分辨率有关(在屏幕投射阶段并不会对原单位立方体的z轴坐标进行任何处理,屏幕坐标系与原单位立方体的z轴一起构成了窗口坐标系Window Coordinates,与x、y进行屏幕投射后的值一起传递到光栅化阶段)

GPU几何阶段最终会输出屏幕空间的二维顶点坐标每个顶点对应的深度值、着色等相关信息

GPU光栅化阶段

三角形设置Triangle Setup

三角形设置是光栅化阶段的第一步,光栅化阶段的输入是屏幕坐标系下的顶点坐标深度值(单位立方体下的Z轴坐标)、法线方向、视角方向等其他相关信息,光栅化阶段的主要目标是计算每个图元覆盖了哪些像素以及计算这些像素的颜色
三角形设置这一步从上一阶段传递过来的三角网格的顶点出发,计算每条边上的像素坐标,来得到整个三角网格对像素的覆盖信息。

三角形遍历Triangle Traversal

TriangleTraversal
三角形遍历步骤根据上一步的计算结果判断一个三角网格覆盖了那些像素,并使用三角网格三个顶点的信息对整个覆盖区域的像素进行插值,这一步的输出就是一个片元序列,这些片元系列包括了诸多信息如顶点信息、屏幕坐标、深度信息等,用于计算每个像素的最终颜色

片元着色器Fragment Shader

FragmentShader
片元着色器的输入时上一阶段对顶点信息的插值结果,输出则是一个或者多个颜色值,此阶段完成众多渲染技术,例如纹理采样等

逐片元操作Per-Fragment Operations

per-fragOperations
逐片元操作时光栅化阶段的最后一步,这个阶段首先解决每个片元的可见性问题,进行一系列的模板测试、深度测试等,通过测试的片元在可以和颜色缓冲区的像素颜色进行混合,最后结果再写入颜色缓冲区,最后显示在我们屏幕上的就是颜色缓冲区中的颜色

REF

书籍:
Unity Shader入门

博客:
https://dev.gameres.com/program/visual/3d/renderstate.htm

原文地址:https://www.cnblogs.com/sylvan/p/9501881.html