1.1 渲染流水线

news2024/11/24 18:36:33

整体流程

 

应用阶段:粗粒度剔除、进行渲染设置、准备基本数据、输出到几何阶段

几何阶段:顶点着色器、曲面细分、几何着色器、顶点裁剪、屏幕映射

光栅化阶段:三角形(点/线)设置、三角形(点/线)遍历、片段着色器

逐片元操作:裁剪测试、透明度测试、深度测试、模板测试、混合

后处理

CPU阶段

①应用阶段:

准备基本场景数据->加速算法、粗颗粒度剔除->设置渲染状态、准备渲染参数->调用drawcall、输出渲染图元到显存

GPU阶段

②几何阶段:

顶点着色器->几何着色器->曲面细分着色器->投影->裁剪->屏幕映射

③光栅化阶段

三角形设置->三角形遍历->片段着色器

④逐片元操作

裁剪测试、透明度测试、模板测试、深度测试、像素着色、颜色混合、目标缓冲区

⑤后处理

-------------------------------CPU阶段---------------------------------

应用阶段

这一阶段开发者主要有3个任务:

①准备好场景数据,例如摄像机的位置、视锥体场景中包含了哪些模型、使用了哪些光源等等;

②为了提高渲染性能,需要进行粗粒度剔除(culling),把看不见的物体剔除处理,这样就不需要移交给几何阶段进行处理。

③设置好每个模型的渲染状态。这些渲染状态包括但不限于它们使用的材质(漫反射颜色、高光反射颜色)、使用的纹理、shader等。

这一阶段最重要的输出是渲染所需的几何信息,即渲染图元(rendering primitives)。简单说就是把渲染图元(点、线、三角面)传递给下一个阶段——几何阶段。

直观点就是说开发者自己在游戏引擎中进行的各种操作,摆模型、相机位置、赋值材质等等。

准备基本场景数据->加速算法、粗颗粒度剔除->设置渲染状态、准备渲染参数->调用drawcall、输出渲染图元到显存

-------------------------------------详细步骤参考《Unity Shader入门精要》------------------------------------

CPU和GPU之间的通信

渲染流水线的起点是CPU,即应用阶段。应用阶段大致可以分为下面3个阶段:

(1)把数据加载到显存中

(2)设置渲染状态

(3)调用Draw Call

把数据加载到显存中

渲染所需要的数据都要从硬盘(Hard Disk Drive ,HHD)中加载到系统内存(Random Access Memory,RAM)中。然后网格和纹理等数据又被加载到显卡的存储空间——显存(Video Rnadom Access Memory,VRAM)中。

硬盘(HHD)->系统内存(RAM)->显存(VRAM)

除上图中展示的纹理及网格外还有:顶点位置信息、发现方向、定点颜色、纹理坐标等等。

当把数据加载到显存后,RAM中的数据就可以移除了。但有些数据后续仍需访问它们(例如,CPU可以访问网格数据来进行碰撞检测),那么就不需要移除,因为从硬盘加载到RAM的过程是十分耗时的。

设置渲染状态

顾名思义,设置一些渲染相关的参数。例如,使用哪个顶点着色器(Vertex Shader)/片元着色器(Fragment Shader)、光源属性、材质等。

准备好上述所有工作后(数据准备好),CPU就可以调用一个渲染命令来告诉GPU开始渲染,这个渲染命令就是DrawCall

调用DrawCall

DrawCall实际上就是一个命令,它的发起方是CPU,接收方是GPU。这个命令仅仅会指向一个需要被渲染的图元列表,而不会在包含任何材质信息(这是因为我们已经在上一阶段中完成了)

中间的具体渲染流程,则是GPU流水线里的东西。

-------------------------------GPU阶段---------------------------------

几何阶段和光栅化阶段,开发者无法拥有绝对的控制权,其实现载体是GPU。不过会开放部分权限给开发者,供其操作。

完全可编程控制:顶点着色器、曲面细分着色器(Tessellation Shader)、几何着色器(Geometry Shader)、片元着色器(Fragment Shader)

可配置不可编程:裁剪(Clipping)、逐片元操作(Per-Fragment Operations)

GPU固定实现,开发者无任何控制权:屏幕映射(Screen Mapping)、三角形设置(Triangle Setup)、三角形遍历(Triangle Traversal)

顶点着色器(Vertex Shader):它通常用于实现顶点空间变换、顶点着色等功能。

