我在Unity 6/URP中重建PS1渲染,直接从psx-spx(硬件文档)中取材,而不是从其他人提供的着色器中。发现了很多人,包括我自己,之前都做错了的事情。分享出来,以便能节省一些时间。

1.顶点抖动不是固定点数学

每个人都说PS1缺乏浮点数导致抖动,但不是这样的。GTE使用16个分数位计算屏幕位置,然后丢弃了它们:SX2 = MAC0 / 0x10000 什么都剩下是有符号的11位整数。GPU的顶点字中没有分数位,顶点X和Y的位数分别是0-10和16-26。所以,顶点抖动必须在透视除法之后发生,在屏幕空间中。很多着色器会在对象或世界位置上进行量化,这导致与距离无关的抖动。实际PS1抖动会随着三角形在屏幕上变小而恶化。

2.抖动过于强大

实际硬件矩阵:

-4 +0 -3 +1 +2 -2 +3 -1 -3 +1 -4 +0 +3 -1 +2 -2

这是±4在256中的值。半个5位的步长。很多包都提供了一个4x4的Bayer矩阵,强度是5到10倍。它也不是Bayer矩阵。第三和第四行是第一和第二行向右移动两像素。它也只应用于Gouraud-着色或纹理调制的多边形。图形和平面着色多边形从来没有抖动,因为没有8位的中间值可以抖动。

3.纹理调制的中性值是128,而不是255

final = (texel * vertexColour) / 128

0x808080是中性值,这意味着顶点颜色可以将表面亮度提高到2倍,而不仅仅是降低它。PS1游戏经常利用这个过亮的一半来制作高光和光焰。使用1.0作为中性值,你会丢弃整个范围。

4.雾是GTE的功能,而不是GPU的功能

雾因素是在透视除法中免费获得的:

IR0 = (H * 0x20000 / SZ3) * DQA + DQB

这使其在1/z中线性,而不是z。与Unity的雾相比,会产生明显不同的衰落效果。它还被折叠到顶点颜色中,因此与现代后纹理雾的相互作用方式不同。惊喜的一点是,纹理值0000h是完全透明的,因此PS1纹理不能包含纯黑色。艺术家使用非常暗的红色或蓝色代替。

所有这些内容都被集成到我正在开发的URP包中,名为True PSX Effects,包括顶点颜色绘制器和光线到顶点颜色烘焐器。因为PS1游戏实际上是通过烘焐光线来照明的。上述所有内容都是从psx-spx.consoledev.net中获得的,如果你想检查我的工作。