WPFとDirect3D9Exの連携 --- 三角形描画
下記記事にてIDirect3DSurface9をWPFで表示しました。
WPFとDirect3D9Exの連携 --- 導入 - 何でもプログラミング
今回は単純な三角形を描画してWPFで表示してみたいと思います。
本記事で利用しているAssertHR、CliComPtr、CreateDevice、CreateRenderTargetに関しましては、上記記事を参照してください.
Shader作成(csoから)
csoデータが存在する場合は、下記関数のみで作成できます。
CComPtr<IDirect3DVertexShader9> CreateVertexShader(IDirect3DDevice9Ex* device, const DWORD* cso) { CComPtr<IDirect3DVertexShader9> shader; AssertHR(device->CreateVertexShader(cso, &shader.p)); return shader; } CComPtr<IDirect3DPixelShader9> CreatePixelShader(IDirect3DDevice9Ex* device, const DWORD* cso) { CComPtr<IDirect3DPixelShader9> shader; AssertHR(device->CreatePixelShader(cso, &shader.p)); return shader; }
Shader作成(コードから)
実行時にコンパイルする場合は、下記関数を利用します。
Direct3D9Exを利用しているため、vs_3_0、ps_3_0より後のバージョンは利用できません。
コンパイルオプション(flags1)は適宜変更してください。
CComPtr<IDirect3DVertexShader9> CreateVertexShader(IDirect3DDevice9Ex* device, std::string code) { return CreateVertexShader(device, (const DWORD*)Compile(code, "vs_3_0")->GetBufferPointer()); } CComPtr<IDirect3DPixelShader9> CreatePixelShader(IDirect3DDevice9Ex* device, std::string code) { return CreatePixelShader(device, (const DWORD*)Compile(code, "ps_3_0")->GetBufferPointer()); }
#include <d3dcompiler.h> #pragma comment(lib, "d3dcompiler.lib") CComPtr<ID3DBlob> Compile(std::string code, std::string target) { #ifdef _DEBUG UINT flags1 = D3DCOMPILE_DEBUG | D3DCOMPILE_ENABLE_STRICTNESS | D3DCOMPILE_WARNINGS_ARE_ERRORS; #else UINT flags1 = D3DCOMPILE_OPTIMIZATION_LEVEL3 | D3DCOMPILE_ENABLE_STRICTNESS | D3DCOMPILE_WARNINGS_ARE_ERRORS; #endif CComPtr<ID3DBlob> compiled, errorMessage; D3DCompile( code.c_str(), code.size(), NULL, NULL, D3D_COMPILE_STANDARD_FILE_INCLUDE, "main", target.c_str(), flags1, 0, &compiled.p, &errorMessage.p); if (errorMessage) throw gcnew Exception(gcnew String((const char*)errorMessage->GetBufferPointer())); return compiled; }
VertexBuffer作成
対象のVertexクラスには、FVF staticメンバが定義されていることを想定しています。
template <class T> CComPtr<IDirect3DVertexBuffer9> CreateVertexBuffer(IDirect3DDevice9Ex* device, const std::vector<T>& vertices) { CComPtr<IDirect3DVertexBuffer9> buffer; AssertHR(device->CreateVertexBuffer( vertices.size() * sizeof(T), 0, T::FVF, D3DPOOL_DEFAULT, &buffer.p, NULL)); void* p; AssertHR(buffer->Lock(0, 0, &p, 0)); memcpy(p, vertices.data(), vertices.size() * sizeof(T)); AssertHR(buffer->Unlock()); return buffer; }
Renderer作成
Shader、VertexBufferを作成して、三角形を描画しています。
struct Vertex { static const DWORD FVF = D3DFVF_XYZ; FLOAT X, Y, Z; }; public ref class Renderer { public: property IntPtr Surface { IntPtr get() { return IntPtr(_surface); } } Renderer(int width, int height) { _device = CreateDevice(); _surface = CreateRenderTarget(_device, width, height); // Shader作成 std::string vertexCode = "float4 main(float4 position : POSITION) : POSITION { \n" " return position; \n" "} \n"; _vertexShader = CreateVertexShader(_device, vertexCode); std::string pixelCode = "float4 main() : COLOR { \n" " return float4(1.0f, 0.0f, 0.0f, 1.0f); \n" "} \n"; _pixelShader = CreatePixelShader(_device, pixelCode); // VertexBuffer作成 std::vector<Vertex> vertices = { { 0.0f, 1.0f, 0.5f }, { 1.0f, -1.0f, 0.5f }, { -1.0f, -1.0f, 0.5f }, }; _vertexBuffer = CreateVertexBuffer(_device, vertices); // 描画準備 AssertHR(_device->SetRenderTarget(0, _surface)); AssertHR(_device->SetFVF(Vertex::FVF)); AssertHR(_device->SetStreamSource(0, _vertexBuffer, 0, sizeof(Vertex))); AssertHR(_device->SetVertexShader(_vertexShader)); AssertHR(_device->SetPixelShader(_pixelShader)); // 描画 AssertHR(_device->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0)); AssertHR(_device->BeginScene()); AssertHR(_device->DrawPrimitive(D3DPT_TRIANGLELIST, 0, 1)); AssertHR(_device->EndScene()); } private: CliComPtr<IDirect3DDevice9Ex> _device; CliComPtr<IDirect3DSurface9> _surface; CliComPtr<IDirect3DVertexShader9> _vertexShader; CliComPtr<IDirect3DPixelShader9> _pixelShader; CliComPtr<IDirect3DVertexBuffer9> _vertexBuffer; };