曲面细分着色器(Tessellation Shader):是一个可选着色器,用于细分图元,例如制作雪地会用到,平滑模型也会用到。

几何着色器(Geometry Shader):可选着色器,它可以被用于执行逐图元(Per-Primitive)的着色操作,或者被用于产生更多的图元。

裁剪(Clipping):这一阶段的目的是将那些不在摄像机视野内的顶点裁剪掉,并剔除某些三角图元的面片。例如,可以使用自定义裁剪平面来配置裁剪区域,也可以通过指令控制裁剪三角图元的正面还是背面,CutOff功能就用了此步骤。

屏幕映射(Screen Mapping):它负责把每个图元的坐标转换到屏幕坐标系中。

三角形设置(Triangle Setup)、三角形遍历(Triangle Traversal):将顶点拼成三角形,对三角形进行拼接成片。

逐片元操作(Per-Fragment Operations):负责更重要的操作,例如修改颜色、深度缓冲、颜色混合等。

几何阶段

几何阶段负责和每个渲染图元打交道,进行逐顶点、逐多边形的操作。几何阶段一个重要的任务就是把顶点坐标转换到屏幕空间中,再交给光栅器进行处理。

通过对输入的渲染图元进行多步处理后,这一阶段会将输出屏幕空间的二维顶点坐标、每个顶点对应的深度值、着色等相关信息,并传递给下一阶段。

换句话说,这一阶段就是决定需要绘制的图元是什么、怎样绘制它们,在哪里绘制它们。

顶点着色器(Vertex Shader)

输入来自于CPU。顶点着色器本身不可以创建或者销毁任何顶点,且无法得到顶点与顶点之间的关系。例如无法得知两个顶点是否属于同一个三角网格。正因这样的相互独立性,GPU可以利用本身的特性并行化处理每个顶点,这意味着这一阶段的处理速度会很快。

主要工作:坐标变换和逐顶点光照。

次要功能:还可以输出后续阶段所需要的数据。

坐标变换

对顶点的坐标(即位置)进行某种变换。顶点着色器可以在这一步改变顶点位置,顶点动画中非常有用。例如,改变顶点位置模拟水平面、布料等。

不论如何改变顶点位置,一个最基本的顶点着色器必须完成一个工作是:把顶点坐标从模型空间转换到齐次裁剪空间。例如代码中的

o.pos = mul(UNITY_MVP,v.position);

此代码就是将顶点坐标转换到齐次裁剪坐标系下,接着通常再由硬件做透视除法,最终得到归一化的设备坐标(Normalized Device Coordinates,NDC)

裁剪(Clipping)

将不在摄像机视野范的物体剔除。

一个图元与相机视野的关系有3种:完全在视野内、部分在视野内、完全在视野外。

完全在是业内的图元就继续传给下一个流水线阶段,完全在视野外的则不会继续向下传递。而那些部分再是业内的图元则需要进行处理,这就是裁剪。

屏幕映射(Screen Mapping)

这一输入的坐标仍然是三维坐标系下的坐标(范围在单位立方体内)。

主要任务:把每个图元的x和y轴坐标转换到屏幕坐标系(Screen Coordinates)下。

屏幕坐标系是一个二维坐标系。

OpenGL与DirectX坐标系有所区别。

屏幕映射只会对x、y轴进行转换,z轴则不作任何处理。屏幕坐标系和z坐标一起构成了一个新的坐标系,叫做窗口坐标系(Window Coordinates)。

这些值会一起被传递到光栅化阶段。

光栅化阶段

上一阶段输出的信息是屏幕空间坐标系下的顶点位置以及和它们相关的额外信息,入深度值(z坐标)、法线方向、视角方向等。

主要目标:①计算每个图元覆盖了哪些像素 ②为这些像素计算它们的颜色

三角形设置(Triangle Setup)

这一阶段计算光栅化一个三角网格所需的信息。

上个阶段输出的饿都是三角形网格的顶点,即我们得到的是三角形网格每条边的两个端点。如果要得到整个三角形网格对像素的覆盖情况,就需要计算每条边上的像素坐标。为了能够计算边界像素的坐标信息,就需要的倒三角形边界的表示方式。这个过程就叫做三角形设置。

简单说就是将单独的顶点连接成三角面。

三角形遍历(Triangle Traversal)

