SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

特集記事

物理エンジンを使ってDirect3Dアプリケーションをつくる

Direct3DアプリケーションにAGEIA PhysXエンジンを導入する

  • X ポスト
  • このエントリーをはてなブックマークに追加

各処理の作成(1/2)

アクターの登録

 アクターとは、PhysXにおいて物理演算の対象になるオブジェクトのことを指します。今回のサンプルのアクターは、地面の平面、球とボックスの3つです。

地面(平面)

地面の生成
HRESULT InitGround()
{
    HRESULT hr = S_OK;

    // 地面のセット
    NxPlaneShapeDesc PlaneDesc;
        NxActorDesc ActorDesc;
    ActorDesc.shapes.pushBack( &PlaneDesc );
    g_pScene->createActor(ActorDesc);

    // 摩擦関連
    NxMaterial * defaultMaterial = g_pScene->getMaterialFromIndex(0);
    defaultMaterial->setRestitution(0.0f);      // 反発係数
    defaultMaterial->setStaticFriction(0.5f);   // 静止摩擦係数
    defaultMaterial->setDynamicFriction(0.5f);  // 動摩擦係数

    return hr;
}

 アクター登録の例の最初は平面のセットです。

 今回は、地面を真っ平らな平面とします。NxPlaneShapeDescが平面のための構造体で、今回はデフォルト値でそのままセットします。createActorすることでシーンにアクターが登録されます。

 Nx~ShapeDesc系のクラスは、PhysXでは形状を扱うためのもので、ここではPlaneなので平面ということになります。

 NxActorDescはアクタークラスです。アクター自体の形状は、球やボックス、平面、カプセルなどさまざまなものがあります。この形状は衝突判定を行うための形状になりますので、単純な形状ほど計算の負荷は小さくなります。ActorDesc.shapes.pushBack()関数では、アクターに衝突形状を登録します。

 摩擦関連というコメントの下は、このアクターの摩擦に関する係数のセットと衝突時の反発に関するパラメータのセットをしています。

球のアクター
VOID CreateSphere( const NxVec3* vPosition,
    const int nSize, const NxVec3* vVelocity )
{
    NxBodyDesc BodyDesc;
    BodyDesc.linearVelocity = *vVelocity;

    // 球型
    NxSphereShapeDesc SphereDesc;
    SphereDesc.radius = nSize;    // 半径

        NxActorDesc ActorDesc;
        ActorDesc.shapes.pushBack( &SphereDesc );
        ActorDesc.body          = &BodyDesc;
    ActorDesc.density       = 50;              // 質量
        ActorDesc.globalPose.t  = *vPosition;  // 初期位置
    ActorDesc.flags = 0;

    g_pScene->createActor( ActorDesc )->userData = (void*)nSize;

    //
    int numActors = g_pScene->getNbActors();
    NxMaterial * defaultMaterial =
        g_pScene->getMaterialFromIndex((NxMaterialIndex)numActors);

    defaultMaterial->setRestitution( 0.6 );    // 反発係数
    defaultMaterial->setStaticFriction(0.5f);  // 静運動摩擦
    defaultMaterial->setDynamicFriction(0.5f); // 動運動摩擦
}

 球や後述のボックスは、今回のように単純に球やボックスのモデルのための衝突形状として使うだけでなく、メッシュの境界球や境界ボックスでの衝突でよく使う形状です。衝突応答の精度は悪くなりますが、計算負荷が高く、PhysXハードウェアで高速に演算できる基本的な形状だと思います。

 球は、NxSphereShapeDescが形状を決めるクラスになります。球の場合は、半径を関数の引数のnSizeで指定しています。

 BodyDescでは、初速となるベクトルをセットしています。ActorDescでは、質量や初期位置などをセットします。

ボックス

ボックスのアクター
VOID CreateBox( const NxVec3* vPosition,
    const int nSize, const NxVec3* vVelocity )
{
    NxBodyDesc BodyDesc;
    BodyDesc.linearVelocity = *vVelocity;      // 速度

    // 箱型
    NxBoxShapeDesc BoxDesc;
    // 縦、横、奥行きのサイズ指定
    BoxDesc.dimensions =
        NxVec3( float(nSize), float(nSize), float(nSize) );

    NxActorDesc ActorDesc;
    ActorDesc.shapes.pushBack( &BoxDesc );
    ActorDesc.body          = &BodyDesc;
    ActorDesc.density       = 100;             // 質量
    ActorDesc.globalPose.t  = *vPosition;      // 初期位置
    ActorDesc.flags = 0;

    g_pScene->createActor( ActorDesc )->userData = (void*)nSize;

    //
    int numActors = g_pScene->getNbActors();
    NxMaterial * defaultMaterial =
        g_pScene->getMaterialFromIndex((NxMaterialIndex)numActors);

    defaultMaterial->setRestitution( 0.8 );    // 反発係数
    defaultMaterial->setStaticFriction(0.5f);  // 静運動摩擦
    defaultMaterial->setDynamicFriction(0.5f); // 動運動摩擦
}

 今度は、ボックスです。

 ボックスでは、BoxDescを使います。dimensionsメンバでは、幅、高さ、奥行きでサイズ指定します。その他は、球や平面のときと同じです。

