Win32APIでウィンドウの表示

はじめに

Win32APIを使用したウィンドウの表示(よく使うけどよく忘れるため)
一応,WINMAINとmainの両方

環境

WINMAINの方

設定

ソリューションエクスプローラー > プロジェクト名 > 構成プロパティ > リンカー > システム > サブシステム > Windows(/SUBSYSTEM:WINDOWS)を選択 > OK

コード

main.cpp

#include <Windows.h>
#include <string>
#include <cstdint>

std::wstring WindowClassName = L"MainWindow";
uint32_t wWidth = 1080;
uint32_t wHeight = 720;

LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
    switch (msg)
    {
    case WM_DESTROY:
        PostQuitMessage(0);
        return 0;
    }
    return DefWindowProc(hwnd, msg, wParam, lParam);
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR lpCmdLine, int nCmdShow) {
    HWND hwnd;
    WNDCLASSEX wc = {};
    MSG msg = {};

    wc.cbSize = sizeof(WNDCLASSEX);
    wc.style = CS_HREDRAW | CS_VREDRAW;
    wc.lpfnWndProc = WndProc;
    wc.hIcon = LoadIcon(hInstance, IDI_APPLICATION);
    wc.hCursor = LoadCursor(hInstance, IDC_ARROW);
    wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
    wc.hInstance = hInstance;
    wc.lpszMenuName = nullptr;
    wc.lpszClassName = WindowClassName.c_str();
    wc.hIconSm = LoadIcon(hInstance, IDI_APPLICATION);

    RegisterClassEx(&wc);

    hwnd = CreateWindowEx(
        0,
        WindowClassName.c_str(),
        L"Title",
        WS_OVERLAPPEDWINDOW,
        0, 0,
        wWidth, wHeight,
        nullptr, nullptr,
        hInstance,
        nullptr
    );

    ShowWindow(hwnd, SW_SHOWNORMAL);
    UpdateWindow(hwnd);
    SetFocus(hwnd);

    while (WM_QUIT != msg.message)
    {
        if (PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE == true))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
        else
        {
            //ここに処理を追加


            UpdateWindow(hwnd);
        }
    }

    return 0;
}

mainの方

設定

ソリューションエクスプローラー > プロジェクト名 > 構成プロパティ > リンカー > システム > サブシステム > コンソール(/SUBSYSTEM:CONSOLE)を選択 > OK

ファイル構成

コード

App.h

#pragma once

#include <Windows.h>
#include <cstdint>
#include <string>

class App {
public:
    App();
    void Run();

private:
    bool InitApp();
    bool InitWindow();
    void MainLoop();

    static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);

private:
    const std::wstring WindowClassName = L"MainWindow";

    uint32_t _width;
    uint32_t _height;

    HWND _hwnd;
    HINSTANCE _hInstance;
};

WindowClassNameは何でもいい

App.cpp

#include "App.h"

App::App() {
    _width = 1080;
    _height = 720;
    _hwnd = nullptr;
    _hInstance = nullptr;
}

void App::Run() {
    if (!InitApp()) {
        return;
    }

    MainLoop();
}

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

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

    return true;
}

//ウィンドウの初期化
bool App::InitWindow() {
    _hInstance = GetModuleHandle(nullptr);
    if (_hInstance == nullptr) {
        return false;
    }

    //ウィンドウの設定
    WNDCLASSEX wc = {};
    wc.cbSize = sizeof(WNDCLASSEX);
    wc.style = CS_HREDRAW | CS_VREDRAW;     //水平方向と垂直方向のサイズ変更で再描画
    wc.lpfnWndProc = WndProc;   //ウィンドウプロシージャの登録
    wc.hIcon = LoadIcon(_hInstance, IDI_APPLICATION);    //アイコン
    wc.hCursor = LoadCursor(_hInstance, IDC_ARROW);      //マウスカーソル
    wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH); //背景色は黒
    wc.hInstance = _hInstance;  //インスタンスハンドル
    wc.lpszMenuName = nullptr;  //メニュー
    wc.lpszClassName = WindowClassName.c_str();      //ウィンドウクラスの名前
    wc.hIconSm = LoadIcon(_hInstance, IDI_APPLICATION);      //小さいアイコン

    RegisterClassEx(&wc);    //ウィンドウクラスの登録

    _hwnd = CreateWindowEx(
        0,
        WindowClassName.c_str(),
        L"Title",
        WS_OVERLAPPEDWINDOW,
        CW_USEDEFAULT, CW_USEDEFAULT,
        _width, _height,
        nullptr, nullptr,
        _hInstance,
        nullptr
    );

    ShowWindow(_hwnd, SW_SHOWNORMAL);
    UpdateWindow(_hwnd);

    SetFocus(_hwnd);

    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
        {
            //ここに処理を追加


            UpdateWindow(_hwnd);
        }
    }
}

//ウィンドウプロシージャ
LRESULT CALLBACK App::WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
    switch (msg) {
    case WM_DESTROY:
        PostQuitMessage(0);
        break;

    default:
        break;
    }

    return DefWindowProc(hwnd, msg, wParam, lParam);
}

main.cpp

#include "App.h"

int main() {
    App app = App();
    app.Run();
}

参考資料

wisdom.sakura.ne.jp

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

ニキシー管時計を作る

はじめに

ニキシー管の時計を作ろうと思ったが,めんどくさいしお金がないのでCGで作ることにした.

DirectX11で透過ウィンドウを使用してポリゴンを表示していたのでそれを利用する.

環境

AMD Ryzen 5 3600
24.0GB
NVIDIA GeForce GTX 1060 6GB

Windows10
Visual Studio 2022
DirectX11

モデルの作成

blenderを使用して適当にモデルを作成する.
作成したモデルをobjファイル形式で出力する.このときにモデルの読み込みを楽にするために,すべてのポリゴンを三角形にして出力する.

全体


数字



ローダー

yttm-work.jp

このサイトを参考にローダーを作成した.(めんどくさかったので愚直に書いた.)obj形式のファイルはテキスト形式で記述されているため,テキストエディタなどで開くことで編集することができる.

レンダリング

ローダーで読み込んだデータをレンダリングする.6本のニキシー管で時,分,秒を表現できるようにした.時間の取得はctimeをインクルードしてlocaltime_s()で適当に取得した.ちょっと見にくいかも.