检查每个像素是否被一个三角网格所覆盖。如果被覆盖的话,就会生成一个片元(fragment)。这样一个找到那些像素被三角网格覆盖的过程就是三角形遍历,这个阶段也被成为扫描变换(Scan Conversion)。

这一步输出就是得到一个片元序列。需要注意的是,一个片元并不是真正意义上的像素,而是包含了很多状态的集合,这些状态用于计算每个像素的最终颜色。这些状态包括了(但不限于)它的屏幕坐标、深度信息,以及其他集合阶段输出的顶点信息,例如法线、纹理坐标等。

片元着色器(Fragment Shader)

在DirectX中被称为像素着色器(Pixel Shader),但片元着色器是一个更合适的名字,因为此时片元并不是一个真正意义上的像素。

片元着色器的输入是上一个阶段对顶点信息插值得到的结果,具体来说,是根据那些从顶点着色器中输入的数据差值得到的。而它的输出是一个或者多个颜色值。

主要任务:纹理采样。

片元着色器进行纹理采样,通常会在顶点着色器阶段输出每个顶点对应的纹理坐标,然后经过光栅化阶段对三角形网格的3个顶点对应的纹理坐标进行插值,就可以得到覆盖片元的纹理坐标了。

虽然片元着色器可以完成很多重要效果,但它局限在于,它仅可以影响单个片元。也就是说,当执行片元着色器是,它不可以将自己的任何结果直接发给它的邻居们。有一个情况例外,就是片元着色器可以访问导数信息(gradient,或者说说是derivative)。

逐片元操作

渲染流水线最后一步,逐片元操作(PerFragment Operations)是OpenGL中的说法,在DirectX中叫做输出合并阶段(Output-Merger)。

主要任务:

①决定每个片元的可见性。这涉及了很多测试工作,例如深度测试、模板测试等。

②如果一个片元通过了所有测试,就需要把这个片元的颜色值和已经存储在颜色缓冲区中的颜色进行合并,或者说是混合。

透明度测试在模板测试前面。

一个片元只有通过了所有测试才能和颜色缓冲区进行合并。否则就会被舍弃掉,之前为了产生这个片元做的所有工作都是白费的。

模板测试(Stencil Test)

模板测试相关的是模板缓冲(Stencil Buffer)。实际上模板缓冲和颜色缓冲、深度缓冲几乎是一类东西。

如果开启了模板测试,GPU会首先读取(使用读取掩码)模板缓冲区中该片元位置的模板值,然后将该值和读取(使用读取掩码)到的参考值(reference value)进行比较,这个比较函数可以是由开发者指定的,例如小于时舍弃该片元。如果这个片元没有通过这个测试,该片元就会被舍弃。不管一个片元有没有通过模板测试,我们都可以根据模板测试和下面的深度测试来修改模板缓冲区,这个操作也是由开发者指定的。开发者可以设置不同结果下的修改操作。例如,在失败时模板缓冲区保持不变,通过时将模板缓冲区对应位置的值加一等。

模板测试通常用于限制渲染区域。另外模板测试还有一些高级的用,入渲染阴影、轮廓渲染等。

深度测试(Depth Test)

GPU会把该片元的深度值和已经存在与深度缓冲区中的深度值进行比较。这个比较函数也是可由开发者设置的,例如小于时舍弃该片元,或者大于等于时舍弃该片元。通常这个函数是小于等于的关系,即如果这个片元深度值大于等于当前深度缓冲区中的值,那么就会舍弃他。因为我们总想只显示离摄像机近的物体,而那些被其他物体遮挡的就不需要出现在屏幕上。

和模板测试有些不同的是,如果一个片元没有通过深度测试,他就没有权利更改深度缓冲区中的值。如果它通过了测试,开发者还可以指定是否要用这个片元的深度值覆盖掉原有的深度值,这是通过开启/关闭深度写入来做到的。透明效果和深度测试以及深度写入关系十分密切。

混合(Blend)

解决每次渲染时颜色缓冲中的颜色与新渲染进来的颜色取舍问题。

对于不透明物体,可以关闭混合(Blend)操作。这样片元着色器计算得到的颜色值就会直接覆盖掉颜色缓冲区中的像素值。

对于半透明物体,就需要开启混合(Blend)操作。

开启混合后,就会使用一个混合函数来进行混合操作。这个混合函数和透明通道息息相关,例如根据透明通道的值进行想加、相减、相乘等。

