🌈
DirectX11で透過ウィンドウ
概要
デスクトップマスコットをするために,背景の透過をしたい.
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;
}
実行結果
参考資料
Discussion