渲染流水线 相关知识总结

news2024/11/26 4:36:46

目录

  • 抽象理解渲染过程
  • 详细介绍各个渲染步骤
    • 1. 应用阶段
      • 1.1设置场景数据
      • 1.2 Culling 粗粒度剔除
      • 1.3 渲染设置
      • 1.4 传递几何信息
      • 1.5 调用DrawCall
    • 2. 几何阶段
      • 2.1 几何着色器
      • 2.2 可选着色器
      • 2.3 投影变换 projection
      • 2.4 裁切 Clipping
      • 2.5 屏幕映射 ScreenMapping
    • 3. 光栅化阶段
      • 3.1 三角形设置
      • 3.2 三角形遍历
    • 4. 逐片元操作
      • 4.1 片元着色
      • 4.2 测试
      • 4.3 混合
      • 4.4 目标缓冲区
  • 空间变换
    • MVP
    • 裁剪空间
    • NDC
    • 屏幕空间
  • 一些理解
  • 一些易混淆的点
  • 一些名词
  • refer

流水线的这种东西,其阶段划分每个人,每个教程都有不同的理解,这篇会结合我看过的几篇文章,写我自己的流程划分

抽象理解渲染过程


总的流程更像是这样:CPU布置工作、准备材料并下达命令(应用阶段),GPU只负责计算(GPU流水线)
在这里插入图片描述

  • 应用阶段
    1.布置场景数据(场景 物体 光源 摄像机等),决定摄像头中有哪些内容需要渲染
    2.传递渲染状态:即设置各个物体的参数,材质,shader等
    3.粗粒度剔除(culling):剔除摄像机外的内容,优化性能
    4.将几何信息传递给几何阶段
    5.发令 drawcall
  • 几何阶段
    1 几何着色器:进行MVP变换
    2 可选着色器:网格顶点的增加
    3 投影变换 projection:透视除法
    4 裁切 Cliping:优化性能
    5 屏幕映射 ScreenMapping:适应不同屏幕
  • 光栅化阶段:
    总的来说就是计算每个图元覆盖了哪些像素
    1.三角形设置
    2.三角形遍历
  • 逐片元操作:
    1.片元着色
    2.测试&颜色混合
    3.目标缓冲区



详细介绍各个渲染步骤

1. 应用阶段


1.1设置场景数据

一般就是地编,布置物体,设置灯光,设置摄像机

1.2 Culling 粗粒度剔除

粗粒度剔除:包含视锥体剔除(Frustum Culling)和遮挡剔除( Occlusion Culling),减少无用的计算,优化性能(这实际上是帮助后面的MVP变换和clip提前减轻负担,是引擎对于渲染的优化)
请注意:应用阶段的剔除操作是以物体为对象的

  • 视锥体剔除 (Frustum Culling) 禁用相机视野外的对象渲染,不禁用视野中被遮挡的任何物体的渲染(剔除在视锥体外的物体运算量较低,初步剔除)

  • 遮挡剔除:遮挡剔除 (Occlusion Culling) 功能是在对象因被其他物体完全遮挡,当前在相机中无法看到时,禁用对象渲染。该功能一般不会在三维计算机图形中自动开启,因为在透明物体渲染中会出错

(更进一步的,一些光源对象也可以剔除,如与视锥体不相交的聚光,距离非常远的点光源)

1.3 渲染设置

  • 材质参数设置:用哪些贴图,属性参数怎样设置
  • 着色器设置:决定使用哪个shader,或者决定使用GPU instance批处理一些对象(没有使用过Unity中的批处理,具体操作还需要理解)
  • 渲染顺序:决定使用哪种排序来渲染对象,Unity一般就是Render Queue,有些特殊的情况可以自定义,如按照与摄像机距离顺序,特殊的顺序可以在特殊情况下优化性能。
  • 渲染目标:RenderBuffer 或 RenderTexture,有时需要同时输出,如SSSSS的皮肤渲染
  • 设置渲染模式:forwardBase前向渲染,延迟渲染等

1.4 传递几何信息

