Unity 渲染原理

1 渲染流程

渲染流程

  • 应用程序阶段(CPU):识别出潜在可视的网格实例,并把他们及其材质提交给 GPU 以供渲染。
  • 几何阶段(GPU):进行顶点变换等计算,并将三角形转换到齐次空间并进行裁剪。
  • 光栅化阶段(GPU):把三角形转换为片元,并对片元执行着色。片元经过多种测试(深度测试,Alpha 测试等)之后,最终与帧缓冲混合。

2 CPU 的工作流程

  1. 准备好需要被渲染的对象。也就是哪些物体需要被渲染,哪些物体需要被剔除(culled),剔除的常用方式包括视锥体剔除和遮挡剔除,并对需要渲染的对象进行排序。
  2. 设置每个对象的渲染状态。渲染状态包括所使用的着色器、光源、材质等。
  3. 发送 DrawCall。当给定一个 DrawCall 时,GPU 会根据渲染状态和输入的顶点数据进行计算。

3 GPU 的工作流程

GPU工作流程
顶点数据主要来自 CPU 端,然后将数据送到渲染管线中,输入的数据可以包括顶点坐标、顶点颜色、顶点法线、纹理坐标等数据。这些数据以图元的方式进行处理,常见的图元有点、线和三角面。

3.1 几何阶段

3.1.1 顶点着色器

是完全可以编程的,它的是流水线的第一个阶段,用于顶点坐标变换以及顶点颜色计算等,在这里改变顶点的位置可以模拟水面和布料等的运动。其中,顶点着色器将顶点坐标从模型空间转换到齐次裁剪空间,接着进行裁剪剔除不渲染的点后,最终得到归一化的设备坐标(NDC),Unity设备坐标范围同 OpenGL 一样在[-1,1]之间。
顶点着色器的输入来自于CPU,CPU输入的每个顶点都会执行一次顶点着色器,顶点着色器本身无法创建和销毁顶点,并且无法得到顶点与顶点之间的关系。正因为这样的独立关系,GPU可以利用自身的特性进行并行运算,所以顶点着色器的运算速度非常快。在此阶段也会进行透视投影、顶点光照、纹理计算、蒙皮。也可以通过修改顶点位置生成程序式动画(procedural animation),例如模拟风吹草动,碧波荡漾。

3.1.2 几何着色器

几何着色器因为在手机端不支持,所以Unity开发程序员也许并不熟悉。几何着色器也是完全可编程的。几何着色器处理以齐次裁剪空间表示的整个图元(三角形,线段,点)。它能够剔除和修改输入的图元,也能生成新的图元。典型应用包括阴影的体积拉伸(shadow volume extrusion)、渲染立方体贴图(cube map)的六个面、在网格的轮廓边拉伸毛发(fur fin)、从点数据生成粒子四边形、动态镶嵌、把线段以分形细分(fractal subdivision)模拟闪电效果、布料模拟等。

3.1.3 裁剪

由于我们的场景会很大,摄像机视野外的画面不需要进行渲染计算,所以裁剪的作用便是剔除视野外的图元。如下图一条线段A点在视野内,B点在视野外,将会剔除B点,取线段与视野交点处C点。注意裁剪这一步我们不可以编辑,这是硬件上的固定操作。
裁剪

3.1.4 屏幕映射

将图元的x和y坐标转换到屏幕坐标系,这与屏幕的分辨率有关,而图元的z坐标表示各物体与摄像机的远近,用于判断各图元的遮挡关系,这一阶段输出屏幕坐标系下的顶点坐标,Z深度信息,法线方向等。虽然屏幕映射是玩家不可配置和编程的,但是屏幕分辨率确实玩家可以设置的,较小的屏幕分辨率对光栅化阶段是有非常重要的优化效果的。

3.2 光栅化阶段

该阶段是将屏幕坐标系坐标转换为图像像素的过程。
光栅化

3.2.1 三角形设置

这个阶段会计算光栅化一个三角网格所需的信息。具体来说,上一个阶段输出的都是三角网格的顶点,即我们得到的是三角网格每条边的两个端点。但如果要得到整个三角网格对像素的覆盖情况,我们就必须计算每条边上的像素坐标。为了能够计算边界像素的坐标信息,我们就需要得到三角形边界的表示方式。这样一个计算三角网格表示数据的过程就叫做三角形设置。它的输出是为了给下一个阶段做准备。

3.2.2 三角形遍历