あとがき

台も作ったんだけど,めんどくさくてまだやってない.なんか重い.

Directx11 ウィンドウの透過

ウィンドウの透過

docomoの羊を作るためにウィンドウの透過をしたかった。 DirectX12で行っていたが、ウィンドウの透過をするための情報が見つからず、DirectX11で行うことにした。

ヘッダ

App.h

#pragma once

#include <Windows.h>
#include <cstdint>
#include <string>

#include "DxManager.h"
#include "Scene.h"

class App {
public:
    App();
    void Run();

private:
    bool InitApp();
    bool InitWindow();
    void MainLoop();

    static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);

private:
    const std::wstring WindowClassName = L"WindowClass";

    uint32_t _width;
    uint32_t _height;

    HWND _hwnd;
    HINSTANCE _hInstance;

    Scene scene;
};

DxManager.h

#pragma once

#include <iostream>
#include <cstdint>
#include <d3d11.h>
#include <dxgi.h>
#include <Windows.h>
#include <wrl/client.h>

#pragma comment(lib, "d3d11.lib")
#pragma comment(lib, "dxgi.lib")

using Microsoft::WRL::ComPtr;

class DxManager
{
private:
    D3D_FEATURE_LEVEL _featurelevel;
    ComPtr<IDXGIFactory> _pFactory = nullptr;
    ComPtr<IDXGIAdapter> _pAdapter = nullptr;

    ComPtr<ID3D11Device> _pDevice = nullptr;
    ComPtr<ID3D11DeviceContext> _pDeviceContext = nullptr;
    ComPtr<IDXGISwapChain> _pSwapChain = nullptr;
    ComPtr<ID3D11Texture2D> _pRenderTarget = nullptr;
    ComPtr<ID3D11RenderTargetView> _pRenderTargetView = nullptr;
    ComPtr<ID3D11DepthStencilState> _pDepthStencilState = nullptr;
    ComPtr<ID3D11Texture2D> _pDepthStencilTex = nullptr;
    ComPtr<ID3D11DepthStencilView> _pDepthStencilView = nullptr;
    ComPtr<ID3D11BlendState> _pBlendState = nullptr;

    D3D11_VIEWPORT _viewport;

    uint32_t _width;
    uint32_t _height;
    HWND _hwnd;

public:
    bool Init(uint32_t width, uint32_t height, HWND hwnd);

    void BeginRender();
    void EndRender();

    ID3D11Device* GetDevice();
    ID3D11DeviceContext* GetDeviceContext();

    uint32_t GetWindowWidth();
    uint32_t GetWindowHeight();

private:
    bool CreateFactory();
    bool CreateDeviceAndSwapChain();
    bool CreateDepthStencilBuffer();
    bool CreateBlendState();
};

extern DxManager* dx;    //グローバル変数

VertexBuffer

#pragma once

#include <iostream>
#include <cstdint>
#include <d3d11.h>
#include <dxgi.h>
#include <wrl/client.h>

#include "DxManager.h"
#include "DxStruct.h"

#pragma comment(lib, "d3d11.lib")
#pragma comment(lib, "dxgi.lib")

using Microsoft::WRL::ComPtr;

class VertexBuffer
{
public:
    bool CreateVertexBuffer(uint32_t size, uint32_t stride, const void* data);

    ID3D11Buffer** GetVertexBuffer();
    uint32_t* GetStride();
    uint32_t* GetOffset();

private:
    ComPtr<ID3D11Buffer> _pBuffer;

    uint32_t _size;
    uint32_t _stride;
    uint32_t _offset;
};

IndexBuffer.h

#pragma once

#include <iostream>
#include <cstdint>
#include <d3d11.h>
#include <dxgi.h>
#include <wrl/client.h>

#include "DxManager.h"
#include "DxStruct.h"

#pragma comment(lib, "d3d11.lib")
#pragma comment(lib, "dxgi.lib")

using Microsoft::WRL::ComPtr;

class IndexBuffer
{
public:
    bool CreateIndexBuffer(uint32_t size, uint32_t* data);

    ID3D11Buffer* GetIndexBuffer();

private:
    ComPtr<ID3D11Buffer> _pBuffer;
};

PipelineState.h

#pragma once

#include <iostream>
#include <cstdint>
#include <string>
#include <d3d11.h>
#include <d3dcompiler.h>
#include <wrl/client.h>

#include "DxManager.h"

#pragma comment(lib, "d3d11.lib")
#pragma comment(lib, "d3dcompiler.lib")

using Microsoft::WRL::ComPtr;

class PipelineState {
public:
    PipelineState();

    bool CreateVertexShader(std::wstring filePath, std::string mainFunc);
    bool CreatePixelShader(std::wstring filePath, std::string mainFunc);
    bool CreateInputLayout(D3D11_INPUT_ELEMENT_DESC* layout, uint32_t elementNum);

    ID3D11VertexShader* GetVertexShader();
    ID3D11PixelShader* GetPixelShader();
    ID3D11InputLayout* GetInputLayout();

private:
    ComPtr<ID3D11VertexShader> _pVertexShader;
    ComPtr<ID3D11PixelShader> _pPixelShader;
    ComPtr<ID3D11InputLayout> _pInputLayout;
    ComPtr<ID3DBlob> _pVSBlob;
};

DxStruct.h

#pragma once

#include <DirectXMath.h>

struct Vertex {
    DirectX::XMFLOAT3 Position;
    DirectX::XMFLOAT4 Color;
};

Scene.h

#pragma once

#include <DirectXMath.h>
#include <dxgi.h>

#include "DxManager.h"
#include "DxStruct.h"
#include "IndexBuffer.h"
#include "VertexBuffer.h"
#include "PipelineState.h"

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

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

private:
    PipelineState _pipelineState;
    VertexBuffer _vertexBuffer;
    IndexBuffer _indexBuffer;
};

ソース

main. cpp

#include "App.h"

int main() {
    App app;
    app.Run();
}

App.cpp

#include "App.h"

App::App() {
    _width = 1080;
    _height = 720;
    _hwnd = nullptr;
    _hInstance = nullptr;
}

void App::Run() {
    if (!InitApp()) {
        return;
    }

    MainLoop();
}

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

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

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

    if (!scene.Init()) {
        return false;
    }

    return true;
}

