0

我正在为一个学术项目从头开始实施透视图。我正在使用 Foley、van Dam、Feiner 和 Hughes 撰写的“计算机图形学:原则和实践”(C 语言第二版)。

我只是按照这本书实现了平移、旋转、剪切、缩放、投影、从透视转换到平行规范视图体积和裁剪所需的所有矩阵转换。这本书显然使用右手坐标系。但是,我最终发现图元出现在左手坐标系中,我无法解释原因。

这是我使用的矩阵:

Translation:
1, 0, 0, dx
0, 1, 0, dy
0, 0, 1, dz
0, 0, 0, 1

Rotation (to align a coordinate system (rx, ry, rz) to XYZ):
rx1, rx2, rx3, 0
ry1, ry2, ry3, 0
rz1, rz2, rz3, 0
0  , 0  , 0  , 1

Scale:
sx, 0 , 0 , 0
0 , sy, 0 , 0
0 , 0 , sz, 0
0 , 0 , 0 , 1

Shear XY:
1, 0, shx, 0
0, 1, shy, 0
0, 0, 1  , 0
0, 0, 0  , 1

Projecting onto a plane at z = d, with PRP at origin, looking in the positive z direction:
1, 0, 0  , 0
0, 1, 0  , 0
0, 0, 1  , 0
0, 0, 1/d, 0

然后给定 VRP、VPN、PRP、VUP、f 和 b(以及投影 dop 的方向),使用 P 将空间缩小到用于透视的规范观察体积:

rz = VPN / |VPN|
rx = (VUP x rz) / |VUP x rz|
ry = rz x rx
P = ScaleUniform(-1 / (vrp1Z + b)) * 
    Scale(-2 * vrp1Z / deltaU, -2 * vrp1Z / deltaV, 1) * 
    Shear(-dopX / dopZ, -dopY / dopZ) * 
    T(PRP) * 
    R(rx, ry, rz) * 
    T(-VRP)

其中 vrp1 是 ShearXY * T(-PRP) * (0, 0, 0, 1),deltaU 和 deltaV 是观察窗口的宽度和高度。dop 计算为 CW - PRP,其中 CW 是观察窗口的中心。

然后 Projection(d) * P 给了我投影矩阵。

我在 x、y 和 z 上投影了表示单位向量的简单线,但我在屏幕上绘制的表示显然是左手坐标系......现在我需要在右手坐标系中工作,所以有吗一种知道我哪里做错的方法?

这是我使用的代码:如您所见,比例矩阵的 Z 分量的符号相反,因为裁剪无法正常工作,因为有些东西是右手的,有些东西是左手的,但我无法辨别什么确切地说,所以我交换了刻度的符号,因为在左手系统中不需要它。

Vector rz = vpn.toUnitVector();
Vector rx = vup.cross(rz).toUnitVector();
Vector ry = rz.cross(rx).toUnitVector(); 

Vector cw  = viewWindow.getCenter();
Vector dop = cw - prp;

Matrix t1 = Matrix::traslation(-vrp[X], -vrp[Y], -vrp[Z]);
Matrix r  = Matrix::rotation(rx, ry, rz);   
Matrix t2 = Matrix::traslation(-prp[X], -prp[Y], -prp[Z]);   
Matrix partial = t2 * r * t1;

Matrix shear  = Matrix::shearXY(-dop[X] / dop[Z], -dop[Y] / dop[Z]);
Matrix inverseShear = Matrix::shearXY(dop[X] / dop[Z], dop[Y] / dop[Z]);

Vector vrp1 = shear * t2 * Vector(0, 0, 0, 1);

Matrix scale = Matrix::scale(
    2 * vrp1[Z] / ((viewWindow.xMax - viewWindow.xMin) * (vrp1[Z] + b)),
    2 * vrp1[Z] / ((viewWindow.yMax - viewWindow.yMin) * (vrp1[Z] + b)),
    1 / (vrp1[Z] + b)); // HERE <--- WAS NEGATIVE
Matrix inverseScale = Matrix::scale(
    ((viewWindow.xMax - viewWindow.xMin) * (vrp1[Z] + b)) / (2 * vrp1[Z]),
    ((viewWindow.yMax - viewWindow.yMin) * (vrp1[Z] + b)) / (2 * vrp1[Z]),
    (vrp1[Z] + b));

float zMin = -(vrp1[Z] + f) / (vrp1[Z] + b);

Matrix parallel = Perspective::toParallelCvv(zMin);
Matrix inverseParallel = Perspective::inverseToParallelCvv(zMin);
Matrix perspective = Perspective::copAtOrigin(-vrp1[Z]);

projection = perspective * shear * partial;
canonicalView = parallel * scale * shear * partial;
canonicalToProjection = perspective * inverseScale * inverseParallel;
4

0 回答 0