Bounding Sphere Frustum Culling 问题
Problem with Bounding Sphere Frustum Culling
下面我将 post 我的截锥体剔除代码用于剔除边界球体。
我的算法应该相当简单易懂:更新方法(称为每帧更新)通过计算平截头体平面的角和相应的法线来更新平截头体的平面。法线应该都指向平截头体的中心。
在 inFrustum 方法中,计算到各个平面的有符号距离,我的想法是,如果一个点到左侧和右侧平面的距离为正,则它必须位于这两个平面之间。对左右、上下和远近进行此操作应确定该点是否可见的天气。只要我转动的角度不超过 180°,就可以正常工作,然后平截头体中的点就会变得不可见。
cam->up 和 cam->dir 是相机的上方向向量和相机视角光线的向量,near, far 和 fov_degree 是对应的投影变量。你知道为什么这不能正常工作吗?这个问题也与凸轮的位置相对应。
class plane{
private:
float a, b, c, d;
public:
void set(glm::vec3 p0, glm::vec3 p1, glm::vec3 p2){
using namespace glm;
vec3 v = p1-p0;
vec3 u = p2-p0;
vec3 n = normalize(cross(v, u));
a = n.x;
b = n.y;
c = n.z;
d = dot(-n, p0);
}
void set(glm::vec3 p, glm::vec3 n){
a = n.x;
b = n.y;
c = n.z;
d = p.x*n.x + p.y*n.y + p.z*n.z;
}
float distanceTo(glm::vec3 p) const{
return a*p.x + b*p.y + c*p.z + d;
}
};
class frustumCulling{
private:
plane front, back, left, right, top, bottom;
public:
frustumCulling(Camera& cam){
update(cam);
}
void update(Camera& cam){
using namespace glm;
vec3 ndir = normalize(cam->dir);
vec3 nup = normalize(cam->up);
vec3 nright = normalize(cross(cam->dir, cam->up));
//aligned planes
vec3 onn = cam->pos + ndir*cam->near;
vec3 onf = cam->pos + ndir*cam->far;
front.set(onn, ndir);
back.set(onf, -ndir);
//far and near dimensions
vec2 fardim = vec2(0.0f, cam->far*tan(radians(cam->fov_degree/2.0f)));
fardim.x= fardim.y*cam->aspect_ratio();
vec2 neardim = vec2(0.0f, cam->near*tan(radians(cam->fov_degree/2.0f)));
neardim.x = neardim.y*cam->aspect_ratio();
//view frustum corners //l = left, r = right, u = up, b=bottom, n= near, f = far
vec3 n_lu = onn + nup*neardim.y*0.5f - nright*neardim.x*0.5f;
vec3 n_ru = onn + nup*neardim.y*0.5f + nright*neardim.x*0.5f;
vec3 n_rb = onn - nup*neardim.y*0.5f + nright*neardim.x*0.5f;
vec3 n_lb = onn - nup*neardim.y*0.5f - nright*neardim.x*0.5f;
vec3 f_lu = onf + nup*fardim.y*0.5f - nright*fardim.x*0.5f;
vec3 f_ru = onf + nup*fardim.y*0.5f + nright*fardim.x*0.5f;
vec3 f_rb = onf - nup*fardim.y*0.5f + nright*fardim.x*0.5f;
vec3 f_lb = onf - nup*fardim.y*0.5f - nright*fardim.x*0.5f;
//non aligned planes
vec3 leftn = normalize(cross(n_lb-n_lu, f_lu-n_lu));
left.set(n_lu, leftn);
vec3 rightn = normalize(cross(n_ru-n_rb, f_rb-n_rb));
right.set(n_ru, rightn);
vec3 topn = normalize(cross(n_lu - n_ru, f_ru - n_ru));
top.set(n_ru, topn);
vec3 botn = normalize(cross(f_rb - n_rb, n_lb - n_rb));
bottom.set(n_rb, topn);
}
bool inFrustum(glm::vec3 p, float radius){
float dt = top.distanceTo(p);
float db = bottom.distanceTo(p);
float dl = left.distanceTo(p);
float dr = right.distanceTo(p);
float df = front.distanceTo(p);
float dn = back.distanceTo(p);
bool ix, iy, iz;
ix = (dl > 0 && dr > 0) || glm::abs(dl) <= radius || glm::abs(dr) <= radius;
iy = (dt > 0 && db > 0) || glm::abs(dt) <= radius || glm::abs(db) <= radius;
iz = (df > 0 && dn > 0) || glm::abs(df) <= radius || glm::abs(dn) <= radius;
//just for debugging; should be ix&&iy&&iz
return ix;
}
};
我解决了问题是集合中的 d = p.x*n.x + p.y*n.y + p.z*n.z;
,它应该是 dot(-n, p)
而不是我 dot(n,p)
下面我将 post 我的截锥体剔除代码用于剔除边界球体。 我的算法应该相当简单易懂:更新方法(称为每帧更新)通过计算平截头体平面的角和相应的法线来更新平截头体的平面。法线应该都指向平截头体的中心。
在 inFrustum 方法中,计算到各个平面的有符号距离,我的想法是,如果一个点到左侧和右侧平面的距离为正,则它必须位于这两个平面之间。对左右、上下和远近进行此操作应确定该点是否可见的天气。只要我转动的角度不超过 180°,就可以正常工作,然后平截头体中的点就会变得不可见。 cam->up 和 cam->dir 是相机的上方向向量和相机视角光线的向量,near, far 和 fov_degree 是对应的投影变量。你知道为什么这不能正常工作吗?这个问题也与凸轮的位置相对应。
class plane{
private:
float a, b, c, d;
public:
void set(glm::vec3 p0, glm::vec3 p1, glm::vec3 p2){
using namespace glm;
vec3 v = p1-p0;
vec3 u = p2-p0;
vec3 n = normalize(cross(v, u));
a = n.x;
b = n.y;
c = n.z;
d = dot(-n, p0);
}
void set(glm::vec3 p, glm::vec3 n){
a = n.x;
b = n.y;
c = n.z;
d = p.x*n.x + p.y*n.y + p.z*n.z;
}
float distanceTo(glm::vec3 p) const{
return a*p.x + b*p.y + c*p.z + d;
}
};
class frustumCulling{
private:
plane front, back, left, right, top, bottom;
public:
frustumCulling(Camera& cam){
update(cam);
}
void update(Camera& cam){
using namespace glm;
vec3 ndir = normalize(cam->dir);
vec3 nup = normalize(cam->up);
vec3 nright = normalize(cross(cam->dir, cam->up));
//aligned planes
vec3 onn = cam->pos + ndir*cam->near;
vec3 onf = cam->pos + ndir*cam->far;
front.set(onn, ndir);
back.set(onf, -ndir);
//far and near dimensions
vec2 fardim = vec2(0.0f, cam->far*tan(radians(cam->fov_degree/2.0f)));
fardim.x= fardim.y*cam->aspect_ratio();
vec2 neardim = vec2(0.0f, cam->near*tan(radians(cam->fov_degree/2.0f)));
neardim.x = neardim.y*cam->aspect_ratio();
//view frustum corners //l = left, r = right, u = up, b=bottom, n= near, f = far
vec3 n_lu = onn + nup*neardim.y*0.5f - nright*neardim.x*0.5f;
vec3 n_ru = onn + nup*neardim.y*0.5f + nright*neardim.x*0.5f;
vec3 n_rb = onn - nup*neardim.y*0.5f + nright*neardim.x*0.5f;
vec3 n_lb = onn - nup*neardim.y*0.5f - nright*neardim.x*0.5f;
vec3 f_lu = onf + nup*fardim.y*0.5f - nright*fardim.x*0.5f;
vec3 f_ru = onf + nup*fardim.y*0.5f + nright*fardim.x*0.5f;
vec3 f_rb = onf - nup*fardim.y*0.5f + nright*fardim.x*0.5f;
vec3 f_lb = onf - nup*fardim.y*0.5f - nright*fardim.x*0.5f;
//non aligned planes
vec3 leftn = normalize(cross(n_lb-n_lu, f_lu-n_lu));
left.set(n_lu, leftn);
vec3 rightn = normalize(cross(n_ru-n_rb, f_rb-n_rb));
right.set(n_ru, rightn);
vec3 topn = normalize(cross(n_lu - n_ru, f_ru - n_ru));
top.set(n_ru, topn);
vec3 botn = normalize(cross(f_rb - n_rb, n_lb - n_rb));
bottom.set(n_rb, topn);
}
bool inFrustum(glm::vec3 p, float radius){
float dt = top.distanceTo(p);
float db = bottom.distanceTo(p);
float dl = left.distanceTo(p);
float dr = right.distanceTo(p);
float df = front.distanceTo(p);
float dn = back.distanceTo(p);
bool ix, iy, iz;
ix = (dl > 0 && dr > 0) || glm::abs(dl) <= radius || glm::abs(dr) <= radius;
iy = (dt > 0 && db > 0) || glm::abs(dt) <= radius || glm::abs(db) <= radius;
iz = (df > 0 && dn > 0) || glm::abs(df) <= radius || glm::abs(dn) <= radius;
//just for debugging; should be ix&&iy&&iz
return ix;
}
};
我解决了问题是集合中的 d = p.x*n.x + p.y*n.y + p.z*n.z;
,它应该是 dot(-n, p)
而不是我 dot(n,p)