//ウィンドウの初期化
bool App::InitWindow() {
    _hInstance = GetModuleHandle(nullptr);
    if (_hInstance == nullptr) {
        return false;
    }

    //ウィンドウの設定
    WNDCLASSEX wc = {};
    wc.cbSize = sizeof(WNDCLASSEX);
    wc.style = CS_HREDRAW | CS_VREDRAW;     //水平方向と垂直方向のサイズ変更で再描画
    wc.lpfnWndProc = WndProc;   //ウィンドウプロシージャの登録
    wc.hIcon = LoadIcon(_hInstance, IDI_APPLICATION);    //アイコン
    wc.hCursor = LoadCursor(_hInstance, IDC_ARROW);      //マウスカーソル
    wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH); //背景色は黒
    wc.hInstance = _hInstance;  //インスタンスハンドル
    wc.lpszMenuName = nullptr;  //メニュー
    wc.lpszClassName = WindowClassName.c_str();      //ウィンドウクラスの名前
    wc.hIconSm = LoadIcon(_hInstance, IDI_APPLICATION);      //小さいアイコン

    RegisterClassEx(&wc);    //ウィンドウクラスの登録

    _hwnd = CreateWindowEx(
        WS_EX_LAYERED,                  //レイヤードウィンドウ
        WindowClassName.c_str(),
        L"Title",
        WS_POPUPWINDOW | WS_VISIBLE,
        CW_USEDEFAULT, CW_USEDEFAULT,
        _width, _height,
        nullptr, nullptr,
        _hInstance,
        nullptr
    );

    ShowWindow(_hwnd, SW_SHOWNORMAL);
    UpdateWindow(_hwnd);

    SetFocus(_hwnd);

    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);

        }
    }
}

//ウィンドウプロシージャ
LRESULT CALLBACK App::WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
    switch (msg) {
    case WM_DESTROY:
        PostQuitMessage(0);
        break;

    default:
        break;
    }

    return DefWindowProc(hwnd, msg, wParam, lParam);
}

DxManager.cpp

#include "DxManager.h"

DxManager* dx;

bool DxManager::Init(uint32_t width, uint32_t height, HWND hwnd) {
    _width = width;
    _height = height;
    _hwnd = hwnd;


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

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

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

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

    return true;
}

bool DxManager::CreateFactory() {
    ComPtr<IDXGIOutput> pOutput;
    DXGI_ADAPTER_DESC adapterDesc;
    size_t stringLength;
    unsigned int numModes = 0;
    int GPUMaxMem = 0;
    int GPUNum = 0;

    HRESULT hResult = S_OK;

    hResult = CreateDXGIFactory(IID_PPV_ARGS(_pFactory.GetAddressOf()));
    if (FAILED(hResult)) {
        return false;
    }

    for (uint32_t i = 0; i < 100; i++) {
        IDXGIAdapter* adapter;
        hResult = _pFactory->EnumAdapters(i, &adapter);
        if (FAILED(hResult)) {
            break;
        }

        hResult = adapter->GetDesc(&adapterDesc);
        if (FAILED(hResult)) {
            return false;
        }

        char videoCardDesc[128];

        int error = wcstombs_s(&stringLength, videoCardDesc, 128, adapterDesc.Description, 128);
        if (error != 0) {
            break;
        }
        //std::cout << "ビデオカード名 : " << videoCardDesc << std::endl;

        int videoCardMemory = (int)(adapterDesc.DedicatedVideoMemory / 1028 / 1024);
        //std::cout << "ビデオメモリー : " << videoCardMemory << std::endl;

        hResult = adapter->EnumOutputs(0, pOutput.GetAddressOf());
        if (FAILED(hResult)) {
            continue;
        }

        hResult = pOutput->GetDisplayModeList(DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_ENUM_MODES_INTERLACED, &numModes, nullptr);
        if (FAILED(hResult)) {
            continue;
        }

        //std::cout << "RGBA8_UNORM Count : " << numModes << std::endl;

        if (videoCardMemory > GPUMaxMem) {
            GPUMaxMem = videoCardMemory;
            GPUNum = i;
        }

    }

    hResult = _pFactory->EnumAdapters(GPUNum, _pAdapter.GetAddressOf());
    if (FAILED(hResult)) {
        return false;
    }

    return true;
}

bool DxManager::CreateDeviceAndSwapChain() {
    HRESULT hResult = S_OK;


    UINT cdev_flags = 0;
#ifdef _DEBUG
    cdev_flags |= D3D11_CREATE_DEVICE_DEBUG;
#endif


    DXGI_MODE_DESC modeDesc = {};
    modeDesc.Width = _width;
    modeDesc.Height = _height;
    modeDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM_SRGB;
    modeDesc.RefreshRate.Numerator = 60;
    modeDesc.RefreshRate.Denominator = 1;
    modeDesc.Scaling = DXGI_MODE_SCALING_CENTERED;
    modeDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;

    DXGI_SWAP_CHAIN_DESC swapChainDesc = {};
    ZeroMemory(&swapChainDesc, sizeof(swapChainDesc));
    swapChainDesc.BufferCount = 2;
    swapChainDesc.BufferDesc = modeDesc;
    swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
    swapChainDesc.OutputWindow = _hwnd;
    swapChainDesc.SampleDesc.Count = 1;
    swapChainDesc.SampleDesc.Quality = 0;
    swapChainDesc.Windowed = true;
    swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
    swapChainDesc.Flags = DXGI_SWAP_CHAIN_FLAG_GDI_COMPATIBLE;


    D3D_FEATURE_LEVEL featureLevels[] = {
        D3D_FEATURE_LEVEL_10_0,
        D3D_FEATURE_LEVEL_10_1,
        D3D_FEATURE_LEVEL_11_0,
        D3D_FEATURE_LEVEL_11_1,
        D3D_FEATURE_LEVEL_12_0,
        D3D_FEATURE_LEVEL_12_1,
    };


    hResult = D3D11CreateDeviceAndSwapChain(
        _pAdapter.Get(),
        D3D_DRIVER_TYPE_UNKNOWN,
        nullptr,
        cdev_flags,
        featureLevels, 6,
        D3D11_SDK_VERSION,
        &swapChainDesc,
        _pSwapChain.GetAddressOf(),
        _pDevice.GetAddressOf(),
        &_featurelevel,
        _pDeviceContext.GetAddressOf());
    if (FAILED(hResult)) {
        return false;
    }

    _pAdapter->Release();
    _pFactory->Release();

    hResult = _pSwapChain->GetBuffer(0, IID_PPV_ARGS(_pRenderTarget.GetAddressOf()));
    if (FAILED(hResult)) {
        return false;
    }

    hResult = _pDevice->CreateRenderTargetView(_pRenderTarget.Get(), nullptr, _pRenderTargetView.GetAddressOf());
    if (FAILED(hResult)) {
        return false;
    }

    _viewport.Width = static_cast<float>(_width);
    _viewport.Height = static_cast<float>(_height);
    _viewport.MinDepth = 0.0f;
    _viewport.MaxDepth = 1.0f;
    _viewport.TopLeftX = 0;
    _viewport.TopLeftY = 0;


    return true;
}

