法線ベクトル

法線ベクトルを設定したモデルを描画します。

前田稔(Maeda Minoru)の超初心者のプログラム入門

プロジェクトの説明

  1. 法線ベクトルを設定したモデルを作成して描画します。
    DirectX9 で使えた D3DXCreateTeapot や D3DXCreateTorus が使えなくなっています。
    簡単にメッシュが生成出来て、サンプルプログラムの作成に重宝していたのですが残念です。
    但し、Cube や Box や Shapes のモデルを生成する関数は、姿を変えてサポートされているようです。
    モデルの生成は Create Cube を参照して下さい。
    D3DXCreateTeapot などで生成したモデルの頂点データは「三次元座標と法線ベクトル」で構成されていました。
    法線ベクトルの説明は Windows Guid を参照して下さい。
    ここでは三次元座標と法線ベクトルで構成するモデルを定義して、回転しながら描画します。
  2. Direct3D Reader をベースにして修正します。
    Model.h の頂点データ構造体を pos と norm に設定します。
    XMFLOAT3 pos が頂点座標で、後の XMFLOAT3 norm が法線ベクトルです。
    struct VertexPosition
    {
        DirectX::XMFLOAT3 pos;
        DirectX::XMFLOAT3 norm;
    };
    
  3. Model.cpp の InputLayout の定義も頂点データの形式に合わせて修正します。
        const D3D11_INPUT_ELEMENT_DESC vertexDesc[] =
        {
            { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0,  0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
            { "NORMAL",   0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 },
        };
    
  4. Model.cpp で立方体の頂点座標を VertexPosition を使って定義します。
    先の XMFLOAT3 が頂点座標で、後の XMFLOAT3 が法線ベクトルです。
        VertexPosition cubeVertices[] = 
        {
            { XMFLOAT3(-0.5f, 0.5f, -0.5f), XMFLOAT3(0.0f, 1.0f, 0.0f) }, // +Y (top face)
            { XMFLOAT3( 0.5f, 0.5f, -0.5f), XMFLOAT3(0.0f, 1.0f, 0.0f) },
            { XMFLOAT3( 0.5f, 0.5f,  0.5f), XMFLOAT3(0.0f, 1.0f, 0.0f) },
            { XMFLOAT3(-0.5f, 0.5f,  0.5f), XMFLOAT3(0.0f, 1.0f, 0.0f) },
    
            { XMFLOAT3(-0.5f, -0.5f,  0.5f), XMFLOAT3(0.0f, -1.0f, 0.0f) }, // -Y (bottom face)
            { XMFLOAT3( 0.5f, -0.5f,  0.5f), XMFLOAT3(0.0f, -1.0f, 0.0f) },
            { XMFLOAT3( 0.5f, -0.5f, -0.5f), XMFLOAT3(0.0f, -1.0f, 0.0f) },
            { XMFLOAT3(-0.5f, -0.5f, -0.5f), XMFLOAT3(0.0f, -1.0f, 0.0f) },
    
            { XMFLOAT3(0.5f,  0.5f,  0.5f), XMFLOAT3(1.0f, 0.0f, 0.0f) }, // +X (right face)
            { XMFLOAT3(0.5f,  0.5f, -0.5f), XMFLOAT3(1.0f, 0.0f, 0.0f) },
            { XMFLOAT3(0.5f, -0.5f, -0.5f), XMFLOAT3(1.0f, 0.0f, 0.0f) },
            { XMFLOAT3(0.5f, -0.5f,  0.5f), XMFLOAT3(1.0f, 0.0f, 0.0f) },
    
            { XMFLOAT3(-0.5f,  0.5f, -0.5f), XMFLOAT3(-1.0f, 0.0f, 0.0f) }, // -X (left face)
            { XMFLOAT3(-0.5f,  0.5f,  0.5f), XMFLOAT3(-1.0f, 0.0f, 0.0f) },
            { XMFLOAT3(-0.5f, -0.5f,  0.5f), XMFLOAT3(-1.0f, 0.0f, 0.0f) },
            { XMFLOAT3(-0.5f, -0.5f, -0.5f), XMFLOAT3(-1.0f, 0.0f, 0.0f) },
    
            { XMFLOAT3(-0.5f,  0.5f, 0.5f), XMFLOAT3(0.0f, 0.0f, 1.0f) }, // +Z (front face)
            { XMFLOAT3( 0.5f,  0.5f, 0.5f), XMFLOAT3(0.0f, 0.0f, 1.0f) },
            { XMFLOAT3( 0.5f, -0.5f, 0.5f), XMFLOAT3(0.0f, 0.0f, 1.0f) },
            { XMFLOAT3(-0.5f, -0.5f, 0.5f), XMFLOAT3(0.0f, 0.0f, 1.0f) },
    
            { XMFLOAT3( 0.5f,  0.5f, -0.5f), XMFLOAT3(0.0f, 0.0f, -1.0f) }, // -Z (back face)
            { XMFLOAT3(-0.5f,  0.5f, -0.5f), XMFLOAT3(0.0f, 0.0f, -1.0f) },
            { XMFLOAT3(-0.5f, -0.5f, -0.5f), XMFLOAT3(0.0f, 0.0f, -1.0f) },
            { XMFLOAT3( 0.5f, -0.5f, -0.5f), XMFLOAT3(0.0f, 0.0f, -1.0f) },
        };
    
  5. 続いてモデルの頂点 Index を定義します。
        unsigned short modelIndices[] = 
        {
            0, 1, 2,      0, 2, 3,
            4, 5, 6,      4, 6, 7,
            8, 9, 10,     8, 10, 11,
            12, 13, 14,   12, 14, 15,
            16, 17, 18,   16, 18, 19,
            20, 21, 22,   20, 22, 23
        };
    
  6. Shader も頂点データの形式に合ったものを使用します。
    SimplePixelShader.hlsl です。
    モデルの色を黄色 float4(1,1,0.2,1) に設定しています。
    struct PixelShaderInput
    {
        float4 pos : SV_POSITION;
        float3 norm : NORMAL;
    };
    
    float4 main(PixelShaderInput input) : SV_TARGET
    {
        float3 lightDirection = normalize(float3(1, -1, 0));
        float lightMagnitude = 0.8f * saturate(dot( input.norm, -lightDirection)) + 0.2f;
        return float4(1,1,0.2,1) * lightMagnitude;
    }
    
  7. SimpleVertexShader.hlsl です。
    cbuffer ModelViewProjectionConstantBuffer : register(b0)
    {
        matrix model;
        matrix view;
        matrix projection;
    };
    
    struct VertexShaderInput
    {
        float3 pos : POSITION;
        float3 norm : NORMAL;
    };
    
    struct VertexShaderOutput
    {
        float4 pos : SV_POSITION;
        float3 norm : NORMAL;
    };
    
    VertexShaderOutput main(VertexShaderInput input)
    {
        VertexShaderOutput output;
        float4 pos = float4(input.pos, 1.0f);
    
        // Transform the vertex position into projected space.
        pos = mul(pos, model);
        pos = mul(pos, view);
        pos = mul(pos, projection);
        output.pos = pos;
    
        float4 norm = float4(normalize(input.norm), 0.0f);
        norm = mul(norm, model);
        output.norm = normalize(norm.xyz);
        return output;
    }
    
  8. プロジェクトを実行すると、黄色の立方体が回転しながら描画されます。
    DirectX10 でも同様のプログラム 立方体を光源で照らして描画する を作成しています。
    Shader の説明は Direct3D 9 での HLSL シェーダーの記述 を参照して下さい。

多角錐をプログラムで生成

  1. 次はプログラムで多角錐を生成して描画してみましょう。
    モデルの頂点座標と頂点 Index の領域の定義です。
    #define      KAKU      7    // (pyramid の角の数+1)
      
        // モデルの頂点座標
        VertexPosition modelVertices[KAKU*2];
        // モデルの頂点 Index
        unsigned short modelIndices[KAKU*6];
    
  2. プログラムで「頂点座標と法線ベクトル」を計算します。
        for(int slice=0; slice<KAKU; slice++)
        {
            float v = (float)slice/(float)(KAKU-1);
            float theta = v * 3.14f * 2;
            modelVertices[2*slice+0].pos = XMFLOAT3( sinf(theta),-1.0f, cosf(theta) );
            modelVertices[2*slice+0].norm = XMFLOAT3( sinf(theta), 1.0f, cosf(theta) );
            modelVertices[2*slice+1].pos = XMFLOAT3( 0.0f, 1.0f, 0.0f );
            modelVertices[2*slice+1].norm = XMFLOAT3( sinf(theta), 1.0f, cosf(theta) );
        }
        for(int slice=0; slice<(KAKU-1); slice++)
        {
            modelIndices[3*slice+0] = slice*2+0;
            modelIndices[3*slice+1] = slice*2+1;
            modelIndices[3*slice+2] = slice*2+2;
            modelIndices[3*(KAKU+slice)+0] = slice*2+3;
            modelIndices[3*(KAKU+slice)+1] = slice*2+2;
            modelIndices[3*(KAKU+slice)+2] = slice*2+1;
        }
    
  3. 頂点座標と頂点 Index の定義を除いて、プログラムは前回と同じです。
    多角錐が回転しながら描画されることを、確かめて下さい。
    DirectX10 でも同様のプログラム 円柱(円錐)をプログラムで生成する を掲載しています。
    DirectX9 でも法線ベクトルのプログラム VertexBuffer で多角形の筒を描画する を掲載しています。
    またテクスチャを貼り付けるプログラム 円筒にテクスチャを貼り付けて描画する も掲載しています。

超初心者のプログラム入門(DirectX Store)