011.立方体とテクスチャ(Dx11版)

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

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

 

図0011a

 


 動画は以下になります。

 

 

【サンプルのポイント】

 今回のテーマは3Dオブジェクトのテクスチャです。ライティング、透明処理も行います。
 今回の頂点型は3D表現のゲームで、一番多用される型と言えるでしょう。もちろん、物理ライティングや複数のテクスチャの貼り付けなど、高度なテクニックは山ほどありますが、まずはテクスチャとライティング処理されたオブジェクトの描画を実装します。

【共通解説】

 Dx12、Dx11両方に共通なのはシェーダーです。DxSharedプロジェクト内にシェーダファイルというフィルタがあり、そこに記述されてます。
 今回使用するシェーダは頂点シェーダとピクセルシェーダです。VertexPositionNormalTexture型の頂点を持つものです。コンスタントバッファもあります。
 シェーダは前項のシェーダに、テクスチャ対応を加えたものです。
 以下はテクスチャに関係あるピクセルシェーダ(PSPNTStatic.hlsl)ですが、
Texture2D g_texture : register(t0);
SamplerState g_sampler : register(s0);

float4 main(PSPNTInput input) : SV_TARGET
{
    //法線ライティング
    float3 lightdir = normalize(LightDir.xyz);
    float3 N1 = normalize(input.norm);
    float4 Light = saturate(dot(N1, -lightdir) * Diffuse) + Emissive;
    Light.a = Diffuse.a;
     //テクスチャを設定
    Light = g_texture.Sample(g_sampler, input.tex) * Light;
    return saturate(Light);
}
 赤くなっているところがテクスチャの設定に関連する部分です。サンプラーとテクスチャーの2つのリソースを使用します。
 カラー要素としてディフューズとエミッシブがあります。テクスチャ要素と合わせて、3つのパラメータがあることになります。これらをどう組み合わせるかは、シェーダ作成者次第ということになります。例えば

float4 main(PSPNTInput input) : SV_TARGET
{

    //法線ライティング
    float3 lightdir = normalize(LightDir.xyz);
    float3 N1 = normalize(input.norm);
    float4 Light = saturate(dot(N1, -lightdir) * Diffuse);
    Light.a = Diffuse.a;
    //テクスチャを設定
    Light = g_texture.Sample(g_sampler, input.tex) * Light;
    return saturate(Light + Emissive);
}
 と最後にエミッシブを加算する形にするだけでも、表現は大きく変わります。いろいろ試してみましょう。

【Dx11版解説】

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

■初期化■

 Dx11版の初期化は、Dx12版のようにリソース初期化はありません。頂点バッファを作成し、スケール、位置などを初期化します。

■更新処理■

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

■描画処理■

 CubeObject::OnDraw()関数です。透明処理をする場合としない場合がありますので、注意してください。
 またディフューズとエミッシブの値も設定しています。
