Japanese | English | Korean

Samples


시추대(視錐台) 컬링

미리 화면 외의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 aspect;          /* 어스펙트비 */
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 =
player->position.x - ( cam_frame->dir.x - cam_frame->pos.x );
camera_pos.y =
player->position.y - ( cam_frame->dir.y - cam_frame->pos.y );
camera_pos.z =
player->position.z - ( cam_frame->dir.z - cam_frame->pos.z );


/* 초점 거리 , 어스펙트비의 계산 */
focus =
( OEMC_Micro3D_Util3D_sin12( cam_frame->angle ) << 12 )
/ OEMC_Micro3D_Util3D_cos12( cam_frame->angle );
aspect = ( VRAM_HEIGHT << 12 ) / VRAM_WIDTH;

시추대의 각 평면의 법선 벡터를 계산합니다. 근평면과 원평면에 대해서는 방향이 반대로 될 뿐이기 때문에 근평면 쪽만 요구하고 있습니다.(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 )
return HI_TRUE;

/* 원평면 */
if( cam_frame->z_far - dot - cam_frame->pos.z < -sphere->r )
return HI_TRUE;

/* 좌평면 */
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 )
return HI_TRUE;

/* 우평면 */
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 )
return HI_TRUE;

/* 하평면 */
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 )
return HI_TRUE;

/* 상평면 */
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_TRUE;

return HI_FALSE;
}