使用 英特尔 流式 SIMD 扩展 优化 动画 模型 的 渲染流水线
作者JMP van Waveren,Id Software,Inc.
介绍
以下 文章 描述了 渲染管道中使用的 各个 例程,
以及如何 使用 英特尔 Streaming SIMD 扩展 进行 优化。
今天的大部分电脑游戏都带有 实时照明和 阴影 的 动画多边形 模型。
电脑游戏DOOM * III(2004年8月)和 Quake * 4(2005年10月)也不例外。
两台电脑游戏都使用 骨架动画系统。
通常被称为“皮肤”的 多边形网格 连续地 改变形状,
其中底层结构通常被称为“bones”。(?)
通过动画化骨骼,skin 被转化。
将skin转变的过程称为“skining加壳”。(我自己 给按的名字!)
两个游戏也使用 阴影卷 定义在 遮挡物阴影的 空间中的 区域。
阴影体积 由包含 多边形封堵器阴影的 体积的 多边形边界 表示 定义。
以下文章概述了 SIMD优化 的 动画模型 渲染流水线,
其性能与电脑游戏DOOM III中使用的 性能相当。
这个改进的渲染流水线在计算机游戏Quake 4中实现。
大部分渲染流水线在CPU上运行,
而管道中的几个步骤可以运行在当今许多显卡上可用的GPU上。
然而,在CPU上运行大部分管道可以提高 广泛系统的兼容性。
较旧的系统可能具有不支持在GPU上执行动画和 skining加壳 的必要功能的图形卡
(如GeForce2和GeForce4MX)。
允许在GPU上进行皮肤化的显卡可能具有将大型“”模型架”模型 细分为 多个 网格的限制,
从而 降低效率。
此外,需要后变换的皮肤来构建阴影体,
并且当前的图形卡在处理之后不允许检索此数据。
阴影体积结构可以完全卸载到GPU,
但是如果闭塞器具有高三角形数量 或者 如果有 大量 阴影投射光源,
则这可能无法提高性能。
由于这些原因,电脑游戏DOOM III和Quake 4运行CPU上的大部分管道,
允许游戏在各种系统配置下运行。
此外,在CPU上运行的流水线几乎没有任何限制,
SIMD优化使得流水线与(部分)GPU实现相竞争。
渲染管道可以细分为 四个 一般 阶段。
这些阶段是 动画,皮肤,阴影体积建设 和 裁剪 和光栅化。
下图显示了这些阶段为大型浅灰色块。
每个阶段被细分为更小的步骤,其中处理的数据以倾斜框显示,
并且处理该数据的例程显示在较暗的灰色框中。
这些框的黑色角落中的数字对应于 底部描述例程的文章
以及如何使用英特尔Streaming SIMD扩展进行优化。
动画系统可以混合一个或多个动画。在上图中仅显示了两个动画,
但是可以将更多的动画混合在一起以产生复杂的运动混合。
动画是一系列动画帧。
每个动画框架将骨架的姿态定义为使用四元数描述方位的关节位置 和 方向的列表。
关节的位置和方向与骨骼层次结构中关节的父母相关。
点击图片查看大图。(此处图片暂无……)
系统从动画中抽取时间t0和t1的两帧,
使得当前时间在t0和t1之间。
然后系统在这两个帧之间进行插值,
以获得当前时间的骨架姿势。
然后将正在播放的所有动画的内插帧混合在一起以获得骨架的最终姿态。
接下来,将 关节位置 和 四元数 变换为 3×4 矩阵。
此外,联合矩阵 用其 parents的 联合 矩阵 进行变换,
以在 模型空间 中创建 skeleton。
(也许很多 动画 方面的 概念 源于 医学 3D视觉效果分析得到的,
但是很多 表述在其他领域换个说法或者理论之类!!
有的我自己都感觉很不爽!)
点击图片查看大图。 (图片请参照原文........)
模型空间中的skeleton 用于为通常称为 skining (应该是 skining ,我自己 译为 蒙壳)
的三角形 网格 生成 动画。
基于三角形网格是用于 渲染 还是仅用于创建阴影体 或 进行 碰撞检测,
系统可以决定最佳的skining 方法。
如果模型没有使用漫反射,法线和 法线贴图,
则通常不需要在顶点位置计算 正态 和 切线矢量。
如果不需要,可以通过不动画化 和 计算这些附加顶点属性来节省 时间。
确定计算正态和切向矢量的skining 方法 要求将 skeleton 的关节进行 变形,
使得它们 相对于被变换以 创建 动画 网格 的 基础姿势的关节。
点击图片查看大图。(图片暂无……)
在下一阶段,为与三角形网格相互作用的 每个 光源 构建 阴影体。
阴影体 定义空间中具有 附加几何 的 对象空间 中 遮挡物 阴影 的 空间区域。
可以为 点光源,聚光灯 和 定向光源 构建 阴影体,
并始终产生 像素精确 但 硬 的阴影。
在 构造 任何 阴影体 之前,
需要导出 三角形网格 中 三角形 的 平面方程。
这些 平面方程 用于 找到 面向 或 远离 光源的 三角形,
并确定 几何图形 的 阴影轮廓 边缘。
这样的 轮廓边缘 是 点燃 和 未点燃三角形 之间的边界。 (此处 翻译可能有误……)
点击图片 查看 大图。(图片暂无 ……)
在最后一个阶段,
通常在GPU上运行,
三角形网格 和 阴影体 被 裁剪和 光栅化。
(我自己 十分 怀疑有的 这个理论 来源于 织布机?还是投影仪?电影放映机?)
阴影体 被渲染到 模板缓冲区,
当在屏幕上 渲染三角形网格 以 确定 哪些像素处于 阴影 时 被 查询。
要确定空间中 三角形网格 的 阴影区域,
模板缓冲区 首先被 清除为 全零。
然后用适当的深度测试将三角形网格的阴影体 呈现到模板缓冲区。
前面的阴影体积三角形增量和 背面三角形减少 模板缓冲区像素。
现在在阴影中 考虑了 具有不等于 零的 模板缓冲区值的 像素。
下表显示了在渲染管道中使用的所有SIMD优化例程的概述。
该表显示了90nm技术上的Intel®Pentium®4处理器上的例程的热缓存 时钟 周期 计数。
将例程的 加速因子 与 执行 相同计算 的 C / C ++中的 参考实现 进行比较。
但是,C / C ++源代码编译成在基于x86 FPU的常规堆栈上运行的代码。
前面的阴影体积三角形增量和背面三角形 减少模板缓冲区像素。
现在在阴影中 考虑了 模板缓冲区值 不等于零的像素。
下表显示了在渲染管道中使用的所有SIMD优化例程的概述。
该表显示了90nm技术上的Intel®Pentium®4处理器上的例程的 热缓存时钟周期计数。
将例程的加速因子与执行相同计算的C / C ++中的参考实现进行比较。
但是,
C / C ++源代码 编译成 在基于x86 FPU的常规堆栈上 运行的代码。
前面的阴影体积三角形增量和背面三角形 减少 模板缓冲区像素。
现在在阴影中考虑了 具有不等于零的 模板缓冲区值 的 像素。
下表显示了在渲染管道中使用的所有SIMD优化例程的概述。
该表显示了90nm技术上的Intel®Pentium®4处理器上的例程的热缓存时钟周期计数。
将例程的加速因子与执行相同计算的C / C ++中的参考实现进行比较。
但是,C / C ++源代码编译成在基于x86 FPU的常规堆栈上 运行的代码。
下表显示了在渲染管道中使用的所有SIMD优化例程的概述。
该表显示了90nm技术上的Intel®Pentium®4处理器上的例程的热缓存时钟周期计数。
将例程的加速因子与 执行 相同 计算 的C / C ++中的参考实现进行比较。
但是,C / C ++源代码编译成在基于x86 FPU的常规堆栈上运行的代码。
下表显示了在渲染管道中使用的所有SIMD优化例程的概述。
该表显示了90nm技术上的Intel®Pentium®4处理器上的例程的热缓存时钟周期计数。
将例程的加速因子与执行相同计算的C / C ++中的参考实现进行 比较。
但是,C / C ++源代码编译成在基于x86 FPU的常规堆栈上运行 的 代码。
| 常规 | 加速系数 | 说明每次迭代 | 每次迭代的元素 | 数迭代 | 总指示 | 总时钟周期 | 每个元件的时钟周期 | 每个指令的时钟周期 |
| SlerpJoints | 7.9 | 213 | 4 | 256 | 54549 | 131517 | 128 | 2.4(2.411) |
LerpJoints | 4.8 | 132 | 4 | 256 | 33819 | 52848 | 52 | 1.6(1.563) |
ConvertJointQuatsToJointMats | 1.8 | 34 | 1 | 1024 | 34823 | 34362 | 34 | 1.0(0.987) |
ConvertJointMatsToJointQuats | 2.4 | 207 | 4 | 256 | 53003 | 73710 | 72 | 1.4(1.391) |
TransformSkeleton | 3.0 | 45 | 1 | 1024 | 46093 | 54297 | 53 | 1.2(1.178) |
UntransformSkeleton | 2.8 | 48 | 1 | 1024 | 49164 | 57285 | 56 | 1.2(1.165) |
TransformJoints | 3.0 | 41 | 1 | 1024 | 41995 | 48906 | 48 | 1.2(1.165) |
TransformVerts | 3.0 | 39 | 1 | 1024 | 39946 | 43956 | 43 | 1.1(1.100) |
TransformVerts(SSE3) | 3.1 | 33 | 1 | 1024 | 33802 | 41963 | 41 | 1.2(1.241) |
TransformVertsAndTangents | 2.6 | 80 | 1 | 1024 | 81930 | 89775 | 88 | 1.1(1.096) |
| TransformVertsAndTangents(SSE3) | 2.8 | 61 | 1 | 1024 | 62474 | 81855 | 80 | 1.3(1.310) |
DeriveTrianglePlanes | 4.2 | 121 | 4 | 256 | 30990 | 36128 | 35 | 1.2(1.165) |
| CountFacing | 59.2 | 31 + 4 | 256 + 16 | 5 + 4 | 196 | 383 | 0.3 | 2.0(1.954) |
CountFacingCull | 2.1 | 37 | 4 | 336 | 12454 | 13883 | 10 | 1.1(1.115) |
| CreateSilTriangles | 1.2 | 70 | 4 | 504 | 35300 | 36901 | 18 | 1.0(1.045) |
| CreateCapTriangles | 2.4 | 54 | 4 | 336 | 18170 | 14205 | 11 | 0.8(0.782) |
所有呈现的例程假设被处理的数据都在缓存中。
可选的预取指令可以添加到例程中。
然而,预取距离不仅取决于CPU类型,
还取决于CPU速度,内存速度,缓存速度,
缓存级别数以及其他几个因素。
因此,在所有系统配置 上 都没有 最佳的预取距离。
英特尔手册 提供了使用预取指令优化特定配置的 内存访问的 指标。
通常可以通过一次将模型推下一个 管道来 提高缓存 的使用率。
因此,
流水线中的一个步骤的结果在流水线的下一步骤中从高速缓存取出后
通过 缓存 和 快速写入存储器。
与130nm技术上的较早的英特尔®奔腾®4处理器相比,
在90nm技术的较新英特尔®奔腾®4处理器上执行代码时,
文章中提供的一些热缓存时钟周期计数略高。
首先,
这些CPU之间的这些热缓存时钟周期差异与所呈现的优化的性能改进无关。
90nm技术上的英特尔®奔腾®4处理器具有更深的流水线,
预期稍高一些的热缓存时钟周期。
然而,90nm技术上的英特尔®奔腾®4处理器可以提供更高的频率,
并且由于更长的管道,
由此架构可实现的频率增加高于热缓存 时钟周期计数 的增加。
此外,90nm技术上的英特尔®奔腾®4处理器具有许多改进,
在许多情况下,
实际上使其在130nm技术上以相同频率运行的英特尔®奔腾®4处理器的性能更好。
采用130nm技术的英特尔®奔腾®4处理器,
90nm技术架构上的英特尔®奔腾®4处理器的一些改进包括:
- 较大的缓存。
- 改进的软件和硬件预取。
- 更好的静态和动态分支预测。
- 增加调度程序队列,以改进对并行性的利用。
- 认识到更多的指示可能会破坏依赖关系链。
- 减少一些指令的延迟,如整数乘法和逐位逻辑移位。
- 新的指令,如浮点整型转换,截断,线程同步指令和流式SIMD扩展3(SSE3)。
130nm技术上的英特尔®奔腾®4处理器从1.6 GHz扩展到3.4 GHz,
并附带512 kB片上缓存。
90nm技术的英特尔®奔腾®4处理器的尺寸为2.4 GHz至3.8 GHz,
并带有1或2 MB片上缓存。