该阶段将会检查每个像素是否被三角网格覆盖,对应覆盖像素会生成一个片元,而片元的状态由三角网格三个顶点插值得到,注意片元不是像素。这些片元包含屏幕坐标、深度信息、法线、纹理坐标等。

3.2.3 片元着色器

此阶段的输入是一组片元属性,这些属性是在三角形遍历阶段通过对顶点属性插值所得。输出则是该片元的颜色信息。这一阶段可以完成很多重要的渲染技术,最重要的技术之一就是纹理采样。

3.2.4 逐片元操作

该阶段也称为合并阶段(merge stage)或混合阶段(blending stage)。此阶段不可编程,但是可以高度配置化。最常用的逐片元操作测试包括深度测试 ZTest、Alpha 测试、模板测试 Stencil test,当片元通过了所有测试以后,其颜色就会与帧缓冲原来的颜色进行混合(Blend),混合的方式是可配置的,如 Blend One One。为了避免看到正在栅格化的图元,GPU 使用双重缓冲,场景渲染是在幕后的后置缓冲区进行的,一旦场景渲染完成后会将后置缓冲区内容与前置缓冲区交换,保证图像的连续性。

3.2.4.1 裁切测试

裁切测试可以避免当视口比屏幕窗口小时造成的渲染浪费问题。

3.2.4.2 Alpha 测试

Alpha 测试可以根据片段颜色的 Alpha 值来裁剪片段。
由于 Alpha 测试本身消耗较大,性能较低,所以只有在必要的情况下才会使用 Alpha 测试。

注:片段着色器执行后再进行深度/模板测试,来确定到底哪些片段(Fragments)对屏幕显示有贡献,哪些片段需要被丢弃(Discard),只有哪些通过了深度/模板测试的片段才成为屏幕上显示的像素(Pixels),这也就是片段和像素本质的区别,也就是说片段是最终显示在屏幕上像素的候选者。
由于深度/模板测试是在片段着色器之后进行的,所以导致着色器计算资源的浪费,因为这些被遮挡的片段对我们最终的画面是没有任何贡献的,而我们还花费了大量的资源对它们进行了复杂的光照等一系列计算。
以上是 Alpha 测试效率较低的原因。

3.2.4.3 模板测试

我们可以把它理解为一个模子 mask,通过 mask 的值来控制那些片段的可见性,无法通过模板测试的片段将被丢弃。

3.2.4.4 深度测试

比较当前片段的深度值是否比深度缓冲中预设的值小(默认比较方式),如果是更新深度缓冲和颜色缓冲;否则丢弃片段不更新缓冲区的值。

3.2.4.5 Alpha 混合

当场景中既有不透明物体,又有半透明物体时,我们需要先渲染不透明物体,渲染顺序为从前往后;然后再渲染半透明物体,渲染顺序为从后往前。我们需要对不透明和半透明物体分开渲染是因为:我们可以透过半透明物体看到半透明物体背后的东西,所以对半透明物体进行渲染时需要后面图层的信息,才能够正确进行混合。

  • 3
    点赞
  • 47
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
Unity3D 是一款跨平台的游戏开发引擎,其原理可以简单分为以下几方面: 1. 游戏对象与组件:Unity3D 中的所有元素都是以游戏对象(GameObject)的形式存在,游戏对象可以通过添加不同的组件(Component)来赋予其功能和行为。 2. 场景与层级:游戏中的场景(Scene)是一个虚拟的环境,包含了一系列的游戏对象。在场景中,游戏对象的层级(Hierarchy)决定了它们的父子关系和渲染顺序。 3. 渲染管线Unity3D 使用了基于物理的渲染管线,包括几何渲染、光照计算、材质渲染等过程,通过将场景中的模型、纹理、材质等进行组合和处理,最终呈现出逼真的图像效果。 4. 脚本编程:Unity3D 使用 C# 作为主要的编程语言,开发者可以通过编写脚本来实现游戏逻辑和交互。脚本可以附加到游戏对象上,并通过事件、更新循环等方式来控制对象的行为。 5. 物理引擎:Unity3D 内置了物理引擎,可以模拟现实世界中的物理效果,例如重力、碰撞、刚体等。开发者可以通过设置物理属性和添加碰撞器组件来实现游戏对象之间的物理交互。 总的来说,Unity3D 通过提供一个开发环境和一系列的功能模块,使开发者能够快速创建、设计和发布游戏。它的核心原理是基于游戏对象和组件,通过脚本编程和渲染管线实现游戏的逻辑和图像渲染,同时还提供了物理引擎和其他辅助功能来增强游戏的真实感和交互性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ByteSaid

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值