上面给出的测试顺序并不是唯一的,而且虽然从逻辑上来说这些测试试在片元着色器之后进行的,但对于大多数GPU来说,他们会尽可能在执行片元着色器之前就进行这些测试。防止在片元着色器器将颜色计算完毕后,发现这些片元没有通过测试被舍弃,造成计算成本的浪费。

Unity给出的渲染流水中Early-Z技术,可以将深度测试提前执行。

提前测试出现的问题:如果将这些测试提前的话,其检验结果可能会与片元着色器中的一些操作冲突。例如,如果在片元着色器进行了透明度测试,而这个片元没有通过透明度测试,我们会在着色器中调用API(例如clip函数)来手动将其舍弃。这就导致GPU无法提前执行各种测试。这就导致GPU无法提前执行各种测试。

解决方法:现代在GPU会判断片元着色器中的操作是否和提前测试发生冲突,如果有冲突,就会禁用提前测试。但是,这样也会造成性能上的下降,因为有更多片元需要被处理了。这也是透明度测试会导致性能下降的原因。

目标缓冲区

当模型的图元经过了上面层层计算和测试后,就会显示到我们的屏幕上。我们的屏幕显示的就是颜色缓冲区中的颜色值。但是避免我们看到那些正在进行光栅化、逐片元操作的图元,GPU会使用双重缓冲(Double Buffering)的策略。

对场景的渲染发生在幕后,即后置缓冲(Back Buffer)中。当渲染好后则将后置缓冲区与前置缓冲(Front Buffer)中的内容交换,由此来保证我们看到的图像总是连续的。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/666878.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

基于android studio开发的火车票购票系统app,android移动开发课设,毕业设计

基于android studio开发的火车票购票系统app 项目概述 基于android studio开发实现火车票购票系统app 适用于android移动开发学习项目,课程设计,毕业设计等 开发环境及工具 开发工具:android studio 或者intellij idea专业版操作系统&…

最新大学计算机专业实习心得报告

最新大学计算机专业实习心得报告(篇1) 一、实习目的 通过理论联系实际,巩固所学的知识,提高处理实际问题的能力,为顺利毕业进行做好充分的准备,并为自己能顺利与社会环境接轨做准备。通过这次实习&#xff…

软件测试入门篇

软件测试含义 在规定条件下对程序进行操作,发现软件错误,衡量软件质量,对其是否能满足设计要求进行评估的过程 开发不做测试原因:测试力度,思维方式,关注度 计算机定义 一种可以自动高效进行技术操作的…

Debian 版本代号与《玩具总动员》

作为最受欢迎的 Linux 发行版之一,Debian 是许多其他发行版的基础,许多非常受欢迎的 Linux 发行版,例如 Ubuntu、Knoppix、PureOS 、Tails、Armbian 以及 Raspbian,都基于 Debian。 经过近 20 个月的开发,2023 年 6 月…

基于SpringBoot的大学生成长管理系统的设计与实现

摘 要 大学生成长管理系统是记录大学生在大学期间的成长记录史。它是为了促进学生成长、提升学习兴趣及其质量。系统是集辅导员、学生和管理员为核心的一个综合平台。 本系统采用Java编程语言,完成了大学生成长管理系统。系统的使用角色分为三个:管理员…

鉴源实验室丨HSM技术浅述

作者 | 徐奕华 上海控安可信软件创新研究院汽车网络安全组 来源 | 鉴源实验室 引言:2023年5月初,工业和信息化部装备工业一司组织全国汽车标准化技术委员会开展《汽车整车信息安全技术要求》等四项强制性国家标准的制修订[1]。这意味着车辆信息安全管理…

CPU调优 iostat命令