bool DxManager::CreateDepthStencilBuffer() {
    D3D11_DEPTH_STENCIL_DESC desc = {};
    desc.DepthEnable = true;
    desc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL;
    desc.DepthFunc = D3D11_COMPARISON_LESS;
    desc.StencilEnable = false;
    desc.StencilReadMask = D3D11_DEFAULT_STENCIL_READ_MASK;
    desc.StencilWriteMask = D3D11_DEFAULT_STENCIL_WRITE_MASK;
    desc.FrontFace.StencilFailOp = D3D11_STENCIL_OP_KEEP;
    desc.BackFace.StencilFailOp = D3D11_STENCIL_OP_KEEP;

    HRESULT hResult = _pDevice->CreateDepthStencilState(&desc, _pDepthStencilState.GetAddressOf());
    if (FAILED(hResult)) {
        return false;
    }

    D3D11_TEXTURE2D_DESC Tex2Desc = {};
    Tex2Desc.Format = DXGI_FORMAT_R24G8_TYPELESS;
    Tex2Desc.Width = _width;
    Tex2Desc.Height = _height;
    Tex2Desc.ArraySize = 1;
    Tex2Desc.MipLevels = 1;
    Tex2Desc.BindFlags = D3D11_BIND_DEPTH_STENCIL;
    Tex2Desc.Usage = D3D11_USAGE_DEFAULT;
    Tex2Desc.CPUAccessFlags = 0;
    Tex2Desc.SampleDesc.Count = 1;
    Tex2Desc.SampleDesc.Quality = 0;
    Tex2Desc.MiscFlags = 0;

    hResult = _pDevice->CreateTexture2D(&Tex2Desc, nullptr, _pDepthStencilTex.GetAddressOf());
    if (FAILED(hResult)) {
        return false;
    }

    D3D11_DEPTH_STENCIL_VIEW_DESC DSVDesc = {};
    DSVDesc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
    DSVDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D;
    DSVDesc.Texture2D.MipSlice = 0;
    DSVDesc.Flags = 0;

    hResult = _pDevice->CreateDepthStencilView(_pDepthStencilTex.Get(), &DSVDesc, _pDepthStencilView.GetAddressOf());
    if (FAILED(hResult)) {
        return false;
    }


    return true;
}

bool DxManager::CreateBlendState() {
    D3D11_RENDER_TARGET_BLEND_DESC descRTBS = {};
    descRTBS.BlendEnable = true;
    descRTBS.SrcBlend = D3D11_BLEND_SRC_ALPHA;
    descRTBS.DestBlend = D3D11_BLEND_INV_SRC_ALPHA;
    descRTBS.BlendOp = D3D11_BLEND_OP_ADD;
    descRTBS.SrcBlendAlpha = D3D11_BLEND_ONE;
    descRTBS.DestBlendAlpha = D3D11_BLEND_ZERO;
    descRTBS.BlendOpAlpha = D3D11_BLEND_OP_ADD;
    descRTBS.RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;

    D3D11_BLEND_DESC descBS = {};
    descBS.AlphaToCoverageEnable = true;
    descBS.IndependentBlendEnable = true;
    for (uint32_t i = 0; i < D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT; i++) {
        descBS.RenderTarget[i] = descRTBS;
    }

    HRESULT hResult = _pDevice->CreateBlendState(&descBS, _pBlendState.GetAddressOf());
    if (FAILED(hResult)) {
        return false;
    }
    return true;
}


void DxManager::BeginRender() {
    _pDeviceContext->OMSetRenderTargets(1, _pRenderTargetView.GetAddressOf(), _pDepthStencilView.Get());
    _pDeviceContext->RSSetViewports(1, &_viewport);

    float clearColor[4] = { 1.0f, 0.0f, 0.0f, 0.0f };
    _pDeviceContext->ClearRenderTargetView(_pRenderTargetView.Get(), clearColor);
    _pDeviceContext->ClearDepthStencilView(_pDepthStencilView.Get(), D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0f, 0);
}

void DxManager::EndRender() {
    _pSwapChain->Present(1, 0);

    IDXGISurface1* pSurface;
    HRESULT hResult = _pSwapChain->GetBuffer(0, IID_PPV_ARGS(&pSurface));
    if (FAILED(hResult)) {
        return;
    }
    HDC surfaceDC;
    hResult = pSurface->GetDC(false, &surfaceDC);
    if (FAILED(hResult)) {
        return;
    }
    HDC ddc = GetDC(_hwnd);
    RECT rc;
    GetWindowRect(_hwnd, &rc);
    POINT wPos = { rc.left, rc.top };
    SIZE wSize = { _width, _height };

    BLENDFUNCTION blend;
    blend.BlendOp = AC_SRC_OVER;
    blend.BlendFlags = 0;
    blend.SourceConstantAlpha = 255;
    blend.AlphaFormat = AC_SRC_ALPHA;

    POINT layerPos;
    layerPos.x = 0;
    layerPos.y = 0;
    UpdateLayeredWindow(_hwnd, ddc, &wPos, &wSize, surfaceDC, &layerPos, RGB(255, 0, 0), &blend, ULW_ALPHA | ULW_COLORKEY);
    pSurface->ReleaseDC(nullptr);
    pSurface->Release();

    _pDeviceContext->OMSetRenderTargets(1, _pRenderTargetView.GetAddressOf(), _pDepthStencilView.Get());

    FLOAT blendFactor[4] = { D3D11_BLEND_ZERO, D3D11_BLEND_ZERO, D3D11_BLEND_ZERO, D3D11_BLEND_ZERO };
    _pDeviceContext->OMSetBlendState(_pBlendState.Get(), blendFactor, 0xffffffff);
}

