Frustum Culling은 많이 공개되어서 특별한 것은 없지만 단지 Directx와 Opengl에서 구현할 때 행렬문제로 인해 실수가 경우가 많다. 그래서 OpenGL 구현코드를 직접 적는다.
행렬을 아래와 같이 정의한다. t_를 붙인 이유는 보통 행행렬을 많이 사용하지만 OpenGL에서는 열행렬이기 때문에 transpose라는 의미에서 t_라고 붙였다.
struct TMATRIX16
- {
- union
- {
- struct { float t_m11,t_m21,t_m31,t_m41;
- float t_m12,t_m22,t_m32,t_m42;
- float t_m13,t_m23,t_m33,t_m43;
- float t_m14,t_m24,t_m34,t_m44;
- };
- float m_MX[16];
- };
- };
현재 세팅된 Projection Matrix와 ModelViewMatrix를 가져온다.
- TMATRIX16 mxModelView, mxProjView;
- ::glGetFloatv(GL_MODELVIEW_MATRIX,mxModelView.m_MX); ::glGetFloatv(GL_PROJECTION_MATRIX,mxProjView.m_MX);
많이 실수한 경우인데
Frustum Matrix = ModelView Matrix * Projection Matrix 순서로 해야 한다.
이 순서를 바꾸어서 하는 바람에 Culling계산이 잘 안되는 원인을 찾기 힘들었다.
TMATRIX16 mxFrustum; MultiMatrix(mxModelView, mxProjView, mxFrustum);
Frustum 의 면을 정의한다.
typedef struct tagFrustumPlane
{
union
{
struct
{
float x;
float y;
float z;
float d;
};
float _m[4];
};
} FRUSTUM_PLANE;
typedef enum emViewPlane
{
VP_LEFT,
VP_RIGHT,
VP_TOP,
VP_BOTTOM,
VP_NEAR,
VP_FAR,
};
6면을 계산한다.
_Plans[VP_LEFT].x=mxFrustum.t_m41+mxFrustum.t_m11; _Plans[VP_LEFT].y=mxFrustum.t_m42+mxFrustum.t_m12; _Plans[VP_LEFT].z=mxFrustum.t_m43+mxFrustum.t_m13; _Plans[VP_LEFT].d=mxFrustum.t_m44+mxFrustum.t_m14; _Plans[VP_RIGHT].x=mxFrustum.t_m41-mxFrustum.t_m11; _Plans[VP_RIGHT].y=mxFrustum.t_m42-mxFrustum.t_m12; _Plans[VP_RIGHT].z=mxFrustum.t_m43-mxFrustum.t_m13; _Plans[VP_RIGHT].d=mxFrustum.t_m44-mxFrustum.t_m14;// _Plans[VP_TOP].x=mxFrustum.t_m41-mxFrustum.t_m21; _Plans[VP_TOP].y=mxFrustum.t_m42-mxFrustum.t_m22; _Plans[VP_TOP].z=mxFrustum.t_m43-mxFrustum.t_m23; _Plans[VP_TOP].d=mxFrustum.t_m44-mxFrustum.t_m24;
_Plans[VP_BOTTOM].x=mxFrustum.t_m41+mxFrustum.t_m21; _Plans[VP_BOTTOM].y=mxFrustum.t_m42+mxFrustum.t_m22; _Plans[VP_BOTTOM].z=mxFrustum.t_m43+mxFrustum.t_m23; _Plans[VP_BOTTOM].d=mxFrustum.t_m44+mxFrustum.t_m24;
_Plans[VP_NEAR].x=mxFrustum.t_m41+mxFrustum.t_m31; _Plans[VP_NEAR].y=mxFrustum.t_m42+mxFrustum.t_m32; _Plans[VP_NEAR].z=mxFrustum.t_m43+mxFrustum.t_m33; _Plans[VP_NEAR].d=mxFrustum.t_m44+mxFrustum.t_m34;
_Plans[VP_FAR].x=mxFrustum.t_m41-mxFrustum.t_m31; _Plans[VP_FAR].y=mxFrustum.t_m42-mxFrustum.t_m32; _Plans[VP_FAR].z=mxFrustum.t_m43-mxFrustum.t_m33; _Plans[VP_FAR].d=mxFrustum.t_m44-mxFrustum.t_m34;
Frustum의 6면을 구하였다. 이제 작업해야 할것은 이 6면이 이루는 Frustum의 공간안에 우리가 그리고자 하는 물체가 포함하는가 아닌가를 판단해야하는 일이다.
제일 기본이 Point(점)이기 때문에 한 점이 Frustum 내부에 있나 외부에 있나만을 확인 할수 있으면 된다. Point(점)만 확인가능하면 Sphere(구), Cubic(직육면체)도 확인할 수 있다.
확인하는 방법은 면과 점의 거리 정확히 얘기하면 면의 앞쪽에 있는지 뒤쪽에 있는지를 확인하면 된다. 즉 면과 점의 거리르 계산해서 +이면 면의 앞쪽에 있는 것이고 -이면 면의 뒤쪽에 있는 것이 된다.
그러므로 Frustum의 6면과 점의 거리를 계산해서 모두 + 이면 Frustum안에 있는 거라고 할 수 있다.
Posted by chungki