ピラミッド形に積み上げる

ピラミッド形に積み上げる関数
void SetupPyramid()
{
    NxVec3 vVelocity(0,0,0);

    // ピラミッド

    // 最下段(1F)
    for(int i=-3;i<=3;i++)
    {
        for(int j=-3;j<=3;j++)
        {
            NxVec3 v;
            v.set(i*2,1.0,j*2);
            CreateBox(&v,1,&vVelocity);
        }
    }
    
    // 下から2段目(2F)
    for(int i=-2;i<=2;i++)
    {
        for(int j=-2;j<=2;j++)
        {
            NxVec3 v;
            v.set(i*2,3,j*2);
            CreateBox(&v,1,&vVelocity);
        }
    }

    // 上から2段目(3F)
    for(int i=-1;i<=1;i++)
    {
        for(int j=-1;j<=1;j++)
        {
            NxVec3 v;
            v.set(i*2,5,j*2);
            CreateBox(&v,1,&vVelocity);
        }
    }

    // 最上段(4F)
    NxVec3 v;
    v.set(0,7,0);
    CreateBox( &v,1,&vVelocity );
}

 ここでは、ボックスをピラミッドのように配置する処理を行っています。

DXUTのUIの処理

UIの処理
void CALLBACK OnGUIEvent( UINT nEvent, int nControlID,
    CDXUTControl* pControl, void* pUserContext )
{
    NxVec3 v(0,15,0);              // オブジェクトの発生位置
    NxVec3 vVelocity(0,0,0);       // オブジェクトに与える初期速度

        switch( nControlID )
        {
            case IDC_TOGGLEFULLSCREEN: DXUTToggleFullScreen(); break;
            case IDC_TOGGLEREF:        DXUTToggleREF(); break;
            case IDC_CHANGEDEVICE:
                g_SettingsDlg.SetActive( !g_SettingsDlg.IsActive() );
                break;
        case IDC_BUTTON_BOX:
            // 箱オブジェクトの生成
            CreateBox( &v, 1, &vVelocity  );
            break;
        case IDC_BUTTON_SPHERE:
            // 球のオブジェクトの生成
        
            // 発生位置は視点
            v = NxVec3(g_Camera.GetEyePt()->x,
                   g_Camera.GetEyePt()->y,
                   g_Camera.GetEyePt()->z);

            // 注視点方向へ50の速度を持つ
            vVelocity = -v;
            vVelocity.normalize(); // 正規化
            vVelocity*=50;

            CreateSphere( &v, 1, &vVelocity );
            break;
    }
}

 ここでは、画面上の[BOX]や[SPHERE]といったボタンが押された時の処理を記述しています。

 [BOX]が押された場合、世界の(0,15,0)の地点に新しいボックスが生成されます。これには速度が0なので、そのまま重力方向に落ちます。

 [SPHERE]の方は、3D空間中のカメラ位置(つまり視点)から注視点(0,0,0)方向に50という速度を与えています。

毎フレームごとに呼び出す必要のある処理

毎フレームごとに呼び出す必要のある処理
void CALLBACK OnFrameMove( IDirect3DDevice9* pd3dDevice,
    double fTime, float fElapsedTime, void* pUserContext )
{
    // Update the camera's position based on user input
    g_Camera.FrameMove( fElapsedTime );

    // シミュレーションの演算
    if( g_pScene && !g_bPause )
        g_pScene->simulate( 1.0f/(float)DXUTGetFPS() );
}

 ここでは、毎フレームごとに呼び出す必要のある処理を記述しています。

 g_pScene->simulate()では、シミュレーション計算時の時間を指定します。

次のページ
各処理の作成(2/2)

この記事は参考になりましたか?

  • X ポスト
  • このエントリーをはてなブックマークに追加
特集記事連載記事一覧

もっと読む

この記事の著者

高橋 誠史(タカハシ マサフミ)

僻地の大学院生です。GPUプログラミングとそのニュースを集めたサイトShader.jpを開いています。

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

  • X ポスト
  • このエントリーをはてなブックマークに追加
CodeZine(コードジン)
https://codezine.jp/article/detail/719 2006/11/29 00:00

おすすめ

アクセスランキング

アクセスランキング

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー

アクセスランキング

アクセスランキング