DirectX12 ⑧ ポリゴンの描画

ポリゴンの描画

環境

言語 : C++
開発環境 : Visual Studio 2020
OS : Windows10
CPU : AMD Ryzen5 3600
RAM : 24.0GB
GPU : NVIDIA GeForce GTX 1050

ソースコード

Scene.h

#pragma once

#include <d3d12.h>
#include <dxgiformat.h>
#include <DirectXMath.h>
#include <wrl/client.h>
#include <cstdint>
#include <iostream>
#include <vector>

#include "Dx.h"
#include "DxStruct.h"
#include "VertexBuffer.h"
#include "IndexBuffer.h"
#include "ConstantBuffer.h"
#include "RootSignature.h"
#include "PipelineState.h"

#pragma comment(lib, "d3d12.lib")

using namespace Microsoft::WRL;

class Scene {
public:
    Scene();
    bool Init();
    void Draw();

private:
    VertexBuffer _vertexBuffer;
    IndexBuffer _indexBuffer;
    ConstantBuffer _constantBuffer[FRAME_BUFFER_COUNT];
    RootSignature _rootSignature;
    PipelineState _pipelineState;
};

extern Scene* scene;

Scene.cpp

#include "Scene.h"

Scene* scene;

Scene::Scene() {
}

bool Scene::Init() {
    //三角形の頂点を定義
    Vertex vertices[3] = {};
    vertices[0].Position = DirectX::XMFLOAT3(-1.0f, -1.0f, 0.0f);
    vertices[0].Color = DirectX::XMFLOAT4(0.0f, 0.0f, 1.0f, 1.0f);
    vertices[1].Position = DirectX::XMFLOAT3(1.0f, -1.0f, 0.0f);
    vertices[1].Color = DirectX::XMFLOAT4(0.0f, 1.0f, 0.0f, 1.0f);
    vertices[2].Position = DirectX::XMFLOAT3(0.0f, 1.0f, 0.0f);
    vertices[2].Color = DirectX::XMFLOAT4(1.0f, 0.0f, 0.0f, 0.5f);
    //インデックスの定義
    uint32_t indices[3] = {0, 1, 2};

    //頂点バッファの作成とインデックスバッファの作成
    _vertexBuffer.CreateVertexBuffer(sizeof(vertices), sizeof(Vertex), vertices);
    _indexBuffer.CreateIndexBuffer(sizeof(indices), indices);

    //視点変換行列
    DirectX::XMVECTOR eyePos = DirectX::XMVectorSet(0.0f, 0.0f, 5.0f, 0.0f);    //視点の位置
    DirectX::XMVECTOR targetPos = DirectX::XMVectorZero();                      //視点を向ける座標
    DirectX::XMVECTOR upward = DirectX::XMVectorSet(0.0f, 1.0f, 0.0f, 0.0f);    //上方向を表すベクトル
    constexpr float fovY = DirectX::XMConvertToRadians(37.5f);
    float aspect = static_cast<float>(dx->GetWindowWidth()) / static_cast<float>(dx->GetWindowHeight());

    //座標変換に使う定数バッファの作成
    for (size_t i = 0; i < FRAME_BUFFER_COUNT; i++) {
        if (!_constantBuffer[i].CreateConstantBuffer(sizeof(Transform))) {
            return false;
        }

        auto ptr = _constantBuffer[i].GetPtr<Transform>();
        ptr->World = DirectX::XMMatrixIdentity();                                   //ワールド座標変換
        ptr->View = DirectX::XMMatrixLookAtRH(eyePos, targetPos, upward);           //カメラ(視点)座標変換
        ptr->Proj = DirectX::XMMatrixPerspectiveFovRH(fovY, aspect, 0.3f, 1000.0f); //投影変換
    }

    //ルートパラメタの設定
    const uint32_t rootPramNum = 1;
    D3D12_ROOT_PARAMETER rootParam[rootPramNum] = {};
    //視点変換行列
    rootParam[0].ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV;     //定数バッファ
    rootParam[0].Descriptor.ShaderRegister = 0;                     //0番目
    rootParam[0].Descriptor.RegisterSpace = 0;
    rootParam[0].ShaderVisibility = D3D12_SHADER_VISIBILITY_VERTEX; //頂点シェーダから参照

    _rootSignature.SetRootParameter(rootParam, rootPramNum);    //ルートパラメータをセット
    _rootSignature.CreatRootSignature();                        //ルートシグネチャの作成

    //入力レイアウトの設定
    const uint32_t elementCount = 2;
    D3D12_INPUT_ELEMENT_DESC elements[elementCount] = {};
    elements[0].SemanticName = "POSITION";                      //シェーダーのセマンティクス
    elements[0].SemanticIndex = 0;
    elements[0].Format = DXGI_FORMAT_R32G32B32_FLOAT;           //float型3つの配列
    elements[0].InputSlot = 0;
    elements[0].AlignedByteOffset = D3D12_APPEND_ALIGNED_ELEMENT;
    elements[0].InputSlotClass = D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA;

    elements[1].SemanticName = "COLOR";                         //シェーダーのセマンティクス
    elements[1].SemanticIndex = 0;
    elements[1].Format = DXGI_FORMAT_R32G32B32A32_FLOAT;        //float型4つの配列
    elements[1].InputSlot = 0;
    elements[1].AlignedByteOffset = D3D12_APPEND_ALIGNED_ELEMENT;
    elements[1].InputSlotClass = D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA;
    elements[1].InstanceDataStepRate = 0;
    D3D12_INPUT_LAYOUT_DESC inputLayout = { elements, elementCount };

    _pipelineState.SetInputLayout(inputLayout);                         //頂点レイアウトのセット
    _pipelineState.SetRootSignature(_rootSignature.GetRootSignature()); //ルートシグネチャのセット
    _pipelineState.SetVertexShader(L"../x64/Debug/VertexShader.cso");   //頂点シェーダのセット
    _pipelineState.SetPixelShader(L"../x64/Debug/PixelShader.cso");     //ピクセルシェーダーのセット
    _pipelineState.CreatePipelineState();                               //グラフィックスパイプラインの作成

    return true;
}

