WPFとDirect3D11の連携 --- テクスチャ貼り付け

下記記事にて三角形を描画するところまで記述しました。
WPFとDirect3D11の連携 --- 三角形描画 - 何でもプログラミング

今回はテクスチャを貼り付けて表示してみたいと思います。

Texture作成

Direct3D9側でD3DFMT_A8R8G8B8にてレンダリングターゲットを作成しているため、DXGI_FORMAT_B8G8R8A8_UNORMにて作成します。(反転しているのでややこしいです。)

TextureではなくResourceViewを返すよう実装してあります。

#define AssertHR(expr) { HRESULT hr = expr; if (FAILED(hr)) throw gcnew ComponentModel::Win32Exception(hr, #expr); }

CComPtr<ID3D11ShaderResourceView> CreateTexture(ID3D11Device* device, int width, int height, const byte* pixels)
{
    D3D11_TEXTURE2D_DESC desc;
    ZeroMemory(&desc, sizeof(desc));
    desc.Width = width;
    desc.Height = height;
    desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
    desc.MipLevels = 1;
    desc.ArraySize = 1;
    desc.SampleDesc.Count = 1;
    desc.SampleDesc.Quality = 0;
    desc.Usage = D3D11_USAGE_DEFAULT;
    desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
    desc.CPUAccessFlags = 0;

    D3D11_SUBRESOURCE_DATA data;
    ZeroMemory(&data, sizeof(data));
    data.pSysMem = pixels;
    data.SysMemPitch = 4 * width;

    CComPtr<ID3D11Texture2D> texture;
    AssertHR(device->CreateTexture2D(&desc, &data, &texture.p));

    CComPtr<ID3D11ShaderResourceView> resourceView;
    AssertHR(device->CreateShaderResourceView(texture, NULL, &resourceView.p));

    return resourceView;
}


Renderer作成

CliComPtr、D3D9Ex::CreateDeviceは下記記事を参照してください。
WPFとDirect3D9Exの連携 --- 導入 - 何でもプログラミング

CreateSharedRenderTarget、CreateDevice、OpenRenderTarget、Tie2は下記記事を参照してください。
WPFとDirect3D11の連携 --- 導入 - 何でもプログラミング

CreateVertexShader、CreatePixelShader、CreateVertexBufferは下記記事を参照してください。
WPFとDirect3D11の連携 --- 三角形描画 - 何でもプログラミング

struct Vertex
{
    float X, Y, Z;
    float U, V;
};
public ref class Renderer
{
public:
    property IntPtr Surface { IntPtr get() { return IntPtr(_surface9); } }
    Renderer(int width, int height, array<byte>^ pixels)
    {
        _device9 = D3D9Ex::CreateDevice();
        HANDLE handle;
        Tie2(_surface9, handle, CreateSharedRenderTarget(_device9, width, height));

        Tie2(_device, _context, CreateDevice());
        _renderTarget = OpenRenderTarget(_device, handle);

        // Shader作成
        std::string vertexCode =
            "struct VS_OUTPUT {                     \n"
            "    float4 Position : SV_POSITION;     \n"
            "    float2 Texcoord : TEXCOORD0;       \n"
            "};                                     \n"
            "VS_OUTPUT main(                        \n"
            "    float4 position : POSITION,        \n"
            "    float2 texcoord : TEXCOORD0) {     \n"
            "    VS_OUTPUT output = (VS_OUTPUT)0;   \n"
            "    output.Position = position;        \n"
            "    output.Texcoord = texcoord;        \n"
            "    return output;                     \n"
            "}                                      \n";
        std::vector<D3D11_INPUT_ELEMENT_DESC> inputDesc =
        {
            { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0,                            0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
            { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT,    0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0 }
        };
        Tie2(_vertexShader, _inputLayout, CreateVertexShader(_device, vertexCode, inputDesc));

        std::string pixelCode =
            "Texture2D texture0 : register(t0);                      \n"
            "SamplerState texture0Sampler {                          \n"
            "   Filter = MIN_MAG_MIP_POINT;                          \n"
            "   AddressU = Clamp;                                    \n"
            "   AddressV = Clamp;                                    \n"
            "};                                                      \n"
            "float4 main(                                            \n"
            "    float4 position : SV_POSITION,                      \n"
            "    float2 texcoord : TEXCOORD0) : SV_TARGET {          \n"
            "    return texture0.Sample(texture0Sampler, texcoord);  \n"
            "}                                                       \n";
        _pixelShader = CreatePixelShader(_device, pixelCode);

        // VertexBuffer作成
        std::vector<Vertex3> vertices =
        {
            { -1.0f,  1.0f, 0.5f, 0.0f, 0.0f },
            {  1.0f,  1.0f, 0.5f, 1.0f, 0.0f },
            { -1.0f, -1.0f, 0.5f, 0.0f, 1.0f },
            {  1.0f, -1.0f, 0.5f, 1.0f, 1.0f },
        };
        _vertexBuffer = CreateVertexBuffer(_device, vertices);

        // テクスチャ作成
        pin_ptr<byte> pixelsPtr = &pixels[0];
        _texture = CreateTexture(_device, width, height, pixelsPtr);

        // 描画準備
        ID3D11RenderTargetView* renderTargets[1] = { _renderTarget };
        _context->OMSetRenderTargets(1, renderTargets, NULL);

        _context->VSSetShader(_vertexShader, NULL, 0);
        _context->PSSetShader(_pixelShader, NULL, 0);
        _context->IASetInputLayout(_inputLayout);

        UINT stride = sizeof(Vertex3);
        UINT offset = 0;
        ID3D11Buffer* vertexBuffers[1] = { _vertexBuffer };
        _context->IASetVertexBuffers(0, 1, vertexBuffers, &stride, &offset);

        ID3D11ShaderResourceView* resourceViews[1] = { _texture };
        _context->PSSetShaderResources(0, 1, resourceViews);

        D3D11_VIEWPORT viewport;
        viewport.Width = (float)width;
        viewport.Height = (float)height;
        viewport.MinDepth = 0.0f;
        viewport.MaxDepth = 1.0f;
        viewport.TopLeftX = 0.0f;
        viewport.TopLeftY = 0.0f;
        _context->RSSetViewports(1, &viewport);

        // 描画
        _context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
        _context->Draw(4, 0);

        _context->Flush();
    };
private:
    CliComPtr<IDirect3DDevice9Ex> _device9;
    CliComPtr<IDirect3DSurface9> _surface9;
    CliComPtr<ID3D11Device> _device;
    CliComPtr<ID3D11DeviceContext> _context;
    CliComPtr<ID3D11RenderTargetView> _renderTarget;
    CliComPtr<ID3D11VertexShader> _vertexShader;
    CliComPtr<ID3D11InputLayout> _inputLayout;
    CliComPtr<ID3D11PixelShader> _pixelShader;
    CliComPtr<ID3D11Buffer> _vertexBuffer;
    CliComPtr<ID3D11ShaderResourceView> _texture;
};


WPF

下記記事のものと同じコードを利用します。
WPFとDirect3D9Exの連携 --- テクスチャ貼り付け - 何でもプログラミング

下記のようなウィンドウが表示されます。
f:id:any-programming:20170502180307p:plain