ID3D11Device* DxManager::GetDevice() {
    return _pDevice.Get();
}

ID3D11DeviceContext* DxManager::GetDeviceContext() {
    return _pDeviceContext.Get();
}

uint32_t DxManager::GetWindowWidth()
{
    return _width;
}

uint32_t DxManager::GetWindowHeight()
{
    return _height;
}

VertexBuffer.cpp

#include "VertexBuffer.h"

bool VertexBuffer::CreateVertexBuffer(uint32_t size, uint32_t stride, const void* data) {
    _size = size;
    _stride = stride;
    _offset = 0;
    _pBuffer = nullptr;

    D3D11_BUFFER_DESC desc = {};
    desc.Usage = D3D11_USAGE_DEFAULT;
    desc.ByteWidth = size;
    desc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
    desc.CPUAccessFlags = 0;
    desc.MiscFlags = 0;
    desc.StructureByteStride = 0;
    D3D11_SUBRESOURCE_DATA subResourceData = {};
    subResourceData.pSysMem = data;
    subResourceData.SysMemPitch = 0;
    subResourceData.SysMemSlicePitch = 0;

    HRESULT hResult = dx->GetDevice()->CreateBuffer(&desc, &subResourceData, _pBuffer.GetAddressOf());
    if (FAILED(hResult)) {
        return false;
    }

    return true;
}

ID3D11Buffer** VertexBuffer::GetVertexBuffer() {
    return _pBuffer.GetAddressOf();
}

uint32_t* VertexBuffer::GetStride() {
    return &_stride;
}

uint32_t* VertexBuffer::GetOffset() {
    return &_offset;
}

IndexBuffer.cpp

#include "IndexBuffer.h"

bool IndexBuffer::CreateIndexBuffer(uint32_t size, uint32_t* data) {
    D3D11_BUFFER_DESC desc = {};
    ZeroMemory(&desc, sizeof(D3D11_BUFFER_DESC));
    desc.ByteWidth = size;
    desc.StructureByteStride = sizeof(uint32_t);
    desc.Usage = D3D11_USAGE_DEFAULT;
    desc.BindFlags = D3D11_BIND_INDEX_BUFFER;
    desc.CPUAccessFlags = 0;

    D3D11_SUBRESOURCE_DATA subResourceData;
    ZeroMemory(&subResourceData, sizeof(D3D11_SUBRESOURCE_DATA));
    subResourceData.pSysMem = data;
    subResourceData.SysMemPitch = 0;
    subResourceData.SysMemSlicePitch = 0;

    HRESULT hResult = dx->GetDevice()->CreateBuffer(&desc, &subResourceData, _pBuffer.GetAddressOf());
    if (FAILED(hResult)) {
        return false;
    }

    return true;
}

ID3D11Buffer* IndexBuffer::GetIndexBuffer() {
    return _pBuffer.Get();
}

PipelineState.cpp

#include "PipelineState.h"

PipelineState::PipelineState() {

}

bool PipelineState::CreateVertexShader(std::wstring filePath, std::string mainFunc) {
#if defined(_DEBUG)
    uint32_t compileFlags = D3DCOMPILE_DEBUG | D3DCOMPILE_SKIP_OPTIMIZATION;
#else
    uint32_t compileFlags = 0;
#endif
    ComPtr<ID3DBlob> pErrorBlob = nullptr;
    HRESULT hResult = D3DCompileFromFile(
        filePath.c_str(),
        nullptr, 
        D3D_COMPILE_STANDARD_FILE_INCLUDE, 
        mainFunc.c_str(),
        "vs_4_0", 
        compileFlags, 
        0, 
        _pVSBlob.GetAddressOf(),
        pErrorBlob.GetAddressOf()
    );

    if (FAILED(hResult)) {
        std::cout << (char*)pErrorBlob->GetBufferPointer() << std::endl;
        return false;
    }

    hResult = dx->GetDevice()->CreateVertexShader(_pVSBlob->GetBufferPointer(), _pVSBlob->GetBufferSize(), nullptr, &_pVertexShader);
    if (FAILED(hResult)) {
        return false;
    }

    return true;
}

bool PipelineState::CreatePixelShader(std::wstring filePath, std::string mainFunc) {
#if defined(_DEBUG)
    uint32_t compileFlags = D3DCOMPILE_DEBUG | D3DCOMPILE_SKIP_OPTIMIZATION;
#else
    uint32_t compileFlags = 0;
#endif
    ComPtr<ID3DBlob> blob;
    ComPtr<ID3DBlob> pErrorBlob = nullptr;
    HRESULT hResult = D3DCompileFromFile(
        filePath.c_str(),
        nullptr,
        D3D_COMPILE_STANDARD_FILE_INCLUDE,
        mainFunc.c_str(),
        "ps_4_0",
        compileFlags,
        0,
        blob.GetAddressOf(),
        pErrorBlob.GetAddressOf()
    );

    if (FAILED(hResult)) {
        std::cout << (char*)pErrorBlob->GetBufferPointer() << std::endl;
        return false;
    }

    hResult = dx->GetDevice()->CreatePixelShader(blob->GetBufferPointer(), blob->GetBufferSize(), nullptr, _pPixelShader.GetAddressOf());
    if (FAILED(hResult)) {
        return false;
    }

    return true;
}

bool PipelineState::CreateInputLayout(D3D11_INPUT_ELEMENT_DESC* layout, uint32_t elementNum)
{
    if (_pVSBlob == nullptr) {
        return false;
    }
    HRESULT hResult = dx->GetDevice()->CreateInputLayout(layout, elementNum, _pVSBlob->GetBufferPointer(), _pVSBlob->GetBufferSize(), _pInputLayout.GetAddressOf());
    if (FAILED(hResult)) {
        return false;
    }

    return true;
}

ID3D11VertexShader* PipelineState::GetVertexShader()
{
    return _pVertexShader.Get();
}

