编辑:这是一些代码,与最初发布的代码相比大大减少了,因为它省略了 viewMatrix 的创建。这仅在某些扫描线渲染中需要,而不用于光线追踪。
艰苦的工作是lookat() 函数,特别是创建“上”和“右”向量。它们必须相互垂直,并且还必须垂直于眼睛和图片中心之间的矢量。这些向量的创建依赖于叉积向量函数。
投射光线的实际函数假定屏幕视口在 Y 方向上从 -0.5 运行到 +0.5。该函数非常简单,只需将“视图”、“向上”和“右”向量的正确比例相加。
public class Camera {
protected Point3d eye;
protected Point3d center;
protected Vector3d up;
protected Vector3d right;
protected Vector3d view;
protected double fovy; // half FoV in radians
protected double tanf;
protected double aspect;
public Ray castRay(double x, double y) {
Vector3d dir = new Vector3d(view);
Vector3d t = new Vector3d();
t.scale(tanf * x * aspect, right);
dir.add(t);
t.scale(tanf * y, up);
dir.add(t);
dir.normalize();
return new Ray(eye, dir);
}
/* algorithm taken from gluLookAt */
public void lookAt(Point3d _eye, Point3d _center, Vector3d _up) {
eye = new Point3d(_eye);
center = new Point3d(_center);
Vector3d u = new Vector3d(_up);
Vector3d f = new Vector3d(center);
f.sub(eye);
f.normalize();
Vector3d s = new Vector3d();
u.normalize();
s.cross(f, u);
s.normalize();
u.cross(s, f);
view = new Vector3d(f);
right = new Vector3d(s);
up = new Vector3d(u);
}
/* algorithm taken from gluPerspective */
public void setfov(double _fovy, double _aspect)
{
fovy = Math.toRadians(_fovy) / 2.0;
tanf = Math.tan(fovy);
aspect = _aspect;
}
}