投影变换
第六章投影相机模型中讲到,其利用持有一系列变换矩阵来简化在相机和视口之间采样的转换。但其中关于投影变换矩阵的推导,与我以往在别的书籍资料中看到的都不太一样。
中默认就是左手坐标系,其正交投影矩阵的目的是将视体变换为近平面为 ,远平面为 的范围,因此其变换的过程为:
- 一次平移变换将近平面 变换到 处。
- 经过前面的变换,远平面 被平移到了 处。再进行一次缩放变换,将远平面 压缩到 ,对于 坐标没做任何的平移和缩放操作。
Scale(1, 1, 1 / (f - n)) * Translate({0, 0, -n});
其他资料中的推导,一般是经过投影变换到齐次裁剪空间,再经过透视除法到 空间。 空间是一个取值范围在 的立方体,且视体中心位于坐标原点,而 中视体经过正交投影变换后还不是 空间。
在 中,经过投影变换后,视体 坐标范围是 。
- 根据分辨率计算出宽高比。
- 如果宽比高长,则高的取值范围为 ,宽的取值范围为 。
- 如果高比宽长,则高的取值范围为 ,宽的取值范围为 。
float aspect = float(film->resolution.x) / float(film->resolution.y);
Bounds2f screen;
if(aspect > 1.0f){
screen = Bounds2f(Point2f(-aspect, -1.0f), Point2f(aspect, 1.0f))
} else{
screen = Bounds2f(Point2f(-1.0f, -1.0f / aspect), Point2f(1.0f, 1.0f / aspect));
}
栅格空间
的相机中持有了屏幕空间到栅格空间的变换 ,也就是说 定义经过投影变换后就是屏幕空间。注意, 中的 空间的近平面左上角为原点,且边长为 ,而不是其他常见资料里中心为原点、边长实际为 、取值范围在 的标准立方体。
- 进行一次平移变换,将视体的近平面左上角变换到原点。
- 进行一次缩放变换将视体变换为边长为 的立方体,即归一化
- 再一次缩放变换将归一化后的 空间下的视体,变换到分辨率的倍数,即栅格化空间。
变换到栅格空间后,极大的简化了对屏幕像素采样点的计算,我们只需要在需要的时候对点或者向量进行相应的变换即可。因此 还存储了一系列的逆变换,以方便计算。
rasterToScreen = Inverse(screenToRaster);
rasterToCamera = Inverse(cameraToScreen) * rasterToScreen;
- 在栅格空间里采样点,将该点从栅格空间变换回相机空间:。
- 再在相机空间与坐标系原点组成方向并生成射线。
- 再将相机空间下的射线转为世界空间:。
Point3f origin = Point3f(0, 0, 0);
Point3f pCamera = rasterToCamera.TransPoint(Point3f(sample.x, sample.y, 0));
Vector3f dir = Normalize(pCamera - origin);
return cameraToWorld.TransRay(origin, dir);
注:代码是参考pbrt到自制软渲染器中后的代码,并非pbrt的源代码,仅供参考。