概括地说,图形处理流程的很大一部分是由 GTE 完成的。 其中包括透视变换(利用摄像机的透视将3D空间投射到2D平面上)和光照。 处理后的数据将被发送到索尼专有的GPU上进行渲染。
硬件组织
系统配备1 MB的VRAM,用于存储帧缓冲区、纹理和GPU渲染场景所需的其他资源。 CPU可以使用DMA填充该区域。
配备的芯片(VRAM)是双端口的,就像Virtual Boy的一样。 VRAM使用两条16位总线,可在CPU/DMA/GPU和视频编码器之间同时访问。
不过在这款游戏机的后期版本中,索尼改用了SGRAM芯片(使用单独32位数据总线的单端口选项)。 嘘!...... 好吧,公平地说,每一种都有其优点和缺点。 可以肯定的是,由于时序上的差异,后来的游戏(如喷气摩托3(Jet Moto 3))在基于VRAM的系统上运行时,会出现图形卡顿的现象。 如果你想了解详情,Martin Korth的"Nocash PSX规格"记录了不同的时序等信息。
绘制场景
如果您一直在阅读世嘉土星的文章,让我告诉您,这款GPU的设计要简单得多!
现在,我主要以Insomniac的小龙斯派罗:龙年(Spyro: Year of the Dragon)为例,向大家展示如何绘制场景。 请注意,这款游戏的内部分辨率过于狭窄(292x217像素),导致我无法清晰地剖析游戏的每个阶段,因此我将其放大了一些,以方便演示。 如果你好奇,这里有一个原始比例的样本 。
指令
首先,CPU通过向内部64字节FIFO缓冲区填充指令(最多三条),向 GPU 发送几何数据(顶点)。 这些命令可能要求GPU渲染某些内容、更改设置或操作VRAM。
从本质上讲,渲染命令说明了绘制基元的方式和位置。 GPU可以单独绘制线条、矩形和三角形,后者是构成丰富3D模型的基本要素。
一旦接收到几何图形,就会进行剪切,以跳过对不可见多边形(位于摄像机视角之外)的操作。
基元的位置用指向帧缓冲区的 X/Y 坐标系来表示。 PS1的GPU采用整数坐标模型,每个坐标对应一个像素的中心点(称为采样点)。 换句话说,没有小数坐标。
可见性方法

古惑狼(Crash Bandicoot)(1996) 这款游戏使用预先排序的几何图形来提高性能。 因此,它的摄像头只能向后或向前移动。
与竞争对手一样,PS1也不具备任何解决可见性问题的硬件功能。 不过,GPU通过提供一个排序表来处理排序的多边形: 这是一个专用表格,其中每个条目都使用深度值(也称为 "Z值")进行索引,并包含GPU命令所在的地址。
CPU首先需要手动对多边形进行排序,然后将它们引用到表中正确的条目中。 最后,CPU会命令DMA将表格发送到GPU。 这一过程将使GPU能够以正确的顺序渲染几何图形。
此外,还提供了多个DMA函数,以协助CPU和GPU创建和遍历该表。
光栅化
一旦命令被GPU解码,就需要将接收到的几何图形(顶点)转换为像素。 这将使系统能够应用纹理映射和特效,并最终将其显示在二维面板(电视或显示器)上。 为此,GPU会分配一个像素矩阵作为工作区,这就是所谓的帧缓冲区。 与更复杂的世嘉土星相比,GPU 只需要一个帧缓冲器。
光栅化器是负责将向量转换为线条、三角形或矩形,然后再转换为像素的单元。 现在,这一过程因所需的基元不同而大相径庭:
- 三角形是最复杂(也是用途最广)的类型,可以制作纹理和阴影。
- 直线的绘制速度较快,但对于纹理表面来说自然不可行。。 它们仍然可以着色
- 矩形也比较快,但只能拿来制作最多容纳256x256像素的精灵(更大的矩形会重复精灵的图形)。 即便如此,它们也不提供仿射变换(X/Y 翻转除外)、着色或特效。 我怀疑这样做是为了帮助 2D 游戏的实施。
对于三角形这个唯一能用来制作纹理的多边形,光栅化器将:
- 抓取每个三点顶点并计算边缘。 这样就形成了一个三角形。
- 分析三角形区域,确定它们占据了帧缓冲区的哪些像素。 只有覆盖采样点的多边形部分才会变成像素。
生成的像素不会立即写入帧缓冲区。 相反,它们会被发送到流水线的下一阶段进行进一步处理,我们将在下面的段落中看到。
着色器
为了在三角形或线条上应用光照效果,GPU提供了两种算法:
- 平面着色: 每个基元都有一个恒定的光照度。
- 高洛德(Gouraud)着色: 每个基元的顶点都有自己的光照度。 然后,每个点之间的亮度会自动插值。
- 可以想象,这种类型比平面阴影效果更逼真。
之所以有这种选择,是因为平面着色每秒填充的多边形数量是高洛德着色的~2.5倍,因此优化哪些多边形需要比其他多边形更逼真的着色非常重要。
纹理
三角形表面还可以与纹理(2D位图)混合,生成最终效果。
GPU执行逆纹理映射,即 GPU 遍历每个光栅化像素,并在纹理贴图中查找其对应的像素(称为纹理元素(Texel))。 纹理元素是通过线性插值纹理贴图(在VRAM中找到)来计算的,以符合多边形的形状。 用于插值的程序称为"仿射纹理贴图",这种技术只使用2D坐标(X-Y值),而忽略了用于透视的第三个坐标(Z或"深度")。
由于纹理贴图很少具有光栅化多边形的精确尺寸,因此可能会出现混叠(不正确的结果)。 这表现为不必要的失真,例如缺失或放大的纹理。 为了解决这个问题,先进的GPU采用纹理过滤技术来平滑(插值)颜色的突然变化。 现在,PS1的GPU没有实现任何过滤功能,因此它采用了一种名为近邻的算法来校正比例,而不会平滑结果。 这种算法速度非常快(而且便宜),但这也解释了为什么纹理模型看起来会"方方正正"。
GPU还包含以下可供使用的特效(在三角形上):
- 半透明: 模拟光线穿过多个纹理。
- 抖动: 柔化颜色的突然变化,同时保持相同的调色板。
值得一提的是,PS1恰好擅长这些效果!
剩余步骤
完成后,GPU会将像素写入VRAM中的帧缓冲区,然后由视频编码器接收并播放到屏幕上。
设计
让我们从这些理论中解脱出来。 这里有一些为3D时代从头开始设计的游戏角色的例子,它们是可交互的,所以我鼓励你去看看!

