시추대(視錐台) 컬링
미리 화면 외의3D오브젝트를 판정하여 이 오브젝트를 랜더링 처리 함수에 건네주지 않는 것으로 실행 속도의 향상과 랜더링 시에 사용하는 메모리의 절감을 얻을 수 있습니다. 이 수법을 " 시추대 컬링 " 이라고 합니다.
목차
3D오브젝트 단위로 시추대 컬링을 실시하는 메리트에는
- 통상의 폴리곤 단위의 컬링과 비교해서 속도가 향상한다
- 랜더링시에 필요한 메모리가 절감이 된다
- 결과적으로 화면 내에 대량의 3D오브젝트를 랜더링할 수 있다
를 들 수 있습니다

Sample_Culling실행화면
1.시추대(視錐台)
시추대란 3차원 공간상에 있어 디스플레이에 표시되는 영역으로, 카메라를 정상(頂上)으로 하는 사각뿔을 근평면(Near Clip)과 원평면(Far Clip)으로 잘라낸 형태를 하고 있습니다.
시추대의 월드 좌표계에 있어서의 위치 및 크기는 카메라의 위치와 방향, 니어 클립/파 클립 및 화각(앵글)에 의해 결정됩니다. 또, 카메라 좌표계에 있어서는, 시추대는 원점(카메라가 있는 위치)을 정상으로서 카메라가 향하고 있을 방향을 향해서 배치됩니다.
화각을α로 할 때, e = 1 / tan(α/2) 에 의해서 나타내지는 값을 초점 거리라고 합니다. 초점 거리를 e로 하면 카메라 좌표계에 있어 평면 z = e는 시추대의 좌우의 평면과 x =±1로 교차합니다.
디스플레이의 높이를 폭으로 나눈 값을 어스펙트비라고 합니다. 어스펙트비를 a로 하면 카메라 좌표계에 있어서 평면
z = e는 시추대의 상하의 평면과 y =±a로 교차합니다
2.컬링(Culling)
모델을 렌더링 해도 실제로 디스플레이에 표시되는 것은 시추대 내에 있는 모델 뿐입니다. 거기서 미리 각 모델이 시추대 내에 있고 없음을 판정하여 시추대 내에 있는 모델만을 렌더링 하는 것을 생각합니다. 시추대 내에 없는 것을 판별하여 모델을 렌더링 하지 않게 하는 것을 컬링이라고 합니다. 여기에서는 구 형태의 모델에 대한 시추대 컬링에 대해 설명합니다.
구 형태의 모델의 반경을 r로 하여 모델의 위치를 모델의 중심의 위치 벡터로 표시하는 것으로 합니다. 모델이 시추대 내에 있고 없음을 판정하려면 모델이 시추대를 구성하는 6개의 각 평면보다 안쪽에 있을지를 조사합니다. 거기에는, 모델의 위치 벡터와 각 평면의 시추대 내로 향하는 법선(normal) 벡터와의 내적을 취해, 그 값에 시추대 핑면으로부터 카메라의 위치까지의 거리를 더합니다. 그 값이 정(+)이라면 모델의 중심은 시추대내에 있습니다. 값이 부(-)의 경우에서도 그 값이 r보다 크면,
모델의 일부는 시추대 내에 있습니다.
또한 카메라 좌표에 있어 초점 거리를 e, 어스펙트비를 a, 시추대가 있는 방향을 z축 정(正)방향으로 할 때, 시추대의 각 평면의 법선(normal) 벡터는 다음과 같이
- 근평면 : ( 0, 0, 1 )
- 원평면 : ( 0, 0, -1 )
- 좌평면 : ( e, 0, 1 )
- 우평면 : ( -e, 0, 1 )
- 하평면 : ( 0, e, a )
- 상평면 : ( 0, -e, a )
내적을 계산할 때는 이러한 벡터를 정규화할 필요가 있습니다
3.컬링 판정의 샘플 코드
여기에서는 샘플 코드내의 구체 오브젝트에 대한 시추대 컬링의 판정을 하는 함수 checkCulling_sphere에 대해 설명합니다.
이 함수는 플레이어, 컬링 판정 대상이 되는 오브젝트, 및 카메라의 정보로부터 컬링 판정을 실시합니다. 이하와 같은 변수를 준비합니다.
hi_bool checkCulling_Sphere
( Player *player, BSphere *sphere, CameraFrame *cam_frame )
{
hi_sint32 focus; /* 초점 거리 */
Vec3i camera_pos; /* camera 위치 */
/* 시추대 평면 법선 벡터 */
Vec3i clip_dir;
Vec3i left_dir;
Vec3i right_dir;
Vec3i under_dir;
Vec3i up_dir;
hi_sint32 cam_dir; /* 평면에서 카메라 위치까지의 거리 */
hi_sint32 dot; /* 내적 */
카메라 위치 및, 초점 거리, 어스펙트비를 요구합니다. 여기서 VRAM_HEIGHT, VRAM_WIDTH는 각각 디스플레이의 높이와 폭입니다
camera_pos.x =
/* 초점 거리 , 어스펙트비의 계산 */
focus =
/ OEMC_Micro3D_Util3D_cos12( cam_frame->angle );
시추대의 각 평면의 법선 벡터를 계산합니다. 근평면과 원평면에 대해서는 방향이 반대로 될 뿐이기 때문에 근평면 쪽만 요구하고 있습니다.(clip_dir).
clip_dir.x = 0;
clip_dir.y = 0;
clip_dir.z = 1 << 12;
OEMC_Micro3D_Vec3i_normalize12( &clip_dir, &clip_dir );
left_dir.x = focus;
left_dir.y = 0;
left_dir.z = 1 << 12;
OEMC_Micro3D_Vec3i_normalize12( &left_dir, &left_dir );
right_dir.x = -focus;
right_dir.y = 0;
right_dir.z = 1 << 12;
OEMC_Micro3D_Vec3i_normalize12( &right_dir, &right_dir );
under_dir.x = 0;
under_dir.y = focus;
under_dir.z = aspect;
OEMC_Micro3D_Vec3i_normalize12( &under_dir, &under_dir );
up_dir.x = 0;
up_dir.y = -focus;
up_dir.z = aspect;
OEMC_Micro3D_Vec3i_normalize12( &up_dir, &up_dir );
시추대 각 평면과 구 형태 오브젝트의 내포 판정을 실시합니다. dot의 값이 -r이하가 되는 것이 하나라도 있다면 이 오브젝트는 컬링 할 수 있습니다.
/* 근평면 */
dot = OEMC_Micro3D_Vec3i_dot( &clip_dir, &sphere->position );
dot = dot >> 12;
if( dot - cam_frame->z_near - cam_frame->pos.z < -sphere->r )
/* 원평면 */
if( cam_frame->z_far - dot - cam_frame->pos.z < -sphere->r )
/* 좌평면 */
dot = OEMC_Micro3D_Vec3i_dot( &left_dir, &sphere->position );
dot = dot >> 12;
cam_dir = OEMC_Micro3D_Vec3i_dot( &left_dir, &camera_pos );
cam_dir = cam_dir >> 12;
if( dot - cam_dir < -sphere->r )
/* 우평면 */
dot = OEMC_Micro3D_Vec3i_dot( &right_dir, &sphere->position );
dot = dot >> 12;
cam_dir = OEMC_Micro3D_Vec3i_dot( &right_dir, &camera_pos );
cam_dir = cam_dir >> 12;
if( dot - cam_dir < -sphere->r )
/* 하평면 */
dot = OEMC_Micro3D_Vec3i_dot( &under_dir, &sphere->position );
dot = dot >> 12;
cam_dir = OEMC_Micro3D_Vec3i_dot( &under_dir, &camera_pos );
cam_dir = cam_dir >> 12;
if( dot - cam_dir < -sphere->r )
/* 상평면 */
dot = OEMC_Micro3D_Vec3i_dot( &up_dir, &sphere->position );
dot = dot >> 12;
cam_dir = OEMC_Micro3D_Vec3i_dot( &up_dir, &camera_pos );
cam_dir = cam_dir >> 12;
if( dot - cam_dir < -sphere->r )
return HI_FALSE;

