Java でgluPerspectiveを複製しましたが、結果の行列をベクトルに適用すると、出力 z が 0.5 を超えることはありません (わずかな浮動小数点エラーを除いて)。ただし、0 (-z = zNear) から 1 (-z = zFar) の間である必要があります。
この関数の単体テストはどこかにあるので、実装が特定の入力に対して既知の正しい出力と一致するかどうかをテストできますか? それとも、この質問は誤った仮定に基づいているのでしょうか? z は 0 から 0.5 の間で問題ありませんか?
または、エラーを見つけることができますか?
/**
* @param fov the vertical viewing angle. This is the angle, in degrees, from the top of the screen to the bottom.
* @param aspect The aspect ratio, which controls the horizontal viewing angle relative to the vertical. We could imagine a variable fovx = aspect × fovy. For a non-stretched perspective, aspect should be the ratio of the screen width to height. For example, on a 640×480 display, aspect should be 4/3.
* @param near The inverted z coordinate of the near clipping plane.
* @param far The inverted z coordinate of the far clipping plane.
*/
public static Matrix4d create(double fov, double aspect, double near, double far) {
Preconditions.checkArgument(near > 0);
Preconditions.checkArgument(far > 0);
Preconditions.checkArgument(far < Double.POSITIVE_INFINITY);
double top = near * Math.tan(fov * Math.PI / 360.0);
double right = top * aspect;
double left = -right;
double bottom = -top;
return Matrix4d.create(
(2.0 * near) / (right - left), 0, 0, 0,
0, (2.0 * near) / (top - bottom), 0, 0,
(right + left) / (right - left), (top + bottom) / (top - bottom), (-far - near) / (far - near), -1.0,
0, 0, (-(2.0 * near) * far) / (far - near), 0
);
}
要求に応じて、行列とベクトルの乗算コードを次に示します。
public Vector3d multiplied(Vector3d other) {
final double r[] = new double[4]; // x, y, z, w
for (int lRow = 0; lRow < 4; lRow++) {
// calculate the dot product of the left row and the right vector
double dp =
(this.get(0, lRow) * other.x) +
(this.get(1, lRow) * other.y) +
(this.get(2, lRow) * other.z) +
(this.get(3, lRow) * 1);
r[lRow] = dp;
}
final double w = r[3];
if (w != 1) {
for (int i = 0; i < 3; i++) {
r[i] = r[i] / w;
}
}
return new Vector3d(r[0], r[1], r[2]);
}
ここにいくつかの数字があります:
fov 90, aspect 1.7777777777777777, near 1, far 1000
perspective:
0.5625000000000001, 0.0, 0.0, 0.0
0.0, 1.0000000000000002, 0.0, 0.0
0.0, 0.0, -1.002002002002002, -1.0
0.0, 0.0, -2.002002002002002, 0.0
IN OUT
outside clipping area
[0.0, 0.0, 0.0] [NaN, NaN, -Infinity]
[0.0, 0.0, -0.5] [0.0, 0.0, -0.4985]
[0.0, 0.0, -2000.0] [0.0, 0.0, 0.5002502499999999]
on clipping edges
[0.0, 0.0, -1.0] [0.0, 0.0, 9.999999999999775E-4]
[0.0, 0.0, -1000.0] [0.0, 0.0, 0.5000005]
centered
[0.0, 0.0, -2.0] [0.0, 0.0, 0.25075]
[0.0, 0.0, -4.0] [0.0, 0.0, 0.37562499999999993]
[0.0, 0.0, -20.0] [0.0, 0.0, 0.475525]
[0.0, 0.0, -40.0] [0.0, 0.0, 0.4880125]
[0.0, 0.0, -80.0] [0.0, 0.0, 0.49425625]
to the right
[100.0, 0.0, -20.0] [1.4048437500000004, 0.0, 0.475525]
[100.0, 0.0, -40.0] [0.7024218750000002, 0.0, 0.4880125]
to the left
[-100.0, 0.0, -20.0] [-1.4048437500000004, 0.0, 0.475525]
[-100.0, 0.0, -40.0] [-0.7024218750000002, 0.0, 0.4880125]
1 to the top
[0.0, -10.0, -10.0] [0.0, -0.4995000000000001, 0.45055]