サンプル

視錐台による可視判定

MCX Collision Package では視錐台を利用した可視判定を行うことが可能です。可視判定には mcxViewVolume 構造体を使用します。

視錐台による可視判定




目次


注意:本サンプルでは説明の都合上、描画に対する効率化を行なっておりません。特にバウンディングボリューム ( BV ) に対応するメッシュの描画は実行速度を低下させる恐れがあります。これはバウンディングボリュームに対する Mesh はあくまでもデバッグ用であり、描画速度よりも形状の精度を優先してあるためです。




1. ViewVolume の作成と視錐台の設定

ViewVolume の作成には mcx_ViewVolume_create 関数を使用します。

/* ViewVolume オブジェクトの生成 */
pmcx -> pViewVol = IMICRO3Dv4es_mcx_ViewVolume_createf ( pMe -> pIM3D, pMe -> pAlc, &pMe -> e );

次に視錐台の設定ですが、投影法・カメラの設定によっていくつかの関数が存在します。V4 では mcx_ViewVolume_setPerspectiveViewFromAspect 関数の使用を推奨しています。そのため、ここでは上記の関数によるアスペクト比を利用した設定を行います。
なお、このとき ViewVolume に設定する視錐台はカメラと同一のものとする必要があります。

/**
* float camPrj [ 4 ];
*/


/* アクティブカメラの投影パラメータを取得 */
IMICRO3Dv4es_m3dCamera_getProjection_pr ( pMe -> pIM3D, pmc -> pCamera, camPrj );

/* ViewVolume に視錐台を登録 */
IMICRO3Dv4es_mcx_ViewVolume_setPerspectiveViewFromAspectf (
pMe -> pIM3D, pmcx -> pViewVol, camPrj [ FOVY ] , camPrj [ ASP_RATIO ] ,
camPrj [ NEAR ] , camPrj [ FAR ] , &pMe -> e );

さらに、視錐台に対してカメラ座標への変換行列を設定します。変換行列の設定は mcx_ViewVolume_setTransform 関数を使用します。 このとき設定する変換行列は、ワールド座標からカメラ座標への変換行列である必要があります。これらの設定を行うことにより、可視・不可視の判定を正しく行うことができます。

/* ViewVolume オブジェクトへ変換行列を設定 */
ret = IMICRO3Dv4es_m3dNode_getTransformTo ( pMe -> pIM3D,
( m3dNode * ) pmc -> pWorld, ( m3dNode * ) pmc -> pCamera, &trans, &pMe -> e );

IMICRO3Dv4es_m3dTransform_get ( pMe -> pIM3D, &camTempTrans, camMatrix );

IMICRO3Dv4es_mcx_ViewVolume_setTransformf ( pMe -> pIM3D, pmcx -> pViewVol, camMatrix, &pMe -> e );


2. BVFigure 全体に対するバウンディングボリュームの設定

BVFigure に対する可視判定には、あらかじめ BVFigure 全体に対するバウンディングボリュームを設定し、実際にバウンディングボリュームを取得する必要があります。

/* BVFigure 全体の BV を更新 */
IMICRO3Dv4es_mcx_BVFigure_calculateBVf ( pMe -> pIM3D, pmcx -> pBvfig, MCX_SHAPE_TYPE_BOX, 1.f, &pMe -> e );

( 中略 )

pmcx -> pBV = IMICRO3Dv4es_mcx_BVFigure_getBVf ( pMe -> pIM3D, pmcx -> pBvfig );

これは ViewVolume の可視判定の対象がバウンディングボリュームであることに起因します。そのため、3D モデルに対して可視判定を行なう場合には、あらかじめバウンディングボリュームを設定する必要があるのです。



3. 可視判定の実施

可視判定には mcx_ViewVolume_isViewable 関数を使用します。この関数に渡されたバウンディングボリュームの一部が ViewVolume に設定された視錐台の内側にあれば可視状態にあると判定し、HI_TRUE を返します。

/**
  * mcxViewVolumef* pViewVolume = pmcx -> pViewVol;
  * AECHAR szCAP_fmt [];
  * AECHAR szSPH_fmt [];
  * AECHAR szFIG_fmt [];
  * AECHAR szNOT_fmt [];
  * hi_bool isVisible;
  */


/* 可視判定 */
/* Capsule   */
isVisible = IMICRO3Dv4es_mcx_ViewVolume_isViewablef ( pMe -> pIM3D,
pViewVolume, ( mcxBoundingVolumef * ) pmcx -> pCapsule, &pMe -> e );

if ( isVisible == HI_TRUE ) {
WSPRINTF ( pmcx -> szCAPSULE, sizeof ( pmcx -> szCAPSULE ), szCAP_fmt );
} else {
WSPRINTF ( pmcx -> szCAPSULE, sizeof ( pmcx -> szCAPSULE ), szNOT_fmt );
}

/* Sphere */
isVisible = IMICRO3Dv4es_mcx_ViewVolume_isViewablef ( pMe -> pIM3D,
pViewVolume, ( mcxBoundingVolumef * ) pmcx -> pSphere, &pMe -> e );

if ( isVisible == HI_TRUE ) {
WSPRINTF ( pmcx -> szSPHERE, sizeof ( pmcx -> szSPHERE ), szSPH_fmt );
} else {
WSPRINTF ( pmcx -> szSPHERE, sizeof ( pmcx -> szSPHERE ), szNOT_fmt );
}

/* BVFigure */
isVisible = IMICRO3Dv4es_mcx_ViewVolume_isViewablef ( pMe -> pIM3D, pViewVolume, pmcx -> pBV, &pMe -> e );

if ( isVisible == HI_TRUE ) {
WSPRINTF ( pmcx -> szFIGURE, sizeof ( pmcx -> szFIGURE ), szFIG_fmt );
} else {
WSPRINTF ( pmcx -> szFIGURE, sizeof ( pmcx -> szFIGURE ), szNOT_fmt );
}

なお前述の通り、可視判定はバウンディングボリュームを対象として行なわれます。これは、ポリゴン単位の可視判定よりも高速であるためです。しかし、実際のバウンディングボリュームは 3D オブジェクトを包含する形で領域を持ちますので、可視であると判定されても実際の 3D オブジェクトは視錐台の外部にある可能性があります。同様の理由から元の 3D オブジェクトより小さいバウンディングボリュームを作成して可視判定を行なった場合は、実際に 3D オブジェクトの一部が可視であっても不可視と判定される可能性があります。



4. ViewVolume の破棄

mcx_ViewVolume_create 関数によって作成された ViewVolume も他のオブジェクト同様、不要となったら破棄する必要があります。破棄には mcx_ViewVolume_destroy 関数を使用します。

/* ViewVolume の破棄 */
IMICRO3Dv4es_mcx_ViewVolume_destroyf ( pMe -> pIM3D, pmcx -> pViewVol );



このページの先頭へ戻る