一个用来实现视景体的功能的类已经在下面呈现出来了。注意下面的代码并没有任何方面的优化,它仅仅只是用来伴随本课程出现的。这个类包含六个平面的数组,加上其他变量比如说视景体的八个顶点和相机的定义参数。平面只是用来裁剪操作,但是保存变量对我们的调试有用并且可视化的目的。
类的头文件如下:
class FrustumG {
private:
enum {
TOP = 0, BOTTOM, LEFT,
RIGHT, NEARP, FARP
};
public:
static enum {OUTSIDE, INTERSECT, INSIDE};
Plane pl[6];
Vec3 ntl,ntr,nbl,nbr,ftl,ftr,fbl,fbr;
float nearD, farD, ratio, angle,tang;
float nw,nh,fw,fh;
FrustumG::FrustumG();
FrustumG::~FrustumG();
void setCamInternals(float angle, float ratio, float nearD, float farD);
void setCamDef(Vec3 &p, Vec3 &l, Vec3 &u);
int pointInFrustum(Vec3 &p);
int sphereInFrustum(Vec3 &p, float raio);
int boxInFrustum(AABox &b);
};
这个函数的参数跟gluPerspective的参数是一样的。每一个透视投影的变换,实际上当窗口改变时,这个函数应该也被调用。
#define ANG2RAD 3.14159265358979323846/180.0
void FrustumG::setCamInternals(float angle, float ratio, float nearD, float farD) {
// store the information
this->ratio = ratio;
this->angle = angle;
this->nearD = nearD;
this->farD = farD;
// compute width and height of the near and far plane sections
tang = (float)tan(ANG2RAD * angle * 0.5) ;
nh = nearD * tang;
nw = nh * ratio;
fh = farD * tang;
fw = fh * ratio;
}
这个函数保存了所有的信息,然后计算了用nh(近平面高度),nw(近平面宽度),fh(远平面高度)和fw(远平面宽度)来计算近平面和远平面的矩形高度和宽度。
这个函数包含三个vector3来包含函数gluLookAt的信息:相机的位置,一个用来表示指向相机朝向的点和一个向上的向量。每当相机位置或者方向改变了,这个函数应该被调用。
void FrustumG::setCamDef(Vec3 &p, Vec3 &l, Vec3 &u) {
Vec3 dir,nc,fc,X,Y,Z;
// compute the Z axis of camera
// this axis points in the opposite direction from
// the looking direction
Z = p - l;
Z.normalize();
// X axis of camera with given "up" vector and Z axis
X = u * Z;
X.normalize();
// the real "up" vector is the cross product of Z and X
Y = Z * X;
// compute the centers of the near and far planes
nc = p - Z * nearD;
fc = p - Z * farD;
// compute the 4 corners of the frustum on the near plane
ntl = nc + Y * nh - X * nw;
ntr = nc + Y * nh + X * nw;
nbl = nc - Y * nh - X * nw;
nbr = nc - Y * nh + X * nw;
// compute the 4 corners of the frustum on the far plane
ftl = fc + Y * fh - X * fw;
ftr = fc + Y * fh + X * fw;
fbl = fc - Y * fh - X * fw;
fbr = fc - Y * fh + X * fw;
// compute the six planes
// the function set3Points assumes that the points
// are given in counter clockwise order
pl[TOP].set3Points(ntr,ntl,ftl);
pl[BOTTOM].set3Points(nbl,nbr,fbr);
pl[LEFT].set3Points(ntl,nbl,fbl);
pl[RIGHT].set3Points(nbr,ntr,fbr);
pl[NEARP].set3Points(ntl,ntr,nbr);
pl[FARP].set3Points(ftr,ftl,fbl);
}
这个函数计算了视景体的八个顶点和在前面一节介绍的六个平面。
下面(更有效的)也可以用来计算上面提到的八个点和六个平面的方法:
pl[NEARP].setNormalAndPoint(-Z,nc);
pl[FARP].setNormalAndPoint(Z,fc);
Vec3 aux,normal;
aux = (nc + Y*nh) - p;
aux.normalize();
normal = aux * X;
pl[TOP].setNormalAndPoint(normal,nc+Y*nh);
aux = (nc - Y*nh) - p;
aux.normalize();
normal = X * aux;
pl[BOTTOM].setNormalAndPoint(normal,nc-Y*nh);
aux = (nc - X*nw) - p;
aux.normalize();
normal = aux * Y;
pl[LEFT].setNormalAndPoint(normal,nc-X*nw);
aux = (nc + X*nw) - p;
aux.normalize();
normal = Y * aux;
pl[RIGHT].setNormalAndPoint(normal,nc+X*nw);
英文地址