目录 一、命令描述 二、命令作用 三、命令 1.用法 2.命令参数 四、使用实例 1.CPU属性值说明 五、压力测试stress 1.stress介绍 2.stress参数 3.安装stress 四、实验 五、总结 一、命令描述 Linux 中的 iostat 是I/O statistics(输入/输出统计&#xf…

毕业设计心得总结10篇

毕业设计心得总结1 201_年5月30日上午,我们的毕业论文答辩圆满结束了。当刘老师给我们送上人生的祝语时,一种即将离别的难舍之情油然而生,我开始眷恋培养我大学四年的母校,看着一张张熟悉的面孔,过去的欢乐和不快都烟消…

JavaEE课程设计——校园招聘管理系统(vue框架分析)

目录 Vue架构 登录 Vue架构 前端执行命令 npm run serve 这是整个前端的目录结构 vue.config.js是对前端vue的一个配置, // var webpack require(webpack); const path require(path)function resolve(dir) {return path.join(__dirname, dir) }function pu…

每日学术速递6.13

CV - 计算机视觉 | ML - 机器学习 | RL - 强化学习 | NLP 自然语言处理 Subjects: cs.CV 1.Tracking Everything Everywhere All at Once 标题:一次跟踪所有地方的一切 作者:Qianqian Wang, Yen-Yu Chang, Ruojin Cai, Zhengqi Li, Bharath Hariha…

数据结构 栈(C语言实现)

绪论 时间就是生命,时间就是速度,时间就是气力。——郭沫若;本章继续学习数据结构,本章主要讲了什么是栈以及栈的基本功能和实现方法。 话不多说安全带系好,发车啦(建议电脑观看)。 附&#xff…

专业科普:什么是单片机?

一、什么是单片机 单片机诞生于20世纪70年代末,它是指一个集成在一块芯片上的完整计算机系统。单片机具有一个完整计算机所需要的大部分部件:CPU、内存、内部和外部总线系统,目前大部分还会具有外存。同时集成诸如通讯接口、定时器&#xff…

AI日报|GitHub报告:开发者正将AI视为新机会;突破ChatGPT的能力极限;AI会让我们变得愚蠢吗?

今日值得关注的人工智能新动态: AI 会让我们变得愚蠢吗?安永:与老板们不同,大多数工人正在拥抱 AI突破 ChatGPT 的能力极限谷歌推出AI虚拟试穿工具Gannett 涉足生成式 AIGitHub 报告:开发者将 AI 视为一个新机会专家敦…

Nik Color Efex 滤镜详解(4/5)

油墨效果 Ink 模拟特种相纸和调色剂的冲印效果。 颜色组合 Color Set 可选择不同的颜色组合。 强度 Strength 调整滤镜效果程度。 层次和曲线 Levels & Curves 用色阶和曲线来调整图像的影调和色调。常与其它滤镜组合使用。 通道 Channel 选择调节色调的通道。 通道除了…

C++基础(10)——函数模板和类模板

前言 本文主要介绍了C中函数模板和类模板基本知识 6.1&#xff1a;函数模板 模板函数的定义 template<typename T>函数的定义或声明 模板函数的两种使用方法&#xff08;编译器自动推测、显示指定T的类型&#xff09; 注意事项&#xff1a;模板一定要确定指出T的数据…

nuxt打包后文件过大的优化

在使用nuxt.js来做项目的时候&#xff0c;遇到了加载缓慢的问题。解决思路如下 1、大文件拆分 2、文件压缩 大文件拆分 通过nuxt build --analyze或者nuxt build -a命令来启用 在package.json中 添加–analyze&#xff0c;然后执行npm run build 打包后如下&#xff1a; …

MySQL数据库——事物

MySQL数据库——事物 一、事务的概念二、事务的ACID特点1.原子性2.一致性3.隔离性4.持久性5.事务隔离级别的作用范围 三、事务级别的查看与设置1.查询全局事务隔离级别2.查询会话事务隔离级别3.设置全局事务隔离级别4.设置会话事务隔离级别 四、事务控制语句1.测试提交事务2.测…

threeJs着色器

一、着色器 着色器&#xff08;Shaders &#xff09;是一种使用GLSL(OpenGL Shading Language)编写并在GPU上运行的程序。它们被用于定位几何体的每个顶点&#xff0c;并为该几何体的每个可见像素着色。使用“像素Pixel”来描述其实并不准确&#xff0c;因为渲染的每个点不一定…

神经网络小结:训练的全过程

这一节我们主要是将之前的知识穿起来&#xff0c;形成一个整体。如果之前的没看过可以回翻一下专栏。但是在整体回归之前&#xff0c;我们还需要学习一个小知识点——随机初始化 随机初始化 在神经网络中&#xff0c;我们大致的训练流程就是&#xff1a;通过前向传播得出当前…

指针和数组--指针和二维数组的关系

指针和二维数组的关系 目录 一、二维数组的行地址和列地址 二、通过二维数组的行指针和列指针来引用二维数组元素 一、二维数组的行地址和列地址 在C语言中&#xff0c;可将一个二维数组看成是由若干个一维数组构成的。例如若有下面的定义&#xff1a; int a[3][4]&#xf…