ID3D11PixelShader* PipelineState::GetPixelShader()
{
    return _pPixelShader.Get();
}

ID3D11InputLayout* PipelineState::GetInputLayout()
{
    return _pInputLayout.Get();
}

シェーダーと頂点レイアウトはPipelineStateというクラスを作成し一括で管理できるようにする。
シェーダーのバージョンは4.0にする。

Scene.cpp

#include "Scene.h"

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, 1.0f);

    uint32_t indices[3] = { 2, 1, 0};

    const uint32_t elementCount = 2;
    D3D11_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 = 0;
    elements[0].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
    elements[0].InstanceDataStepRate = 0;

    elements[1].SemanticName = "COLOR";
    elements[1].SemanticIndex = 0;
    elements[1].Format = DXGI_FORMAT_R32G32B32A32_FLOAT;    //float型4つの配列
    elements[1].InputSlot = 0;
    elements[1].AlignedByteOffset = 12;
    elements[1].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
    elements[1].InstanceDataStepRate = 0;

    if (!_vertexBuffer.CreateVertexBuffer(sizeof(vertices), sizeof(Vertex), vertices)) {
        std::cout << "Failed to create VertexBuffer" << std::endl;
        return false;
    }
    if (!_indexBuffer.CreateIndexBuffer(sizeof(indices), indices)) {
        std::cout << "Failed to create IndexBuffer" << std::endl;
        return false;
    }

    if (!_pipelineState.CreateVertexShader(L"VertexShader.hlsl", "main")) {
        std::cout << "Failed to create VertexShader" << std::endl;
        return false;
    }
    if (!_pipelineState.CreatePixelShader(L"PixelShader.hlsl", "main")) {
        std::cout << "Failed to create PixelShader" << std::endl;
        return false;
    }
    if (!_pipelineState.CreateInputLayout(elements, elementCount)) {
        std::cout << "Failed to create InputLayout" << std::endl;
        return false;
    }

    return true;
}

void Scene::Draw() {
    dx->GetDeviceContext()->IASetInputLayout(_pipelineState.GetInputLayout());
    dx->GetDeviceContext()->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
    dx->GetDeviceContext()->IASetVertexBuffers(0, 1, _vertexBuffer.GetVertexBuffer(), _vertexBuffer.GetStride(), _vertexBuffer.GetOffset());
    
    dx->GetDeviceContext()->IASetIndexBuffer(_indexBuffer.GetIndexBuffer(), DXGI_FORMAT_R32_UINT, 0);
      
    dx->GetDeviceContext()->VSSetShader(_pipelineState.GetVertexShader(), nullptr, 0);
    dx->GetDeviceContext()->PSSetShader(_pipelineState.GetPixelShader(), nullptr, 0);
    
    dx->GetDeviceContext()->DrawIndexed(3, 0, 0);
}

シェーダー

VertexShader.hlsl

struct VSInput
{
    float3 pos : POSITION;
    float4 color : COLOR;
};

struct VSOutput
{
    float4 svpos : SV_POSITION;
    float4 color : COLOR;
};

VSOutput main(VSInput input)
{
    VSOutput output;
    
    output.svpos = float4(input.pos, 1.0);
    output.color = input.color;
    
    return output;
}

PixelShader.hlsl

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


float4 main(PSInput input) : SV_TARGET
{
    return input.color;
}

実行結果

参考資料

https://www.sfpgmr.net/blog/entry/立方体以外を透明化することができるようになっ.amp.html

DirectX12 ⑦ 定数バッファの作成

定数バッファの作成

環境

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

ソースコード

DxStruct.h

#pragma once

#include <DirectXMath.h>
#include <vector>

struct alignas(256) Transform {
    DirectX::XMMATRIX   World;      // ワールド行列
    DirectX::XMMATRIX   View;       // ビュー行列
    DirectX::XMMATRIX   Proj;       // 射影行列
};

struct Vertex {
    DirectX::XMFLOAT3 Position;     //座標
    DirectX::XMFLOAT4 Color;        //色
};

ConstantBuffer.h

#pragma once

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

#include "Dx.h"
#include "DxStruct.h"

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

class ConstantBuffer
{
public:
    ConstantBuffer();
    bool CreateConstantBuffer(size_t size);

    D3D12_GPU_VIRTUAL_ADDRESS GetAddress() const;
    D3D12_CONSTANT_BUFFER_VIEW_DESC GetConstantBufferView();

    void* GetPtr() const;

    template<typename T>
    T* GetPtr() {
        return reinterpret_cast<T*>(GetPtr());
    }

private:
    ComPtr<ID3D12Resource> _pBuffer;
    D3D12_CONSTANT_BUFFER_VIEW_DESC _viewDesc;

    void* _ptr;
};

ConstantBuffer.cpp

#include "ConstantBuffer.h"

ConstantBuffer::ConstantBuffer() {
    _viewDesc = {};
    _ptr = nullptr;
}

//定数バッファの作成
bool ConstantBuffer::CreateConstantBuffer(size_t size) {
    size_t align = D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT;
    uint64_t sizeAligned = (size + (align - 1)) & ~(align - 1); //アライメント
    
    //ヒーププロパティ
    D3D12_HEAP_PROPERTIES heapProp = {};
    heapProp.Type = D3D12_HEAP_TYPE_UPLOAD;
    heapProp.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
    heapProp.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
    heapProp.CreationNodeMask = 1;
    heapProp.VisibleNodeMask = 1;

    //バッファの設定
    D3D12_RESOURCE_DESC desc = {};
    desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
    desc.Alignment = 0;
    desc.Width = sizeAligned;
    desc.Height = 1;
    desc.DepthOrArraySize = 1;
    desc.MipLevels = 1;
    desc.Format = DXGI_FORMAT_UNKNOWN;
    desc.SampleDesc.Count = 1;
    desc.SampleDesc.Quality = 0;
    desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
    desc.Flags = D3D12_RESOURCE_FLAG_NONE;

    //バッファの作成
    HRESULT hResult;
    hResult = dx->GetDevice()->CreateCommittedResource(&heapProp, D3D12_HEAP_FLAG_NONE, &desc, D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, IID_PPV_ARGS(_pBuffer.GetAddressOf()));
    if (FAILED(hResult)) {
        std::cout << "Failed to create ConstantBuffer" << std::endl;
        return false;
    }

    //マッピング
    hResult = _pBuffer->Map(0, nullptr, &_ptr);
    if (FAILED(hResult)) {
        std::cout << "Failed mapping ConstantBuffer" << std::endl;
        return false;
    }

    _viewDesc = {};
    _viewDesc.BufferLocation = _pBuffer->GetGPUVirtualAddress();
    _viewDesc.SizeInBytes = uint32_t(sizeAligned);

    return true;
}

