Raspberrypi 4でOpenGLES(ウィンドウの表示)
開発環境
- Raspberry Pi 4 8GB
- Raspberry Pi OS(32bit)
環境構築
ライブラリのインストール
sudo apt install libgles2-mesa-dev libegl1-mesa-dev xorg-dev
ソースコード
main.cpp
#include <X11/Xlib.h> #include <X11/Xutil.h> #include <GLES2/gl2.h> #include <EGL/egl.h> #include <EGL/eglext.h> #include <iostream> #include <unistd.h> bool InitEGL(Display* xDisplay, Window& xWin, EGLDisplay& display, EGLContext &context, EGLSurface& surface) { display = eglGetDisplay(static_cast<EGLNativeDisplayType>(xDisplay)); if (display == EGL_NO_DISPLAY) { std::cout << "Failed to get Display" << std::endl; return false; } if (!eglInitialize(display, nullptr, nullptr)) { std::cout << "Failed to init EGL" << std::endl; return false; } EGLint attr[] = {EGL_BUFFER_SIZE, 16, EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, EGL_NONE}; EGLConfig config = nullptr; EGLint numConfigs = 0; if (!eglChooseConfig(display, attr, &config, 1, &numConfigs)) { std::cout << "Failed to choose Config" << std::endl; return false; } if (numConfigs != 1) { std::cout << "Error numConfigs" << std::endl; return false; } surface = eglCreateWindowSurface(display, config, xWin, nullptr); if (surface == EGL_NO_SURFACE) { std::cout << "Failed to create WindowSurface" << std::endl; return false; } EGLint ctxattr[] = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE}; context = eglCreateContext(display, config, EGL_NO_CONTEXT, ctxattr); if (context == EGL_NO_CONTEXT) { std::cout << "Failed to create context" << std::endl; return false; } eglMakeCurrent(display, surface, surface, context); return true; } void MainLoop(Display* xDisplay, EGLDisplay display, EGLSurface surface) { while (true) { XPending(xDisplay); glClearColor(1.0f, 1.0f, 0.0f, 1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); eglSwapBuffers(display, surface); } } int main(int argc, char*argv[]) { Display* xDisplay = XOpenDisplay(nullptr); if (xDisplay == nullptr) { std::cout << "Failed to open display" << std::endl; return -1; } Window xWindow = XCreateSimpleWindow(xDisplay, DefaultRootWindow(xDisplay), 100, 100, 640, 480, 1, BlackPixel(xDisplay, 0), WhitePixel(xDisplay, 0)); XMapWindow(xDisplay, xWindow); EGLDisplay display = nullptr; EGLContext context = nullptr; EGLSurface surface = nullptr; if (!InitEGL(xDisplay, xWindow, display, context, surface)) { return -1; } MainLoop(xDisplay, display, surface); eglDestroyContext(display, context); eglDestroySurface(display, surface); eglTerminate(display); XDestroyWindow(xDisplay, xWindow); XCloseDisplay(xDisplay); return 0; }
Makefile
CC = g++ CFLAGS = -Wall -Weffc++ TARGET = program OBJS = $(SRCS:.cpp=.o) INCDIR = LIBS = -L/usr/lib -lX11 -lEGL -lGL SRCS = main.cpp $(TARGET): $(OBJS) $(CC) -o $(TARGET) $(OBJS) $(LIBS) $(OBJS): $(SRCS) $(CC) $(CFLAGS) $(INCDIR) -c $(SRCS) all: clean $(OBJS) $(TARGET) clean: $(TARGET) rm $(OBJS)
参考資料
WSLでOpenGL
環境構築
WSLのインストール
コマンドプロンプトを管理者として実行しする. 下のコマンドを実行し,Ubuntuをインストール.(ディストリビューションはUbuntuにしとく)
wsl --install -d Ubuntu
インストールが終わったら,ユーザ名とパスワードを求められるので,適当に入力. 以下のコマンドを入力して,いろいろインストール.
sudo apt update sudo apt upgrade sudo apt install gnome-text-editor -y sudo apt intall g++
Xmingのインストール
ダウンロードページのDownloadからダウンロード.ダウンロードが終わったら,ファイルを実行する.全てデフォルトでインストール.
インストールが終わったらXLaunchというアプリが追加されているので実行.基本デフォルトで進めてよいが,Extra settingのDisable access controlにチェックを入れる.
wslのシェルで以下のコマンドを実行.
sudo apt-get install x11-apps echo "export DISPLAY=localhost:0.0" >> ~/.bashrc exec bash
ライブラリのインストール
sudo apt-get install freeglut3 freeglut3-dev
サンプルプログラム
#include <GL/glut.h> void display(void) { } int main(int argc, char *argv[]) { glutInit(&argc, argv); glutCreateWindow(argv[0]); glutDisplayFunc(display); glutMainLoop(); return 0; }
コンパイル,実行
g++ -Wall -Weffc++ -o glut_main main.cpp -lglut -lGLU -lGL ./glut_main
参考資料
npmを使用したweb開発環境構築(for Windows)
はじめに
Three.jsを使用した開発をするため,web開発環境の構築を行う.
web開発初心者なので,できるだけ簡単な方法でやりたい.
環境
Windows10 Home
開発環境構築
Node.jsのインストール
公式サイトからNode.jsをダウンロード.推奨版でいいと思われる.
nodejs.org
ダウンロードが終わったら実行.実行したら下の画面が表示されるのでNextをクリック.
その後もNextを押して進めていく.下の画面が表示されたら,チェックを外してNextを押し,インストールを進めていく.
インストールが終わったらPCを再起動する.再起動が終わったら,コマンドプロンプトを起動し,以下のコマンドを実行.
node
以下の文字列が表示されたら成功.vの後の数字は自分が入れたバージョンになる.
Welcome to Node.js v18.16.0.
npmコマンドの使い方
プロジェクトフォルダの初期化
npm init
を実行.すると,色々聞かれるのでEnterを押して進める.
his utility will walk you through creating a package.json file. It only covers the most common items, and tries to guess sensible defaults. See `npm help init` for definitive documentation on these fields and exactly what they do. Use `npm install <pkg>` afterwards to install a package and save it as a dependency in the package.json file. Press ^C at any time to quit. package name: (project2) version: (1.0.0) description: entry point: (main.js) test command: git repository: keywords: author: license: (ISC)
最後に
Is this OK? (yes)
と聞かれるので,yesと入力し,Enter. package.jsonが生成される.
また,
npm init -y
とすることで,質問をすべてスキップすることができる.
webpackのインストール
webpackとwebpackをCLIから利用するためのツールをインストール.
npm install --save-dev webpack webpack-cli
プロジェクトのディレクトリで以下のコマンドを実行し,srcフォルダを作成し,その中にindex.jsというファイルを作成する.このindex.jsにコードを記述する.
mkdir src cd ./src type nul > index.js
プロジェクトフォルダに戻り,バンドルを実行.
cd ../ npx webpack --watch
成功すると,プロジェクトフォルダにdistというフォルダが作成され,その中にmain.jsが作成される.
htmlでjavascriptのソースコードを呼び出す
distディレクトリの中にindex.htmlを作成し,以下を記述.
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"/> <title>title</title> <script src="./main.js"></script> </head> <body> </body> </html>
htmlのプレビュー
visual studio codeの拡張機能で,Live Serverと検索し,インストール.
index.htmlを右クリックし,Open with Live Serverを選択すると,ブラウザの画面が表示され,実行結果を表示することができる.
おまけ(本題)
Three.jsのインストール
今回は,npmを使用したThree.jsのインストールを行う. プロジェクトフォルダの初期化が終わった後,
npm install three --save
これで,カレントディレクトリにnode_modulesとpackage-lock.jsonが生成される.
立方体の表示
index.jsに以下のコードを記述
import * as THREE from "three" window.addEventListener('DOMContentLoaded', init); function init() { const width = 960; const height = 540; // レンダラーを作成 const renderer = new THREE.WebGLRenderer({ canvas: document.querySelector('#myCanvas') }); renderer.setSize(width, height); renderer.setPixelRatio(window.devicePixelRatio); // シーンを作成 const scene = new THREE.Scene(); // カメラを作成 const camera = new THREE.PerspectiveCamera(45, width / height, 1, 10000); // カメラの初期座標を設定(X座標:0, Y座標:0, Z座標:0) camera.position.set(0, 0, 1000); // 箱を作成 const geometry = new THREE.BoxGeometry(500, 500, 500); const material = new THREE.MeshStandardMaterial({color: 0x0000FF}); const box = new THREE.Mesh(geometry, material); scene.add(box); // 平行光源 const light = new THREE.DirectionalLight(0xFFFFFF); light.intensity = 2; // 光の強さを倍に light.position.set(1, 1, 1); // ライトの方向 // シーンに追加 scene.add(light); // レンダリング renderer.render(scene, camera); }
index.html
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"/> <title>title</title> <script src="./main.js"></script> </head> <body> <canvas id="myCanvas"></canvas> </body> </html>
このような画像がレンダリングされれば成功.
DirectX11 マルチスクリーン3
続き
モニターの数を取得してスワップチェインの生成,デプスステンシルバッファの生成をできるようになったので書きます.
変数の宣言
std::vector<IDXGISwapChain*> _pSwapChains; std::vector<ID3D11Texture2D*> _pRenderTargets; std::vector<ID3D11RenderTargetView*> _pRenderTargetViews; std::vector<ID3D11DepthStencilState*> _pDepthStencilStates; std::vector<ID3D11Texture2D*> _pDepthStencilTextures; std::vector<ID3D11DepthStencilView*> _pDepthStencilViews; uint32_t _monitorNum;
初期化
スワップチェインとデプスステンシルバッファの生成をモニターの数繰り返す
bool DxManager::Init(SCREEN* monitorInfo, uint32_t monitorNum) { _monitorNum = monitorNum; if (!CreateFactory()) { return false; } if (!CreateDevice()) { return false; } _pSwapChains.resize(monitorNum); _pRenderTargets.resize(monitorNum); _pRenderTargetViews.resize(monitorNum); _pDepthStencilStates.resize(monitorNum); _pDepthStencilTextures.resize(monitorNum); _pDepthStencilViews.resize(monitorNum); for (uint32_t i = 0; i < _monitorNum; i++) { if (!CreateSwapChain(monitorInfo[i], i)) { return false; } if (!CreateDepthStencilBuffer(monitorInfo[i], i)) { return false; } } return true; }
ソースコード
DxManager.cpp
#include "DxManager.h" DxManager* dx; DxManager::DxManager() { _monitorNum = 0; } bool DxManager::Init(SCREEN* monitorInfo, uint32_t monitorNum) { _monitorNum = monitorNum; if (!CreateFactory()) { return false; } if (!CreateDevice()) { return false; } _pSwapChains.resize(monitorNum); _pRenderTargets.resize(monitorNum); _pRenderTargetViews.resize(monitorNum); _pDepthStencilStates.resize(monitorNum); _pDepthStencilTextures.resize(monitorNum); _pDepthStencilViews.resize(monitorNum); for (uint32_t i = 0; i < _monitorNum; i++) { if (!CreateSwapChain(monitorInfo[i], i)) { return false; } if (!CreateDepthStencilBuffer(monitorInfo[i], i)) { return false; } } if (!CreateBlendState()) { return false; } return true; } bool DxManager::CreateFactory() { ComPtr<IDXGIOutput> pOutput; DXGI_ADAPTER_DESC adapterDesc = {}; size_t stringLength; uint32_t numModes = 0; uint32_t GPUMaxMem = 0; uint32_t GPUNum = 0; HRESULT hResult = S_OK; //DXGIファクトリーの作成 hResult = CreateDXGIFactory(IID_PPV_ARGS(_pFactory.GetAddressOf())); if (FAILED(hResult)) { return false; } //GPUを列挙 for (uint32_t i = 0; i < 100; i++) { IDXGIAdapter* adapter; hResult = _pFactory->EnumAdapters(i, &adapter); if (FAILED(hResult)) { break; } //GPUの情報を取得 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; } uint32_t videoCardMemory = (uint32_t)(adapterDesc.DedicatedVideoMemory / 1028 / 1024); std::cout << "ビデオカード名: " << videoCardDesc << std::endl; 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; } //一番メモリが多いGPUを探す if (videoCardMemory > GPUMaxMem) { GPUMaxMem = videoCardMemory; GPUNum = i; } } //GPUを選ぶやでー hResult = _pFactory->EnumAdapters(GPUNum, _pAdapter.GetAddressOf()); if (FAILED(hResult)) { return false; } return true; } bool DxManager::CreateDevice() { HRESULT hResult = S_OK; UINT cdev_flags = 0; //デバッグレイヤーを有効にするやでー #ifdef _DEBUG cdev_flags |= D3D11_CREATE_DEVICE_DEBUG; #endif D3D_FEATURE_LEVEL featureLevels[] = { D3D_FEATURE_LEVEL_10_0, D3D_FEATURE_LEVEL_10_1, D3D_FEATURE_LEVEL_11_0, D3D_FEATURE_LEVEL_11_1, }; hResult = D3D11CreateDevice( _pAdapter.Get(), D3D_DRIVER_TYPE_UNKNOWN, nullptr, cdev_flags, featureLevels, 4, D3D11_SDK_VERSION, _pDevice.GetAddressOf(), &_featurelevel, _pDeviceContext.GetAddressOf() ); if (FAILED(hResult)) { return false; } return true; } bool DxManager::CreateSwapChain(SCREEN monitor, uint32_t index) { HRESULT hResult = S_OK; DXGI_MODE_DESC modeDesc = {}; modeDesc.Width = monitor.Width; modeDesc.Height = monitor.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 = monitor.Hwnd; swapChainDesc.SampleDesc.Count = 1; swapChainDesc.SampleDesc.Quality = 0; swapChainDesc.Windowed = true; swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD; swapChainDesc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH; hResult = _pFactory->CreateSwapChain(_pDevice.Get(), &swapChainDesc, &_pSwapChains[index]); if (FAILED(hResult)) { return false; } _pAdapter->Release(); _pFactory->Release(); hResult = _pSwapChains[index]->GetBuffer(0, IID_PPV_ARGS(&_pRenderTargets[index])); if (FAILED(hResult)) { return false; } hResult = _pDevice->CreateRenderTargetView(_pRenderTargets[index], nullptr, &_pRenderTargetViews[index]); if (FAILED(hResult)) { return false; } _viewport.Width = static_cast<float>(monitor.Width); _viewport.Height = static_cast<float>(monitor.Height); _viewport.MinDepth = 0.0f; _viewport.MaxDepth = 1.0f; _viewport.TopLeftX = 0; _viewport.TopLeftY = 0; return true; } bool DxManager::CreateDepthStencilBuffer(SCREEN monitor, uint32_t index) { 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, &_pDepthStencilStates[index]); if (FAILED(hResult)) { return false; } D3D11_TEXTURE2D_DESC Tex2Desc = {}; Tex2Desc.Format = DXGI_FORMAT_R24G8_TYPELESS; Tex2Desc.Width = monitor.Width; Tex2Desc.Height = monitor.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, &_pDepthStencilTextures[index]); 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(_pDepthStencilTextures[index], &DSVDesc, &_pDepthStencilViews[index]); 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() { for (uint32_t i = 0; i < _monitorNum; i++){ _pDeviceContext->OMSetRenderTargets(1, &_pRenderTargetViews[i], _pDepthStencilViews[i]); _pDeviceContext->RSSetViewports(1, &_viewport); float clearColor[4] = { 1.0f, 0.0f, 0.0f, 0.0f }; _pDeviceContext->ClearRenderTargetView(_pRenderTargetViews[i], clearColor); _pDeviceContext->ClearDepthStencilView(_pDepthStencilViews[i], D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0f, 0); } } void DxManager::EndRender() { for (uint32_t i = 0; i < _monitorNum; i++) { _pSwapChains[i]->Present(1, 0); } }
DxManager.h
#pragma once #include <iostream> #include <cstdint> #include <vector> #include <d3d11.h> #include <dxgi.h> #include <Windows.h> #include <windef.h> #include <wrl/client.h> #pragma comment(lib, "d3d11.lib") #pragma comment(lib, "dxgi.lib") using Microsoft::WRL::ComPtr; struct SCREEN { int32_t X; int32_t Y; int32_t Width; int32_t Height; HWND Hwnd; }; class DxManager { private: D3D_FEATURE_LEVEL _featurelevel; ComPtr<IDXGIFactory> _pFactory = nullptr; ComPtr<IDXGIAdapter> _pAdapter = nullptr; ComPtr<ID3D11Device> _pDevice = nullptr; ComPtr<ID3D11DeviceContext> _pDeviceContext = nullptr; std::vector<IDXGISwapChain*> _pSwapChains; std::vector<ID3D11Texture2D*> _pRenderTargets; std::vector<ID3D11RenderTargetView*> _pRenderTargetViews; std::vector<ID3D11DepthStencilState*> _pDepthStencilStates; std::vector<ID3D11Texture2D*> _pDepthStencilTextures; std::vector<ID3D11DepthStencilView*> _pDepthStencilViews; ComPtr<ID3D11BlendState> _pBlendState; D3D11_VIEWPORT _viewport; uint32_t _monitorNum; public: DxManager(); bool Init(SCREEN* monitorInfo, uint32_t monitorNum); void BeginRender(); void EndRender(); private: bool CreateFactory(); bool CreateDevice(); bool CreateSwapChain(SCREEN montor, uint32_t index); bool CreateDepthStencilBuffer(SCREEN monitor, uint32_t index); bool CreateBlendState(); }; extern DxManager* dx;
DirectX11 マルチスクリーン2
画面の初期化
スワップチェインとレンダーターゲットをモニターの数だけ生成する.できればモニターの数を自動で取得して初期化をしたかったが,めんどくさそうだったのでやめた.
モニターの情報を保持する構造体を作成
struct SCREEN { int32_t X; int32_t Y; int32_t Width; int32_t Height; HWND Hwnd; };
スワップチェインの生成
const uint32_t MONITOR_NUM = 4; IDXGISwapChain* _pSwapChains[4]; ID3D11Texture2D* _pRenderTargets[4]; ID3D11RenderTargetView* _pRenderTargetViews[4];
bool DxManager::CreateSwapChain(SCREEN monitor, uint32_t index) { HRESULT hResult = S_OK; DXGI_MODE_DESC modeDesc = {}; modeDesc.Width = monitor.Width; modeDesc.Height = monitor.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 = monitor.Hwnd; swapChainDesc.SampleDesc.Count = 1; swapChainDesc.SampleDesc.Quality = 0; swapChainDesc.Windowed = true; swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD; swapChainDesc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH; hResult = _pFactory->CreateSwapChain(_pDevice.Get(), &swapChainDesc, &_pSwapChains[index]); if (FAILED(hResult)) { return false; } _pAdapter->Release(); _pFactory->Release(); hResult = _pSwapChains[index]->GetBuffer(0, IID_PPV_ARGS(&_pRenderTargets[index])); if (FAILED(hResult)) { return false; } hResult = _pDevice->CreateRenderTargetView(_pRenderTargets[index], nullptr, &_pRenderTargetViews[index]); if (FAILED(hResult)) { return false; } _viewport.Width = static_cast<float>(monitor.Width); _viewport.Height = static_cast<float>(monitor.Height); _viewport.MinDepth = 0.0f; _viewport.MaxDepth = 1.0f; _viewport.TopLeftX = 0; _viewport.TopLeftY = 0; return true; }
レンダリング
void DxManager::BeginRender() { for (uint32_t i = 0; i < MONITOR_NUM; i++){ _pDeviceContext->OMSetRenderTargets(1, &_pRenderTargetViews[i], nullptr); _pDeviceContext->RSSetViewports(1, &_viewport); float clearColor[4] = { 1.0f, 0.0f, 0.0f, 0.0f }; _pDeviceContext->ClearRenderTargetView(_pRenderTargetViews[i], clearColor); } } void DxManager::EndRender() { for (uint32_t i = 0; i < MONITOR_NUM; i++) { _pSwapChains[i]->Present(1, 0); } }
DirectX11 マルチスクリーン1
はじめに
現在このような環境でモニターを配置している.これに対応できるようにウィンドウを表示したい.
フルスクリーンでウィンドウの表示
方法① Win32APIで愚直にフルスクリーン
これを参考にフルスクリーン表示をしてみる
SetMenu(_hwnd, NULL); SetWindowLong(_hwnd, GWL_STYLE, WS_VISIBLE | WS_POPUP); MoveWindow( _hwnd, GetSystemMetrics(SM_XVIRTUALSCREEN), GetSystemMetrics(SM_YVIRTUALSCREEN), GetSystemMetrics(SM_CXVIRTUALSCREEN), GetSystemMetrics(SM_CYVIRTUALSCREEN), TRUE );
結果
全画面をそのままキャプチャした.赤いところが表示されている部分.
それっぽくできてそう?
横と縦を表示してみると
x: 5888 y: 2520
と表示された.
これだとDirectX11でレンダリングするときに不都合がありそう...なので,別の方法を考えてみる.
方法② 複数ウィンドウを作成して最大化
App.h
#pragma once #include <Windows.h> #include <cstdint> #include <string> #include <iostream> #include <vector> class App { public: App(); void Run(); private: HINSTANCE RegisterWindowClass(); HWND InitWindow(HINSTANCE hInstance, std::wstring className); bool InitApp(); void MainLoop(); static BOOL CALLBACK MonitorEnumProc(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData); 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; std::vector<MONITORINFO> _monitorInfo; std::vector<HWND> _windowHandles; }; extern App* appPtr;
App.cpp
#include "App.h" App* appPtr; App::App() { _width = 1080; _height = 720; appPtr = this; } void App::Run() { if (!InitApp()) { return; } MainLoop(); } //初期化 bool App::InitApp() { EnumDisplayMonitors(nullptr, nullptr, MonitorEnumProc, 0); HINSTANCE hInstance = RegisterWindowClass(); if (hInstance == nullptr) { return false; } for (uint32_t i = 0; i < _monitorInfo.size(); i++) { HWND hwnd = InitWindow(hInstance, WindowClassName); if (!hwnd) { std::cout << "Failed to create window" << std::endl; return false; } int32_t x = _monitorInfo[i].rcMonitor.left; int32_t y = _monitorInfo[i].rcMonitor.top; int32_t width = _monitorInfo[i].rcMonitor.right - x; int32_t height = _monitorInfo[i].rcMonitor.bottom - y; SetWindowPos(hwnd, nullptr, x, y, width, height, SWP_NOZORDER); _windowHandles.push_back(hwnd); } return true; } HINSTANCE App::RegisterWindowClass() { HINSTANCE hInstance = GetModuleHandle(nullptr); //ウィンドウの設定 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(GRAY_BRUSH); //背景色は黒 wc.hInstance = hInstance; //インスタンスハンドル wc.lpszMenuName = nullptr; //メニュー wc.lpszClassName = WindowClassName.c_str(); //ウィンドウクラスの名前 wc.hIconSm = LoadIcon(hInstance, IDI_APPLICATION); //小さいアイコン RegisterClassEx(&wc); //ウィンドウクラスの登録 return hInstance; } HWND App::InitWindow(HINSTANCE hInstance, std::wstring className) { HWND hwnd = CreateWindowEx( 0, className.c_str(), L"Title", WS_OVERLAPPEDWINDOW, 0, 0, _width, _height, nullptr, nullptr, hInstance, nullptr ); ShowWindow(hwnd, SW_SHOWMAXIMIZED); UpdateWindow(hwnd); return hwnd; } //メインループ void App::MainLoop() { MSG msg = {}; while (WM_QUIT != msg.message) { if (PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE == true)) { TranslateMessage(&msg); DispatchMessage(&msg); } else { for (uint32_t i = 0; i < _windowHandles.size(); i++) { UpdateWindow(_windowHandles[i]); } } } } BOOL CALLBACK App::MonitorEnumProc(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData) { MONITORINFOEX monitorInfo; monitorInfo.cbSize = sizeof(monitorInfo); GetMonitorInfo(hMonitor, &monitorInfo); appPtr->_monitorInfo.push_back(monitorInfo); return true; } //ウィンドウプロシージャ 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); }
結果
できたっぽい
とりあえずこれで進めていくことにする
次は画面の初期化をしたいなぁ
参考資料
DirectX11 初期化
はじめに
DirectX11を使用して画面の初期化を行う.
環境
- Windows10 Home
- Visual Studio 2022
- C++
- AMD Ryzen5 3600
- RAM 24GB
- GeForce GTX1060 6GB
ウィンドウの作成
GPUを列挙して選択
bool DxManager::CreateFactory() { ComPtr<IDXGIOutput> pOutput; DXGI_ADAPTER_DESC adapterDesc = {}; size_t stringLength; uint32_t numModes = 0; uint32_t GPUMaxMem = 0; uint32_t GPUNum = 0; HRESULT hResult = S_OK; //DXGIファクトリーの作成 hResult = CreateDXGIFactory(IID_PPV_ARGS(_pFactory.GetAddressOf())); if (FAILED(hResult)) { return false; } //GPUを列挙 for (uint32_t i = 0; i < 100; i++) { IDXGIAdapter* adapter; hResult = _pFactory->EnumAdapters(i, &adapter); if (FAILED(hResult)) { break; } //GPUの情報を取得 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; } uint32_t videoCardMemory = (uint32_t)(adapterDesc.DedicatedVideoMemory / 1028 / 1024); std::cout << "ビデオカード名: " << videoCardDesc << std::endl; 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; } //一番メモリが多いGPUを探す if (videoCardMemory > GPUMaxMem) { GPUMaxMem = videoCardMemory; GPUNum = i; } } //GPUを選ぶやでー 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_ALLOW_MODE_SWITCH; D3D_FEATURE_LEVEL featureLevels[] = { D3D_FEATURE_LEVEL_10_0, D3D_FEATURE_LEVEL_10_1, D3D_FEATURE_LEVEL_11_0, D3D_FEATURE_LEVEL_11_1, }; hResult = D3D11CreateDeviceAndSwapChain( _pAdapter.Get(), D3D_DRIVER_TYPE_UNKNOWN, nullptr, cdev_flags, featureLevels, 4, 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); }
ソースコード
main.cpp
#include "App.h" int main() { App app = App(); app.Run(); }
App.h
#pragma once #include <Windows.h> #include <cstdint> #include <string> #include <iostream> #include "DxManager.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"MainWindow"; uint32_t _width; uint32_t _height; HWND _hwnd; HINSTANCE _hInstance; };
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() { dx = new DxManager(); if (!InitWindow()) { return false; } if (!dx->Init(_width, _height, _hwnd)) { 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 { dx->BeginRender(); 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.h
#pragma once #include <iostream> #include <cstdint> #include <d3d11.h> #include <dxgi.h> #include <Windows.h> #include <windef.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; 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(); private: bool CreateFactory(); bool CreateDeviceAndSwapChain(); bool CreateDepthStencilBuffer(); bool CreateBlendState(); };
DxManager.cpp
#include "DxManager.h" 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; uint32_t numModes = 0; uint32_t GPUMaxMem = 0; uint32_t GPUNum = 0; HRESULT hResult = S_OK; //DXGIファクトリーの作成 hResult = CreateDXGIFactory(IID_PPV_ARGS(_pFactory.GetAddressOf())); if (FAILED(hResult)) { return false; } //GPUを列挙 for (uint32_t i = 0; i < 100; i++) { IDXGIAdapter* adapter; hResult = _pFactory->EnumAdapters(i, &adapter); if (FAILED(hResult)) { break; } //GPUの情報を取得 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; } uint32_t videoCardMemory = (uint32_t)(adapterDesc.DedicatedVideoMemory / 1028 / 1024); std::cout << "ビデオカード名: " << videoCardDesc << std::endl; 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; } //一番メモリが多いGPUを探す if (videoCardMemory > GPUMaxMem) { GPUMaxMem = videoCardMemory; GPUNum = i; } } //GPUを選ぶやでー 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_ALLOW_MODE_SWITCH; D3D_FEATURE_LEVEL featureLevels[] = { D3D_FEATURE_LEVEL_10_0, D3D_FEATURE_LEVEL_10_1, D3D_FEATURE_LEVEL_11_0, D3D_FEATURE_LEVEL_11_1, }; hResult = D3D11CreateDeviceAndSwapChain( _pAdapter.Get(), D3D_DRIVER_TYPE_UNKNOWN, nullptr, cdev_flags, featureLevels, 4, 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); }
おまけ(デバイスとスワップチェインを別に作成)
bool DxManager::CreateSwapChain() { HRESULT hResult = S_OK; 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_ALLOW_MODE_SWITCH; hResult = _pFactory->CreateSwapChain(_pDevice.Get(), &swapChainDesc, _pSwapChain.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; }