🌈

DirectX11で透過ウィンドウ

2023/12/11に公開

概要

デスクトップマスコットをするために,背景の透過をしたい.
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.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 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;
		}

		int videoCardMemory = (int)(adapterDesc.DedicatedVideoMemory / 1028 / 1024);
		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);
    ReleaseDC(_hwnd, surfaceDC);
    ReleaseDC(_hwnd, ddc);
	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

Discussion