//アドレスを取得
D3D12_GPU_VIRTUAL_ADDRESS ConstantBuffer::GetAddress() const {
    return _viewDesc.BufferLocation;
}

//バッファビューを取得
D3D12_CONSTANT_BUFFER_VIEW_DESC ConstantBuffer::GetConstantBufferView() {
    return _viewDesc;
}

//ポインタを取得
void* ConstantBuffer::GetPtr() const {
    return _ptr;
}

参考資料

書籍

サイト

qiita.com

learn.microsoft.com

DirectX12 ⑥ パイプラインステートの作成

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

描画するためのパイプライン

環境

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

ソースコード

PipelineState.h

#pragma once

#include <d3d12.h>
#include <d3dcompiler.h>
#include <cstdint>
#include <wrl/client.h>
#include <iostream>
#include <string>

#include "Dx.h"
#include "DxStruct.h"

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

using namespace Microsoft::WRL;


class PipelineState
{
public:
    PipelineState();
    bool CreatePipelineState();

    void SetInputLayout(D3D12_INPUT_LAYOUT_DESC layout);
    void SetRootSignature(ID3D12RootSignature* rootSignature);
    bool SetVertexShader(std::wstring filePath);
    bool SetPixelShader(std::wstring filePath);

    ID3D12PipelineState* GetPipelineState();

private:
    D3D12_GRAPHICS_PIPELINE_STATE_DESC _desc;
    ComPtr<ID3D12PipelineState> _pPipelineState;

    ComPtr<ID3DBlob> _pBlobVS;
    ComPtr<ID3DBlob> _pBlobPS;
};

PipelieState.cpp

#include "PipelineState.h"

//初期化
PipelineState::PipelineState() {
    _desc = {};

    // ラスタライザーステートの設定
    D3D12_RASTERIZER_DESC descRS;
    descRS.FillMode = D3D12_FILL_MODE_SOLID;    //ソリッドモデル
    descRS.CullMode = D3D12_CULL_MODE_NONE;     //カリングはしない
    descRS.FrontCounterClockwise = false;       //インデックスは時計回り
    descRS.DepthBias = D3D12_DEFAULT_DEPTH_BIAS;
    descRS.DepthBiasClamp = D3D12_DEFAULT_DEPTH_BIAS_CLAMP;
    descRS.SlopeScaledDepthBias = D3D12_DEFAULT_SLOPE_SCALED_DEPTH_BIAS;
    descRS.DepthClipEnable = true;
    descRS.MultisampleEnable = false;       //サンプリングはしない
    descRS.AntialiasedLineEnable = false;   //アンチエイリアスはしない
    descRS.ForcedSampleCount = 0;
    descRS.ConservativeRaster = D3D12_CONSERVATIVE_RASTERIZATION_MODE_OFF;

    // レンダーターゲットのブレンド設定
    D3D12_RENDER_TARGET_BLEND_DESC descRTBS = {};
    descRTBS.BlendEnable = true;        //アルファブレンドはON
    descRTBS.LogicOpEnable = false;     

    descRTBS.SrcBlend = D3D12_BLEND_ONE;  
    descRTBS.DestBlend = D3D12_BLEND_ZERO;
    descRTBS.BlendOp = D3D12_BLEND_OP_ADD;

    descRTBS.SrcBlendAlpha = D3D12_BLEND_ONE;
    descRTBS.DestBlendAlpha = D3D12_BLEND_ZERO;
    descRTBS.BlendOpAlpha = D3D12_BLEND_OP_MIN;

    descRTBS.LogicOp = D3D12_LOGIC_OP_NOOP;
    descRTBS.RenderTargetWriteMask = D3D12_COLOR_WRITE_ENABLE_ALL;

    //ブレンドステート
    D3D12_BLEND_DESC descBS;
    descBS.AlphaToCoverageEnable = true;
    descBS.IndependentBlendEnable = true;
    for (uint32_t i = 0; i < D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT; i++) {
        descBS.RenderTarget[i] = descRTBS;
    }

    //深度ステンシルステート
    D3D12_DEPTH_STENCIL_DESC descDSS = {};
    descDSS.DepthEnable = true;     //深度ON
    descDSS.DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ALL;
    descDSS.DepthFunc = D3D12_COMPARISON_FUNC_LESS_EQUAL;
    descDSS.StencilEnable = true;   //ステンシルON
    descDSS.StencilReadMask = D3D12_DEFAULT_STENCIL_READ_MASK;
    descDSS.StencilWriteMask = D3D12_DEFAULT_STENCIL_WRITE_MASK;
    descDSS.FrontFace.StencilFailOp = D3D12_STENCIL_OP_KEEP;
    descDSS.FrontFace.StencilDepthFailOp = D3D12_STENCIL_OP_KEEP;
    descDSS.FrontFace.StencilPassOp = D3D12_STENCIL_OP_INCR;
    descDSS.FrontFace.StencilFunc = D3D12_COMPARISON_FUNC_GREATER_EQUAL;
    descDSS.BackFace.StencilFailOp = D3D12_STENCIL_OP_KEEP;
    descDSS.BackFace.StencilDepthFailOp = D3D12_STENCIL_OP_KEEP;
    descDSS.BackFace.StencilPassOp = D3D12_STENCIL_OP_INCR;
    descDSS.BackFace.StencilFunc = D3D12_COMPARISON_FUNC_GREATER_EQUAL;

    _desc.RasterizerState = descRS;
    _desc.BlendState = descBS;
    _desc.DepthStencilState = descDSS;
    _desc.SampleMask = UINT_MAX;
    _desc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
    _desc.NumRenderTargets = 1;
    _desc.RTVFormats[0] = DXGI_FORMAT_R8G8B8A8_UNORM;
    _desc.DSVFormat = DXGI_FORMAT_D32_FLOAT;
    _desc.SampleDesc.Count = 1;
    _desc.SampleDesc.Quality = 0;
}