void Scene::Draw() {
    uint32_t currentIndex = dx->GetCurrentBackBufferIndex();                            //書き込むフレームのインデックスを取得
    D3D12_VERTEX_BUFFER_VIEW vertexBufferView = _vertexBuffer.GetVertexBufferView();    //頂点バッファビューを取得
    D3D12_INDEX_BUFFER_VIEW indexBufferView = _indexBuffer.GetIndexBufferView();        //インデックスバッファビューの取得

    dx->GetCmdList()->SetGraphicsRootSignature(_rootSignature.GetRootSignature());
    dx->GetCmdList()->SetGraphicsRootConstantBufferView(0, _constantBuffer[dx->GetCurrentBackBufferIndex()].GetAddress());
    dx->GetCmdList()->SetPipelineState(_pipelineState.GetPipelineState());

    dx->GetCmdList()->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);      //ポリゴンの描画方法はトライアングルリスト
    dx->GetCmdList()->IASetVertexBuffers(0, 1, &vertexBufferView);
    dx->GetCmdList()->IASetIndexBuffer(&indexBufferView);

    dx->GetCmdList()->DrawIndexedInstanced(3, 1, 0, 0, 0);                              //描画
}

VertexShader.hlsl

cbuffer Transform : register(b0)
{
    float4x4 World; //ワールド行列
    float4x4 View; //ビュー行列
    float4x4 Proj; //投影行列
}

struct VSInput
{
    float3 pos : POSITION; //頂点座標
    float4 color : COLOR; //頂点の色
};

struct VSOutput
{
    float4 svpos : SV_POSITION; //変換された座標
    float4 color : COLOR; //頂点の色
};

VSOutput main(VSInput input)
{
    VSOutput output;

    float4 localPos = float4(input.pos, 1.0f); //頂点座標
    float4 worldPos = mul(World, localPos); //ワールド座標に変換
    float4 viewPos = mul(View, worldPos); //ビュー座標に変換
    float4 projPos = mul(Proj, viewPos); //投影変換

    output.svpos = projPos; //投影変換された座標をピクセルシェーダに渡す
    output.color = input.color; //頂点の色をそのままピクセルシェーダに渡す

    return output;
}

PixelShader.hlsl

struct PSInput
{
    float4 svpos : SV_POSITION; // 頂点シェーダーから来た座標
    float4 color : COLOR;
};

struct PSOutput
{
    float4 color : SV_TARGET;
};

PSOutput main(PSInput input) : SV_TARGET
{
    PSOutput output;
    
    output.color = input.color;

    return output;
}

App.hとApp.cppの変更

App.hに追加

#include "Scene.h"

App.cppに追加

//初期化
bool App::InitApp() {

    if (!InitWindow()) {
        return false;
    }

    dx = new Dx();
    if (!dx->Init(_width, _height, _hwnd)) {
        return false;
    }

    scene = new Scene();
    if (!scene->Init()) {
        return false;
    }

    return true;
}
//メインループ
void App::MainLoop() {
    MSG msg = {};
    while (WM_QUIT != msg.message)
    {
        if (PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE == true))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
        else
        {
            // ここに描画処理を書く
            dx->BeginRender();

            scene->Draw();

            dx->EndRender();
            UpdateWindow(_hwnd);

        }
    }
}

参考資料

書籍

サイト

qiita.com

learn.microsoft.com