010.立方体とライティング(Dx12版)

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

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

 

図0010a

 


 動画は以下になります。

 

 

【サンプルのポイント】

 今項でのテーマはライティングです。3D表現でなくてはならない処理です。ライティングによって、オブジェクトに陰(影ではありません)を表示できます。  ライティングを実装するためには頂点に法線の情報を入れる必要があります。どのように法線を入れるかで、どのようなライティングになるかが変わります。このサンプルでは、その違いを確認しましょう。

【共通解説】

 Dx12、Dx11両方に共通なのはシェーダーです。DxSharedプロジェクト内にシェーダファイルというフィルタがあり、そこに記述されてます。
 今回使用するシェーダは頂点シェーダとピクセルシェーダです。VertexPositionNormal型の頂点を持つものです。コンスタントバッファもあります。

 更新処理は動きは同じですが、Dx12版の更新処理で説明します。OnUpdate()関数には、更新する方法が記述されています。

【Dx12版解説】

 BaseCrossDx12.slnを開くと、BaseCrossDx12というメインプロジェクトがあります。この中のCharacter.h/cppが主な記述個所になります。

■初期化■

 初期化は、まず頂点の配列、インデックスの配列を初期化しメッシュを作成します。インスタンス構築時のパラメータで法線の作成方法を変えます。CubeObject::CreateBuffers()関数でその処理をしています。
void CubeObject::CreateBuffers() {
    float HelfSize = 0.5f;
    vector<Vec3> PosVec = {
        { Vec3(-HelfSize, HelfSize, -HelfSize) },
        { Vec3(HelfSize, HelfSize, -HelfSize) },
        { Vec3(-HelfSize, -HelfSize, -HelfSize) },
        { Vec3(HelfSize, -HelfSize, -HelfSize) },
        { Vec3(HelfSize, HelfSize, HelfSize) },
        { Vec3(-HelfSize, HelfSize, HelfSize) },
        { Vec3(HelfSize, -HelfSize, HelfSize) },
        { Vec3(-HelfSize, -HelfSize, HelfSize) },
    };
    vector<UINT> PosIndeces = {
        0, 1, 2, 3,
        1, 4, 3, 6,
        4, 5, 6, 7,
        5, 0, 7, 2,
        5, 4, 0, 1,
        2, 3, 7, 6,
    };
    vector<Vec3> FaceNormalVec = {
        { Vec3(0, 0, -1.0f) },
        { Vec3(1.0f, 0, 0) },
        { Vec3(0, 0, 1.0f) },
        { Vec3(-1.0f, 0, 0) },
        { Vec3(0, 1.0f, 0) },
        { Vec3(0, -1.0f, 0) }
    };

    vector<VertexPositionNormal> vertices;
    vector<uint16_t> indices;
    UINT BasePosCount = 0;
    for (int i = 0; i < 6; i++) {
        for (int j = 0; j < 4; j++) {
            VertexPositionNormal Data;
            Data.position = PosVec[PosIndeces[BasePosCount + j]];
            if (m_Flat) {
                //フラット表示の場合は法線は頂点方向にする
                Data.normal = Data.position;
                Data.normal.normalize();
            }
            else {
                //フラット表示しない場合は、法線は面の向き
                Data.normal = FaceNormalVec[i];
            }
            vertices.push_back(Data);
        }

        indices.push_back((uint16_t)BasePosCount + 0);
        indices.push_back((uint16_t)BasePosCount + 1);
        indices.push_back((uint16_t)BasePosCount + 2);
        indices.push_back((uint16_t)BasePosCount + 1);
        indices.push_back((uint16_t)BasePosCount + 3);
        indices.push_back((uint16_t)BasePosCount + 2);

        BasePosCount += 4;
    }
    //メッシュの作成(変更できない)
    m_CubeMesh = MeshResource::CreateMeshResource(vertices, indices, false);
}
 上記、赤くなっているところは構築時に渡されるフラグですm_Flatフラット表示にするかどうかで、向かって右側の立方体での表示方法です。フラットかそうでないか法線の向きできまります。法線が面に対して垂直の場合は通常の表示です。中心から頂点への直線の向きにするとフラットになります。
 メッシュを作成したらDX12リソースの初期化を行います。

■ルートシグネチャ作成■

 CubeObject::CreateRootSignature()関数です。コンスタントバッファのみのルートシグネチャです。

■デスクプリタヒープ作成■

 CubeObject::CreateDescriptorHeap()関数です。コンスタントバッファのみのデスクプリタヒープです。

■コンスタントバッファ作成■

 CubeObject::CreateConstantBuffer()関数です。StaticConstantBuffer構造体で作成します。
 今項では、前回までの構造体にLightDir(ライト方向)Diffuse(ディフューズ)要素が加わります。

■パイプラインステート作成■

 CubeObject::CreatePipelineState()関数です。頂点型、頂点シェーダ型、ピクセルシェーダ型を渡して、テンプレート関数を呼び出します。

■コマンドリスト作成■

 CubeObject::CreateCommandList()関数です。デフォルトの処理です。

■コンスタントバッファの更新■

 CubeObject::UpdateConstantBuffer()関数です。ここでライト方向も作成してコンスタントバッファを作成します。
 通常はライトは、ゲームステージなどに持たせて、配置されるオブジェクトで共有します。今回は簡易的に直接設定しています。また、ビューや射影行列を作成するカメラも、通常は共通のものを使いますが、ここで即値で設定しています。

■更新処理■

 CubeObject::OnUpdate()関数です。オブジェクトを回転させています。

■描画処理■

 CubeObject::DrawObject()関数です。前項と変わりません。

 以上、Dx12側の説明は終わりです。

【まとめ】

 今回はライティングと法線の関係について法線を変えて頂点を作成するという方法で紹介しました。描画そのものは前項とシェーダと頂点型こそ違いうますが、処理は同じような感じです。