"现代版本"中可用的互动模型
小龙斯派罗(Spyro the Dragon)(1998)
413个三角形

"现代版本"中可用的互动模型
古惑狼(Crash Bandicoot) (1996)
732个三角形
玩转 VRAM
利用可用的 VRAM(整整 1 MB),我们可以分配一个1024×512像素、16位色彩的超大帧缓冲区,或者一个960×512像素、24位色彩的逼真帧缓冲区-让我们可以绘制任何游戏都曾展示过的最佳帧...... 这听起来很令人印象深刻,对吧? 不过,这也引发了一些问题:
- 这些尺寸必须按照标准化的定义(即 480 NTSC、576 PAL)重新缩放,这样视频编码器才能将其播放到消费者的电视上。
- 如果没有任何空间留给其他素材(如纹理、色彩表等),GPU 又怎么能画出像样的东西呢?
- PS1的GPU最多只能绘制640×480像素和16bpp颜色的帧缓冲区。
好吧,那就用16bpp的640x480缓冲区来代替,这样就有424 KB的VRAM用于绘制材质。 到目前为止还不错吧? 同样,这样的分辨率在 CRT 显示器上可能还不错,但在 90 年代每个人家里都有的那种电视上就不那么明显了。 那么,有没有办法优化帧缓冲器呢? 引入可调节的帧缓冲器。

NO$PSX调试器上的VRAM可视化。 您可以看到双帧缓冲区和纹理(使用颜色查找表进行翻译,也存储在这里)。
从本质上讲,该游戏机的GPU不需要通过使用"不受欢迎"的分辨率来浪费宝贵的VRAM,而是允许减少帧缓冲区的尺寸,从而有效地增加其他资源的可用空间。 在"Gears Episode 2"中,Halkun展示了一种将640x480帧缓冲区分为两个320x480帧缓冲区的设置,然后依靠一种名为"翻页"(page-flipping)的技术同时渲染多个场景。
翻页技术包括在游戏需要时,在两个可用的帧之间切换显示位置,使游戏可以在显示一个场景的同时渲染另一个场景。 因此,可以隐藏任何闪烁效果,并改善加载时间(玩家肯定会对此表示赞赏!)。
总体而言,Halkun的布局仅消耗600 KB的VRAM。 剩下的部分(424 KB)可用于存储颜色查找表和纹理,再加上2 KB的纹理缓存,这样的设置非常方便高效。
最后值得一提的是,VRAM可以同时使用多种颜色深度进行映射,这意味着程序员可以在24bpp位图(例如FMV框架使用的位图)旁边分配一个16bpp的帧缓冲区。 这是另一项有利于进一步优化空间的功能。
机密与限制
尽管PS1的架构非常简单合适,但问题还是接踵而至。 令人惊讶的是,某些问题却能通过非常巧妙的变通方法得到解决!
扭曲的模型/纹理

