关于Jittering的公式,很多地方只是大概提了一下公式,这是Unity中的实现,使用的公式是:
matrix[0, 2] += offset.x * 2 / horizontal;
matrix[1, 2] += offset.y * 2 / vertical;
具体参考代码(话说这函数定义horizontal,vertical意义不明,可能是为了提高计算精度?)
public static Matrix4x4 GetJitteredPerspectiveProjectionMatrix(Camera camera, Vector2 offset)
{
float near = camera.nearClipPlane;
float far = camera.farClipPlane;
float vertical = Mathf.Tan(0.5f * Mathf.Deg2Rad * camera.fieldOfView) * near;
float horizontal = vertical * camera.aspect;
offset.x *= horizontal / (0.5f * camera.pixelWidth);
offset.y *= vertical / (0.5f * camera.pixelHeight);
var matrix = camera.projectionMatrix;
matrix[0, 2] += offset.x / horizontal;
matrix[1, 2] += offset.y / vertical;
return matrix;
}
现在来分析一下原理:
先不管Jitter的数值是多少,我们把Jitter带入到投影矩阵中
然后计算clip space坐标的差值
因为坐标值只涉及到xy的修改,所以后面都只看xy,下一步是到NDC空间
以及屏幕空间
现在把最初的Jitter数值带入进去
得到最终的差异:
其中Offset的xy介于[-0.5, 0.5]之间,到这一步作用已经很明显了,1除以屏幕分辨率得到的是每个像素的长宽,乘以Offset代表偏移的长度,表示往像素在水平和垂直分别偏移最多0.5个像素。
在很多实现当中,比如https://zhuanlan.zhihu.com/p/138866533,会使用这样的公式
var jitteredProjection = camera.projectionMatrix;
jitteredProjection.m02 += (offset.x * 2 - 1) / camera.pixelWidth;
jitteredProjection.m12 += (offset.x * 2 - 1) / camera.pixelHeight;
区别只是这里的分母多减了1,结果变成了
实际上没有区别,只是这里Offset值域不一样,这里的是[0, 1]