//入力レイアウトをセット
void PipelineState::SetInputLayout(D3D12_INPUT_LAYOUT_DESC layout) {
    _desc.InputLayout = layout;
}

//ルートシグネチャをセット
void PipelineState::SetRootSignature(ID3D12RootSignature* rootSignature) {
    _desc.pRootSignature = rootSignature;
}

//頂点シェーダをセット
bool PipelineState::SetVertexShader(std::wstring filePath) {
    HRESULT hResult = D3DReadFileToBlob(filePath.c_str(), _pBlobVS.GetAddressOf());
    if (FAILED(hResult)) {
        std::cout << "Failed to read VertexShader" << std::endl;
        return false;
    }
    _desc.VS.pShaderBytecode = _pBlobVS->GetBufferPointer();
    _desc.VS.BytecodeLength = _pBlobVS->GetBufferSize();

    return true;
}

//ピクセルシェーダをセット
bool PipelineState::SetPixelShader(std::wstring filePath) {
    HRESULT hResult = D3DReadFileToBlob(filePath.c_str(), _pBlobPS.GetAddressOf());
    if (FAILED(hResult)) {
        std::cout << "Failed to read PixelShader" << std::endl;
        return false;
    }
    _desc.PS.pShaderBytecode = _pBlobPS->GetBufferPointer();
    _desc.PS.BytecodeLength = _pBlobPS->GetBufferSize();
    
    return true;
}

//パイプラインステートの作成
bool PipelineState::CreatePipelineState() {
    HRESULT hResult = dx->GetDevice()->CreateGraphicsPipelineState(&_desc, IID_PPV_ARGS(_pPipelineState.GetAddressOf()));
    if (FAILED(hResult)) {
        std::cout << "Failed to create GraphicsPipelineState" << std::endl;
        return false;
    }

    return true;
}

//パイプラインステートの取得
ID3D12PipelineState* PipelineState::GetPipelineState() {
    return _pPipelineState.Get();
}

参考資料

書籍

サイト

qiita.com

learn.microsoft.com

DirectX12 ⑤ ルートシグネチャの作成

ルートシグネチャの作成 

環境

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

ソースコード

RootSignature.h

#pragma once

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

#include "Dx.h"
#include "DxStruct.h"

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

using namespace Microsoft::WRL;

class RootSignature
{
public:
    RootSignature();
    void SetRootParameter(D3D12_ROOT_PARAMETER* rootParam, uint32_t rootParamNum);
    bool CreatRootSignature();

    ID3D12RootSignature* GetRootSignature();

private:
    D3D12_ROOT_SIGNATURE_DESC _desc;

    ComPtr<ID3D12RootSignature> _pRootSignature;

    ComPtr<ID3DBlob> pBlob;
    ComPtr<ID3DBlob> pErrorBlob;
};



RootSignature.cpp

#include "RootSignature.h"

RootSignature::RootSignature() {
    _desc = {};
}

//ルートシグネチャの作成
bool RootSignature::CreatRootSignature() {
    auto flag = D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT;   //入力アセンブラの使用を宣言
    flag |= D3D12_ROOT_SIGNATURE_FLAG_DENY_DOMAIN_SHADER_ROOT_ACCESS;   //ドメインシェーダからアクセスを拒否
    flag |= D3D12_ROOT_SIGNATURE_FLAG_DENY_HULL_SHADER_ROOT_ACCESS;     //ハルシェーダからアクセスを拒否
    flag |= D3D12_ROOT_SIGNATURE_FLAG_DENY_GEOMETRY_SHADER_ROOT_ACCESS; //ジオメトリシェーダからアクセスを拒否


    //サンプラーの設定
    D3D12_STATIC_SAMPLER_DESC sampler = {};
    sampler.AddressU = D3D12_TEXTURE_ADDRESS_MODE_WRAP; //テクスチャをタイル化
    sampler.AddressV = D3D12_TEXTURE_ADDRESS_MODE_WRAP;
    sampler.AddressW = D3D12_TEXTURE_ADDRESS_MODE_WRAP;
    sampler.MipLODBias = 0.0f;
    sampler.MaxAnisotropy = 16;
    sampler.BorderColor = D3D12_STATIC_BORDER_COLOR_TRANSPARENT_BLACK;
    sampler.Filter = D3D12_FILTER_MIN_MAG_MIP_LINEAR;
    sampler.MaxLOD = D3D12_FLOAT32_MAX;
    sampler.MinLOD = 0.0f;
    sampler.ShaderRegister = 0; //0番目(ピクセルシェーダからはs0で参照できる)
    sampler.RegisterSpace = 0;
    sampler.ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL;   //ピクセルシェーダから見えるようにする
    sampler.ComparisonFunc = D3D12_COMPARISON_FUNC_NEVER;

    _desc.NumStaticSamplers = 1;    //サンプラーの数は1
    _desc.pStaticSamplers = &sampler;
    _desc.Flags = flag;

    HRESULT hResult = D3D12SerializeRootSignature(&_desc, D3D_ROOT_SIGNATURE_VERSION_1_0, pBlob.GetAddressOf(), pErrorBlob.GetAddressOf());
    if (FAILED(hResult)) {
        std::cout << "Failed to serialize RootSignature" << std::endl;
        return false;
    }

    hResult = dx->GetDevice()->CreateRootSignature(0, pBlob->GetBufferPointer(), pBlob->GetBufferSize(), IID_PPV_ARGS(_pRootSignature.GetAddressOf()));
    if (FAILED(hResult)) {
        std::cout << "Failed to create RootSignature" << std::endl;
        return false;
    }

    return true;
}

//ルートシグネチャを取得
ID3D12RootSignature* RootSignature::GetRootSignature() {
    return _pRootSignature.Get();
}

//ルートパラメータをセット
void RootSignature::SetRootParameter(D3D12_ROOT_PARAMETER* rootParam, uint32_t rootParamNum) {
    _desc.pParameters = rootParam;
    _desc.NumParameters = rootParamNum; //ルートパラメータの数
}

参考資料

書籍

サイト

qiita.com

qiita.com

learn.microsoft.com