void CubeObject::OnDraw() {
    auto Dev = App::GetApp()->GetDeviceResources();
    auto pD3D11DeviceContext = Dev->GetD3DDeviceContext();
    auto RenderState = Dev->GetRenderState();

    //行列の定義
    Mat4x4 World, View, Proj;
    //ワールド行列の決定
    World.affineTransformation(
        m_Scale,            //スケーリング
        Vec3(0, 0, 0),      //回転の中心(重心)
        m_Qt,               //回転角度
        m_Pos               //位置
    );
    //転置する
    World.transpose();
    //ビュー行列の決定
    View = XMMatrixLookAtLH(Vec3(0, 2.0, -5.0f), Vec3(0, 0, 0), Vec3(0, 1.0f, 0));
    //転置する
    View.transpose();
    //射影行列の決定
    float w = static_cast<float>(App::GetApp()->GetGameWidth());
    float h = static_cast<float>(App::GetApp()->GetGameHeight());
    Proj = XMMatrixPerspectiveFovLH(XM_PIDIV4, w / h, 1.0f, 100.0f);
    //転置する
    Proj.transpose();
    //コンスタントバッファの準備
    PNTStaticConstantBuffer sb;
    sb.World = World;
    sb.View = View;
    sb.Projection = Proj;
    //ライティング
    Vec4 LightDir(0.5f, -1.0f, 0.5f, 0.0f);
    LightDir.normalize();
    sb.LightDir = LightDir;
    //ディフューズ
    sb.Diffuse = Col4(1.0f, 1.0f, 1.0f, 1.0f);
    //エミッシブ加算。
    sb.Emissive = Col4(0.4f, 0.4f, 0.4f, 0);
    //コンスタントバッファの更新
    pD3D11DeviceContext->UpdateSubresource(CBPNTStatic::GetPtr()->GetBuffer(), 0, nullptr, &sb, 0, 0);

    //ストライドとオフセット
    UINT stride = sizeof(VertexPositionNormalTexture);
    UINT offset = 0;
    //頂点バッファのセット
    pD3D11DeviceContext->IASetVertexBuffers(0, 1, 
        m_CubeMesh->GetVertexBuffer().GetAddressOf(), &stride, &offset);
    //インデックスバッファのセット
    pD3D11DeviceContext->IASetIndexBuffer(m_CubeMesh->GetIndexBuffer().Get(), DXGI_FORMAT_R16_UINT, 0);

    //描画方法(3角形)
    pD3D11DeviceContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);

    //コンスタントバッファの設定
    ID3D11Buffer* pConstantBuffer = CBPNTStatic::GetPtr()->GetBuffer();
    ID3D11Buffer* pNullConstantBuffer = nullptr;
    //頂点シェーダに渡す
    pD3D11DeviceContext->VSSetConstantBuffers(0, 1, &pConstantBuffer);
    //ピクセルシェーダに渡す
    pD3D11DeviceContext->PSSetConstantBuffers(0, 1, &pConstantBuffer);
    //シェーダの設定
    pD3D11DeviceContext->VSSetShader(VSPNTStatic::GetPtr()->GetShader(), nullptr, 0);
    pD3D11DeviceContext->PSSetShader(PSPNTStatic::GetPtr()->GetShader(), nullptr, 0);
    //インプットレイアウトの設定
    pD3D11DeviceContext->IASetInputLayout(VSPNTStatic::GetPtr()->GetInputLayout());

    //ブレンドステート
    if (m_Trace) {
        //透明処理
        pD3D11DeviceContext->OMSetBlendState(RenderState->GetAlphaBlendEx(), nullptr, 0xffffffff);
    }
    else {
        //透明処理しない
        pD3D11DeviceContext->OMSetBlendState(RenderState->GetOpaque(), nullptr, 0xffffffff);
    }

    //デプスステンシルステート
    pD3D11DeviceContext->OMSetDepthStencilState(RenderState->GetDepthDefault(), 0);

    //テクスチャとサンプラーの設定
    ID3D11ShaderResourceView* pNull[1] = { 0 };
    pD3D11DeviceContext->PSSetShaderResources(0, 1,
         m_TextureResource->GetShaderResourceView().GetAddressOf());
    ID3D11SamplerState* pSampler = RenderState->GetLinearClamp();
    pD3D11DeviceContext->PSSetSamplers(0, 1, &pSampler);

    if (m_Trace) {
        //透明処理の場合は、ラスタライザステートを変更して2回描画
        //ラスタライザステート(裏面描画)
        pD3D11DeviceContext->RSSetState(RenderState->GetCullFront());
        //描画
        pD3D11DeviceContext->DrawIndexed(m_CubeMesh->GetNumIndicis(), 0, 0);
        //ラスタライザステート(表面描画)
        pD3D11DeviceContext->RSSetState(RenderState->GetCullBack());
        //描画
        pD3D11DeviceContext->DrawIndexed(m_CubeMesh->GetNumIndicis(), 0, 0);
    }
    else {
        //ラスタライザステート(表面描画)
        pD3D11DeviceContext->RSSetState(RenderState->GetCullBack());
        //描画
        pD3D11DeviceContext->DrawIndexed(m_CubeMesh->GetNumIndicis(), 0, 0);
    }
    //後始末
    Dev->InitializeStates();
}