14.Rigidbodyと物理世界

1402.少し複雑な物理オブジェクト

 このサンプルはFullSample402というディレクトリに含まれます。
 BaseCrossDx11.slnというソリューションを開くとDx11版が起動します。
 BaseCrossDx12.slnというソリューションを開くとDx12版が起動します。

 実行結果は以下のような画面が出ます。

 

図1402a

 

凸型オブジェクト

 Rigidbodyにせよ、Collisionにせよ、ボリューム境界の形状は凸型オブジェクトです。つまり、へっこんだ部分がなくすべて、出っ張った頂点(三角形)で表現されます。
 まず、このサンプルでは正12面体を作成して、それに物理計算を実装する形状を紹介しています。
 Character.h/cppActivePsConvexクラスがあります。これが正12面体の形状です。以下はそのOnCreate()関数です。
void ActivePsConvex::OnCreate() {
    if (!m_ConvexMesh || !m_PsConvexMesh) {
        vector<VertexPositionNormalTexture> vertices;
        vector<uint16_t> indices;
        MeshUtill::CreateDodecahedron(0.5, vertices, indices);
        m_ConvexMesh = MeshResource::CreateMeshResource(vertices, indices, false);
        m_PsConvexMesh = PsConvexMeshResource::CreateMeshResource(vertices, indices);
    }

    auto PtrTransform = GetComponent<Transform>();
    PtrTransform->SetScale(Vec3(1.0f));
    PtrTransform->SetQuaternion(Quat());
    PtrTransform->SetPosition(m_Position);

    //影をつける
    auto ShadowPtr = AddComponent<Shadowmap>();
    ShadowPtr->SetMeshResource(m_ConvexMesh);

    auto PtrDraw = AddComponent<BcPNTStaticDraw>();
    PtrDraw->SetFogEnabled(true);
    PtrDraw->SetMeshResource(m_ConvexMesh);
    PtrDraw->SetTextureResource(L"WALL_TX");

    //物理計算凸面
    PsConvexParam param;
    param.m_ConvexMeshResource = m_PsConvexMesh;
    param.m_Mass = 1.0f;
    //慣性テンソルの計算(球と同じにする)
    param.m_Inertia = BasePhysics::CalcInertiaSphere(0.5f, param.m_Mass);
    param.m_MotionType = PsMotionType::MotionTypeActive;
    param.m_Quat = Quat();
    param.m_Pos = m_Position;
    auto PsPtr = AddComponent<RigidbodyConvex>(param);
    PsPtr->SetDrawActive(true);
    //親クラスのOnCreateを呼ぶ
    SeekObject::OnCreate();
}
 赤くなっているところが物理計算の初期化の部分です。慣性テンソルは球と同じにしています。
 この物体は、親クラスにSeekObjectを持ち、プレイヤーを追いかけるようになっています。

凹んだオブジェクト

 場合によっては、くびれた(凹んだ)オブジェクトも表現したい場合があります。
 こういう場合は凸型オブジェクトを組み合わせて使用します。
 ActivePsCombinedObjectは、組み合わせたオブジェクトです。以下がそのOnCreate()関数です。
void ActivePsCombinedObject::OnCreate() {
    auto PtrTransform = GetComponent<Transform>();
    PtrTransform->SetScale(Vec3(1.0f));
    PtrTransform->SetQuaternion(m_Qt);
    PtrTransform->SetPosition(m_Position);
    //合成オブジェクトの準備
    PsCombinedParam param;
    //質量は重くする
    param.m_Mass = 3.0f;
    //Box用の慣性(慣性テンソル)を計算
    param.m_Inertia = BasePhysics::CalcInertiaBox(Vec3(2.5f, 1.0f, 1.0f), param.m_Mass);
    param.m_MotionType = PsMotionType::MotionTypeActive;
    param.m_Quat = m_Qt;
    param.m_Pos = m_Position;
    //合成されるプリミティブ(0番目、ボックス)
    PsCombinedPrimitive primitive;
    primitive.reset();
    primitive.m_CombinedType = PsCombinedType::TypeBox;
    primitive.m_HalfSize = Vec3(0.5f, 0.5f, 1.5f);
    primitive.m_OffsetPosition = Vec3(-2.0f, 0.0f, 0.0f);
    //合成オブジェクトに追加
    param.AddPrim(primitive);
    //合成されるプリミティブ(1番目、ボックス)
    primitive.reset();
    primitive.m_CombinedType = PsCombinedType::TypeBox;
    primitive.m_HalfSize = Vec3(0.5f, 1.5f, 0.5f);
    primitive.m_OffsetPosition = Vec3(2.0f, 0.0f, 0.0f);
    //合成オブジェクトに追加
    param.AddPrim(primitive);
    //合成されるプリミティブ(2番目、カプセル)
    primitive.reset();
    primitive.m_CombinedType = PsCombinedType::TypeCapsule;
    primitive.m_HalfLen = 1.5f;
    primitive.m_Radius = 0.5f;
    primitive.m_OffsetPosition = Vec3(0.0f, 0.0f, 0.0f);
    //合成オブジェクトに追加
    param.AddPrim(primitive);
    //物理コンポーネント(合成)
    auto PsPtr = AddComponent<RigidbodyCombined>(param);
    PsPtr->SetDrawActive(true);
    //物理コンポーネントに合わせて描画コンポーネント(影も)を作成
    CreateDrawComp(param);
}
 このように、1つ1つボックスやカプセルを作り出して、合成オブジェクトに追加しています。
 またCreateDrawComp()関数によって、描画コンポーネントを設定しています。

発射する球体

 このサンプルではXボタンで発射する球体が実装されています。
 物理オブジェクトに向かってXボタンを押すと、球体が発射して、各物理オブジェクトと衝突します。