Video - 史克威尔(Square)的最终幻想8(Final Fantasy VIII)(1999) 纹理在移动时会有一些抖动
众所周知,用于处理几何图形和应用纹理的例程存在一些误差。
首先,光栅处理器只能处理像素单位:虽然顶点坐标是整数,但计算出的三角形边缘可能只占一个像素的一小部分。 然而,光栅化器只会在三角形区域覆盖像素采样点的情况下绘制像素,而不会跟踪所占的部分。 这就带来了一些问题:
- 模型的外部边缘在轻微移动时会突然跳动。
- 网格中的三角形(共享相同的顶点和边缘)会"争抢"绘制相同的像素。 有了排序表,GPU将按照"先到先得"的原则进行绘制,这可能会导致三角形交叉点在轻微移动时闪烁或重叠。
解决这一问题的方法通常是采用亚像素分辨率(sub-pixel resolution),光栅化器从中跟踪每个三角形区域所占像素的分数。 因此,可以添加抗锯齿方法来缓和锯齿状边缘或颜色的突然变化。
接着,排序表要求开发人员/程序按照正确的顺序显示几何图形。 在某些情况下,为了提高性能,执行的计算依赖于过多的近似值。 这可能会导致本应显示的表面闪烁或被遮挡。
此外,设置低分辨率的帧缓冲区可能会放大所有这些混叠问题。
最后,正如大家所知,仿射变换没有深度感,当摄像机靠近模型并垂直于观看者时,用户的感知可能会被混淆。 这种效果也被称为纹理扭曲(texture warping)。 因此,一些游戏采用了曲面细分(将大多边形分割成小多边形)来减少失真,而另一些游戏则直接交换纹理,改用纯色。 一般来说,GPU最终会通过实现透视校正来解决这一问题,即使用深度值对纹理进行插值。
自相矛盾的主张
如果你查看其他技术频道或论坛,你会发现关于PS1摇摆/扭曲/失真效果的其他解释。 其中一些与我之前的解释不谋而合,而另一些则会提出不同的观点。 因此,我想就以下说法不准确的原因谈谈我的看法:
模型/纹理晃动是因为缺少FPU
FPU 并不决定计算机是否能进行小数运算。 PS1和其他没有FPU的计算机一样,仍然可以进行定点运算。 此外,使用软件仿真,浮点数也可以计算(只是速度较慢)。 总之,FPU只是加速器,不要将其与ALU(算术逻辑单元,CPU中执行算术运算的关键部分)或十进制数混为一谈。
GPU 的整数坐标系导致模型/纹理晃动
采用整数坐标系是降低GPU计算成本的常用方法。 正是因为没有采用亚像素分辨率,这才成为一个显而易见的问题。 总而言之,如果光栅处理器能够计算三角形所占像素的比例,那么就可以使用抗锯齿技术来平滑色彩的突然变化。
缺乏混合映射导致纹理扭曲
实施反纹理映射的GPU(如本机)会出现一种称为"欠采样"的测量误差(一个像素被映射到多个纹理)。 因此,这会产生混叠(错误的结果)。 在渲染距离摄像机较远的几何体时,这种现象非常明显。 为了解决这个问题,现代纹理贴图程序采用了"三线性过滤"技术,即使用存储在不同比例的相同纹理软化色元(mipmaps),并在两者之间进行一些插值。 总而言之,mipmapping是一种解决混叠问题的方法。 它是一种仿射纹理贴图(缺乏透视校正),在三点表面上进行纹理插值,而不考虑深度。 因此会产生"扭曲"效果。
缺乏Z缓冲导致模型/纹理闪烁
带有Z缓冲的GPU可在硬件层面上解决可见表面的确定问题。 PS1依赖于排序表,这意味着开发人员负责确定哪些几何体位于其他几何体之前。 总之,任何显示闪烁三角形的模型都是由排序例程(软件)引起的,因此可以通过相同的软件来解决。
预渲染的图形

史克威尔的最终幻想7(Final Fantasy VII) (1997) 预渲染背景的场景。 模型的互动和移动方式对于_欺骗_用户的感知至关重要。
现在让我们来谈谈"好"的功能...
如果一款游戏想要获得比GPU所能提供的更逼真的场景,一个可行的办法就是堆叠两个三角形,然后使用运动解码器在上面输入预渲染的电影画面。 FMV视频会占用大量空间,幸好CD-ROM为此做了准备。
有些游戏专门依靠它来合成背景,而且老实说,在显像管电视上看这些视频还是很有说服力的,但显然,具有升分辨率功能的现代模拟器很快就能分辨出来。
视频输出
该控制台的第一版带有以下端口,可传输数量惊人的视频信号:
- RFU DC:这个接口很快就被移除了,它本来是用来连接射频调制器的。
- RCA:提供复合视频接口。
- S-Video:提供Luma+Sync(组合)和Chroma。
- AV多路输出: 提供除RFU以外的所有前述信号,以及RGB和一条5V+电源线。
后来的控制台改版取消了这些端口,最后只剩下 "AV多路输出"。