将准备好的场景信息存入显存(我不确定是整个场景的数据还是当前剔除后的数据,需要进一步查证,如果是剔除后的数据,那显存岂不是每一帧都要来回的写入?)

  • 几何信息:位置、法线、uv坐标、(颜色)发送给几何着色器 (注意这些信息全部是模型空间的信息!
    (有一个问题,几何信息是以物体/图元为单位的,还是没单位,所有顶点全视为单个顶点,后续再组装起来?)(思考3min后的解答:当然是以对象为单位的,渲染是以对象为单位的啊,一个对象渲染完成后,下一个对象还会进行几何阶段,顶点自然也就分开了)
  • MVP矩阵信息(M矩阵就是这个物体在世界中的位置了)
  • 贴图(先存入显存,后续再由纹理坐标读取?)

1.5 调用DrawCall

当一切都准备好之后,发送最后一句drawcall命令
drawcall由CPU发起,GPU接收执行,其指向一个需要被渲染的图元列表(图元列表?是不是就是一个对象?)
应用阶段准备好了一切计算需要的材料,只需要开始计算即可得到结果,drawcall就是发起命令




2. 几何阶段

2.1 几何着色器

  • MVP变换
  • (顶点着色)

2.2 可选着色器

顶点着色器是不能生成更多的顶点的,其只能进行变换
这一步是可以有也可以没有的,都还没学,慢慢补吧

  • 几何着色器:以图元为单位(点线面)来生成更多的图元
  • 曲面细分着色器:使用当前的顶点按照算法生成更多的顶点,分成细致的网格和图元

2.3 投影变换 projection

Unity会自动完成

  • P变换,两种,正交和透视

2.4 裁切 Clipping

裁切选择在 几何和可选着色器 之后进行,是为了防止出错
(出错情况举例:截了一半的物体,vert里要缩小它,那后续不就露出来那被截断的部分了么)

  • CVV视锥体裁切
  • 正背面剔除 (所以说clipping和culling的划分很混乱)

2.5 屏幕映射 ScreenMapping

Unity会自动完成

  • 另外需要考虑不同的图形API的坐标系

在几何阶段完成后,最终我们会获得这样一个坐标系:以屏幕左下角为原点(OpenGL屏幕原点在左下,DirectX在左上)
而几何阶段最终传递的信息为:

  • 顶点信息:位置(在屏幕空间中的xy坐标)深度值法线方向uv坐标颜色(如果有)
  • 其他信息:摄像机位置信息,光线信息等




3. 光栅化阶段

3.1 三角形设置

在这个过程中进行的操作是:前一步传入的数据全部是顶点,三角形设置则将所有的顶点组装成图元,(一般是三角形,也有线段和折线)
不必纠结这个过程究竟怎么实现的,因为这是渲染器要做的事情
在这里插入图片描述

3.2 三角形遍历

在上一步我们获得了各个三角形(而不是顶点),现在我们知道了各个三角形的边界是如何的了,三角形遍历要做的事情就是:根据三角形的边界,映射到片元中:
在这里插入图片描述

  • 这个过程中最重要的是,将顶点信息插值,赋给每一个片元
    (我们本身只有顶点的数据(如:深度,法线,UV坐标等等),那每一个片元中的信息就是根据所在图元的几个顶点按照规则插值出来的,这样我们就获取了每一个片元计算所需要的数据,剩下的就是计算的问题,也就是片元着色器)
  • 同时如果有顶点着色,片元颜色的插值也会在这一步进行(片元着色器就没有着色的计算了直接输出即可):

在这里插入图片描述

  • 抗锯齿:由于光栅化是硬件自动进行的,无法使用着色器进行编程,所以这一步能够进行只有硬件的抗锯齿算法:SSAA,MSAA
    (其余的抗锯齿是在后处理阶段软件进行的FXAA,TXAA
  • 详细的抗锯齿可以看本人的抗锯齿文章



4. 逐片元操作

4.1 片元着色

  • 正常情况下这一步就是进行fragment shader了,正常来讲也是整个流水线最耗时的部分,包括读取纹理,光照计算等等
  • 但是一般现代GPU会把这个过程放到测试之后,原因接着看:

4.2 测试

包括:模板测试、深度测试、透明度测试
大家都懂哈,不多说了

详细说一下测试和着色的顺序

  • 经典情况下是先着色再进行测试
  • 但是呢这回有一个问题,性能开销太大,辛辛苦苦着色完了,还被抛弃掉了;因此现代的渲染顺序一般都会先进行测试,再进行着色,包括Unity的Early-Z技术等,这会大大提高性能,尤其是场景遮挡比较复杂时
  • 当然也有其缺点,这个问题出现在透明物体上,比如:透明物体在前,如果先进行了测试,那么先渲染的物体(后面的物体)被前面透明物体遮挡住的部分就不会进行着色,也就是空白的,这样在后面透明物体进行着色后,跟缓冲区的颜色进行混合时就会出错,因为缓冲区根本没有颜色缓冲数据。
  • 所以当面临透明物体的渲染时,就需要考虑一下测试和着色的顺序了。

4.3 混合

  • 前面着色后的数据会被存入颜色缓冲,后面物体着色后如果在同一个像素,就需要进行混合(或者替换),这个混合/替换法则是可以配置的。

4.4 目标缓冲区

渲染完一帧之后,我们获得了完整的一张图像(颜色缓冲中),最后要进行的就是把它输出到什么位置:

  • 一般就是交换前置后置缓冲
  • 或者输出到渲染纹理,进行后处理操作等




空间变换

模型空间 → \to 世界空间 → \to 观察空间 → \to 裁剪空间 → \to NDC → \to 屏幕空间
在这里插入图片描述

MVP

模型空间 → \to 世界空间 → \to 观察空间 → \to 裁剪空间

  • 这个过程中的三个箭头对应MVP三个矩阵
  • MVP在几何着色器中执行(UnityModelToClipPos)

M:

  • 从模型的空间变换到世界空间
  • 物体的移动,真正的落实在这个M矩阵上

V:

  • 从世界到观察
  • 原点变换到摄像机位置
  • 某种意义上,摄像机看到的前进其实是世界在后退

P:

  • 不是真正的投影,而是为投影做准备
  • 为什么这么说:需要进行透视除法才算真正完成投影,而透视除法需要先计算好对应的 w分量,P矩阵就在计算w(根据距离摄像机的距离计算得)

裁剪空间

进行MVP变换后便得到了裁剪空间,在这个空间中,我们自然是要进行裁剪,裁剪的范围是可以设定的(就是视锥体的范围)

  • 裁剪的方法:对于xyz任意一个坐标大于其w分量的顶点,进行剔除(其实在应用阶段已经进行了粗粒度剔除),如果是半截在边界外的图元,会截断图元,并在边界生成新的顶点补足这个图元

最终的裁剪结果就是下面这样:
从这时开始,之前的空间都变为有限的空间
这个过程进行了透视除法

NDC

在裁剪过后,进行透视除法,并标准化坐标,得到NDC
透视除法是一个开销很大的过程,其需要对每一个顶点的分量都除以w分量,因此需要在裁剪过后再进行透视除法,以减少工作量
(下面这个图有错误,第二个不是裁剪空间,裁剪空间应当是锥形的)
在这里插入图片描述

屏幕空间

从NDC到屏幕空间的变化称为视口变换




一些理解

1.为什么要使用模型空间?所有模型顶点直接用世界坐标原点不就好了?省的计算M矩阵

  • 答:
    (1)缓存传递:不能这么做的最大问题在于:如果使用世界坐标,每次模型运动时,每一个顶点的数据都需要重新发送给缓存,这是不能接受的;如果当使用模型坐标,要移动模型,我们无需改变已经在缓冲区的顶点坐标数据,只需改变M矩阵,即可将模型移到我们指定的位置。
    (2)计算量上:使用世界坐标看似减少计算,实际上如果要进行位移计算,其需要矩阵的加减乘积运算结合,是非常复杂的;另外其实M变换和MV变换的计算量是一致的(MV可以预计算,记为一个矩阵)
    (4)简洁性上:将模型起始于原点位置进行顶点的设置,所有的顶点坐标都是相对于 (0,0,0),简洁明了

2. 透视除法为什么安排在最后?
答:因为透视除法会破坏其几何结构,顶点着色器和下面的可选着色器都需要在裁剪坐标系下进行,此时的几何关系是正确的,最后完成所有的几何操作之后,映射之前,才会进行投影变换)




一些易混淆的点

剔除和裁切(culling & clipping):很多将culling和clipping都叫做剔除,不管是中英文都会混着叫
earlyZ和剔除:

一些名词

OverDraw:因为在大部分情况下,离相机最远的对象最先渲染,离相机近的对象覆盖先前的物体(该步骤称之为“重复渲染 (overdraw)”)

DrawCall:





refer

《入门精要》
百人计划
LearnOpenGL
各个空间
空间变换
NDC和裁剪

知乎
csdn

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

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

相关文章

C++ Primer阅读笔记--返回类型和return语句

1--返回引用 同其他引用类型一样,如果函数返回引用,则该引用仅是所引对象的一个别名;则返回结果时不会发生拷贝操作; 不能返回局部对象的引用或指针;因为局部对象在函数结束后会被释放,从而其引用或指针将指…

【第六篇:测试左移-研发流程优化】

(1)规范了技术需求的研发流程(和产品需求一样走相同的流程,只不过需求的主R变为了RD) (2)规范了需求变更流程:需求变更要合理并做到全员周知; (3)强调冒烟不过,提测打回流程; (4)增加交互视觉评审环节,方便RD更合理估时; (5)规范回归测试流程,回归测试时需…

PbootCMS Sqlite数据库转Mysql数据库教程 sqlite转mysql

PbootCMS默认采用的是Sqlite数据库,系统自带完整后台以及一套响应式模板,放入PHP(5.3+)环境即可直接使用 线上搭建简易环境为:Apache 、 PHP5.6-PHP7.3 、 Mysql5.5+ 所以如果已经上线一段时间了,网站已经有较多内容后要想换成Mysql版本是很不方便的,以下就是快速将Mys…

WebSocket的那些事(2-实操篇)

目录 一、概述二、Websocket API1、引入相关依赖2、配置WebSocket处理器3、WebSocket配置4、测试 三、总结 一、概述 在上一节 WebSocket的那些事(1-概念篇)中我们简单的介绍了关于WebSocket协议的相关概念、与HTTP的联系区别等等。 这一节将会带来Web…

BM59-N皇后问题

题目 N 皇后问题是指在 n * n 的棋盘上要摆 n 个皇后。 要求:任何两个皇后不同行,不同列也不在同一条斜线上。 求给一个整数 n ,返回 n 皇后的摆法数。 数据范围: 1≤n≤9。 要求:空间复杂度 O(1) ,时间复杂度 O(…

牛客 NC24724 Feb S]Chocolate Eating 解题报告

原题链接&#xff1a; 登录—专业IT笔试面试备考平台_牛客网 题目描述&#xff1a; 链接&#xff1a;登录—专业IT笔试面试备考平台_牛客网 来源&#xff1a;牛客网 题目描述 Bessie has received N (1 < N < 50,000) chocolates from the bulls, but doesnt want to …

Notepad++ 配置python环境及虚拟环境

背景&#xff1a; 在执行某些项目的时候&#xff0c;经常会否遇到这样一种情况(以python语言为例)&#xff1a;不想在python的基础环境下运行&#xff0c;创建了虚拟环境来装相关项目的包&#xff0c;但是每次使用都要切换到虚拟环境下面使用"activate "命令激活环境…

C++linux高并发服务器项目实践 day8

Clinux高并发服务器项目实践 day8 内存映射内存映射相关系统调用例子思考问题案例2案例3 信号信号的5中默认处理动作信号相关函数kill、raise和abort函数alarm函数案例 setitimer函数 signal信号捕捉函数 内存映射 内存映射是将磁盘文件的数据映射到内存&#xff0c;用户通过修…

Spring MVC数据格式化与验证以及国际化和中文乱码处理

目录 Spring MVC数据格式化 基本介绍 ConversionService converters 基本数据类型和字符串自动转换 代码实例 -页面演示方式 创建Monster 类 创建data_valid.jsp 创建MonsterHandler类 创建monster_addUI.jsp 解读: 说明 阶段测试一下 ​编辑 继续完成功能 创建s…

springboot+vue校园疫情防控系统(源码+文档)

风定落花生&#xff0c;歌声逐流水&#xff0c;大家好我是风歌&#xff0c;混迹在java圈的辛苦码农。今天要和大家聊的是一款基于springboot的校园疫情防控系统。项目源码以及部署相关请联系风歌&#xff0c;文末附上联系信息 。 &#x1f495;&#x1f495;作者&#xff1a;风…

理想汽车VS特斯拉,电动汽车正在吞噬世界

来源&#xff1a;猛兽财经 作者&#xff1a;猛兽财经 电动汽车正在吞噬世界 长期以来&#xff0c;电动汽车在美国一直是一项边缘技术&#xff08;当时主要是加州的环保主义者和科技圈在关注&#xff09;。即使现在如日中天的特斯拉(TSLA)&#xff0c;当年也是在成立三年后的20…

【案例1】图书馆管理系统毕业论文

博主介绍&#xff1a; &#x1f680;自媒体 JavaPub 独立维护人&#xff0c;全网粉丝打大于100w&#xff0c;csdn博客专家、java领域优质创作者&#xff0c;51ctoTOP10博主&#xff0c;知乎/掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和副业。&#x1f680; …

npm私有仓库(nexus)-Vue组件发布到nexus

1、创建组件项目 进入项目目录并 执行 npm install 安装依赖&#xff0c;npm run dev 运行&#xff0c;此时浏览器打开 http://localhost:8080 可看到初始化页面 2、在 src 目录下新建测试组件&#xff0c;如下图所示 3、项目目录下新建组件暴露文件 4、修改 package.json pri…

Spring Boot项目使用maven的jib插件打docker使用所需的镜像tar包

jib插件介绍 Jib是一个由Google开发的基于Docker镜像构建的工具&#xff0c;它的Maven插件可以让我们以更高效的方式构建和管理Docker镜像。使用Jib&#xff0c;我们可以摆脱手动编写Dockerfile的繁琐过程&#xff0c;而是直接将我们的Java应用程序打包为镜像&#xff0c;并将…

CPU狂飙900%,该怎么处理?

一位小伙伴面试了 网易&#xff0c;遇到了一个 性能类的面试题&#xff1a;CPU飙升900%&#xff0c;该怎么处理&#xff1f; 可惜的是&#xff0c;以上的问题&#xff0c;这个小伙没有回答理想。 最终&#xff0c;导致他网易之路&#xff0c;终止在二面&#xff0c;非常可惜 …

MySQL学习笔记第九天

第08章聚合函数 上一章讲到了 SQL 单行函数。实际上 SQL 函数还有一类&#xff0c;叫做聚合&#xff08;或聚集、分组&#xff09;函数&#xff0c;它是对一组数据进行汇总的函数&#xff0c;输入的是一组数据的集合&#xff0c;输出的是单个值。 1.聚合函数介绍 什么是聚合…

智能优化算法:袋獾优化算法-附代码

智能优化算法&#xff1a;袋獾优化算法 文章目录 智能优化算法&#xff1a;袋獾优化算法1. 袋獾优化算法1.1 初始化1.2 策略一&#xff1a;以腐肉为食&#xff08;探索阶段&#xff09; 2.实验结果3.参考文献4.Matlab 摘要&#xff1a;袋獾优化算法&#xff08;Tasmanian Devil…

MyBatis官方文档学习笔记(一)

本笔记根据mybatis官方文档顺序学习&#xff0c;根据本笔记可快速掌握mybatis的使用。 1 快速开始 1.1 快速开始 1.1.1 安装 使用MyBatis之前必须要安装mybatis-x.x.x.jar驱动文件到类路径中&#xff0c;如果使用的是Maven工程&#xff0c;则只需要导入下面的依赖即可&…

Java集合-Java集合基础

目录 讲一讲Java集合吧 集合的使用 为什么要使用集合&#xff1f; 如何选用集合? Collection Collection与Collections的区别是什么&#xff1f; Collections.sort和Arrays.sort的实现原理 为何Collection不从Cloneable和Serializable接口继承&#xff1f; 线程安全集…

面向开发人员的 ChatGPT 提示语教程中文版

面向开发人员的 ChatGPT 提示语教程中文版 1. 指南1-1. 提示的指南1-2. 配置1-3. 提示语原则原则 1: 写出清晰而具体的指示技巧 1: 使用分隔符来清楚地表明输入的不同部分技巧 2: 要求提供结构化的输出技巧 3: 要求模型检查条件是否得到满足技巧 4: "少许样本"提示 原…