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