Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationEventAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
10
Help us understand the problem. What are the problem?

More than 5 years have passed since last update.

DirectX(D3D11.1)再入門 Texture

気が変わったのでTextureを先にやる。
今回のコード

これもD3DX無き世界でどうするかとなるのだけどWindowsのWindowsImagingComponent略してWICを使ってみる。

今回のシェーダー
Texture2D diffuseTexture;
SamplerState diffuseTextureSampler;

struct VS_IN
{
    float4 Position: POSITION;
    float4 Color: COLOR;
    float2 Tex: TEXCOORD0;
};

struct VS_OUT
{
    float4 Position: SV_POSITION;
    float4 Color: COLOR;
    float2 Tex: TEXCOORD0;
};

typedef VS_OUT PS_IN;

//cbuffer buffer
//{
    float4x4 ModelMatrix;
//};

VS_OUT vsMain(VS_IN input)
{
    VS_OUT Output;
    Output.Position = mul(input.Position, ModelMatrix);
    Output.Color = input.Color;
    Output.Tex = input.Tex;
    return Output;    
}

float4 psMain(PS_IN input) : SV_TARGET
{
    float4 texel = diffuseTexture.Sample(diffuseTextureSampler, input.Tex);
    return input.Color * texel;
}

Texture2D(ShaderResourceView)とSamplerStateが増えてTextureの参照座標Texが頂点属性に追加になった。

増えた
// 定義
Texture2D diffuseTexture;
SamplerState diffuseTextureSampler;

struct VS_IN
{
    float4 Position: POSITION;
    float4 Color: COLOR;
    float2 Tex: TEXCOORD0; // 増えた
};

struct VS_OUT
{
    float4 Position: SV_POSITION;
    float4 Color: COLOR;
    float2 Tex: TEXCOORD0; // 増えた
};

// 使う
    float4 texel = diffuseTexture.Sample(diffuseTextureSampler, input.Tex);

プログラム側

デバイスからID3D11Texture2Dを作って、ID3D11Texture2DからID3D11ShaderResourceView(SRV)を作る。
SamplerStateも作る。
作ったSRVをデバイスコンテキストにセットする。
SamplerStateはセットしなくてもデフォルトのものが使われる(分かりにくい)。
謎のimageutil::ImageはWICから画像を読み込んだもの。次節で。

テクスチャクラス
class Texture
{
    Microsoft::WRL::ComPtr<ID3D11Texture2D> m_texture;
    Microsoft::WRL::ComPtr<ID3D11ShaderResourceView> m_srv; // これがhslslのtexture2Dになる
    Microsoft::WRL::ComPtr<ID3D11SamplerState> m_sampler; // これがhlslのSamplerStateになる

public:
    bool Initialize(const Microsoft::WRL::ComPtr<ID3D11Device> &device
            , const std::shared_ptr<imageutil::Image> &image)
    {
        D3D11_TEXTURE2D_DESC desc;
        desc.Width = image->Width();
        desc.Height = image->Height();
        desc.MipLevels = 1;
        desc.ArraySize = 1;
        desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
        desc.SampleDesc.Count = 1;
        desc.SampleDesc.Quality = 0;
        desc.Usage = D3D11_USAGE_DEFAULT;
        desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
        desc.CPUAccessFlags = 0;
        desc.MiscFlags = 0;

        D3D11_SUBRESOURCE_DATA initData;
        initData.pSysMem = image->Pointer();
        initData.SysMemPitch = image->Stride();
        initData.SysMemSlicePitch = image->Size();

        auto hr = device->CreateTexture2D(&desc, &initData, &m_texture);
        if (FAILED(hr)){
            return false;
        }

        D3D11_SHADER_RESOURCE_VIEW_DESC SRVDesc = {};
        SRVDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
        SRVDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
        SRVDesc.Texture2D.MipLevels = 1;

        hr = device->CreateShaderResourceView(m_texture.Get(), &SRVDesc, &m_srv);
        if (FAILED(hr))
        {
            return false;
        }

        D3D11_SAMPLER_DESC samplerDesc;
        samplerDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
        samplerDesc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP;
        samplerDesc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP;
        samplerDesc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP;
        samplerDesc.MipLODBias = 0.0f;
        samplerDesc.MaxAnisotropy = 1;
        samplerDesc.ComparisonFunc = D3D11_COMPARISON_ALWAYS;
        samplerDesc.BorderColor[0] = 0;
        samplerDesc.BorderColor[1] = 0;
        samplerDesc.BorderColor[2] = 0;
        samplerDesc.BorderColor[3] = 0;
        samplerDesc.MinLOD = 0;
        samplerDesc.MaxLOD = D3D11_FLOAT32_MAX;

        // Create the texture sampler state.
        hr = device->CreateSamplerState(&samplerDesc, &m_sampler);
        if(FAILED(hr))
        {
            return false;
        }

        return true;
    }

    void Set(const Microsoft::WRL::ComPtr<ID3D11DeviceContext> &deviceContext)
    {
        deviceContext->PSSetShaderResources(0, 1, m_srv.GetAddressOf());
        //deviceContext->PSSetSamplers(0, 1, m_sampler.GetAddressOf());
    }
};

WICで画像をロード

imageutil
    #pragma once
    #include <memory>
    #include <string>
    #include <vector>
    #include <wrl/client.h>


    struct IWICImagingFactory;

    namespace imageutil {

    class Image
    {
        std::vector<unsigned char> m_buffer;
        int m_width;
        int m_height;
        int m_pixelBytes;

    public:
        Image(int w, int h, int pixelBytes);
        int Width()const{ return m_width; }
        int Stride()const{ return m_width*m_pixelBytes; }
        int Height()const{ return m_height; }
        unsigned char* Pointer(){ return m_buffer.empty() ? nullptr : &m_buffer[0]; }
        size_t Size()const{ return m_buffer.size(); }
    };

    class Factory
    {
        IWICImagingFactory *m_factory;

    public:
        Factory();
        ~Factory();
        std::shared_ptr<Image> Load(const std::wstring &path);
    };

    }
使う
    auto wicFactory = std::make_shared<imageutil::Factory>();
        // 画像をロードする
        auto image=wicFactory->Load(textureFile);
        if(image){
            // テクスチャを作る
            if (!m_texture->Initialize(pDevice, image)){
                return false;
            }
        }

WICによる画像のロードはCOMプログラミングでございます。

WIC
    IWICImagingFactory *m_factory;
    HRESULT hr = CoCreateInstance(
        CLSID_WICImagingFactory,
        nullptr,
        CLSCTX_INPROC_SERVER,
        IID_PPV_ARGS(&m_factory)
        );

    // decoder作ってファイルを渡す
    Microsoft::WRL::ComPtr<IWICBitmapDecoder> decoder;
    HRESULT hr = m_factory->CreateDecoderFromFilename(path.c_str(), 0
            , GENERIC_READ, WICDecodeMetadataCacheOnDemand, &decoder);
    if(FAILED(hr)){
        return nullptr;
    }

    // decoderからframeを取得
    Microsoft::WRL::ComPtr<IWICBitmapFrameDecode> frame;
    hr = decoder->GetFrame(0, &frame);
    if(FAILED(hr)){
        return nullptr;
    }

    // フレームからサイズとピクセルフォーマットとデータを得る
    UINT width, height;
    hr = frame->GetSize( &width, &height );
    if(FAILED(hr)){
        return nullptr;
    }

    assert( width > 0 && height > 0 );

    // Determine format
    WICPixelFormatGUID pixelFormat;
    hr = frame->GetPixelFormat(&pixelFormat);
    if (FAILED(hr)){
        return nullptr;
    }

    if (pixelFormat != GUID_WICPixelFormat32bppRGBA){
        // 変換する
        Microsoft::WRL::ComPtr<IWICFormatConverter> FC;
        hr = m_factory->CreateFormatConverter(&FC);
        if(FAILED(hr)){
            return nullptr;
        }

        hr = FC->Initialize(frame.Get(), GUID_WICPixelFormat32bppRGBA
                , WICBitmapDitherTypeErrorDiffusion
                , 0, 0, WICBitmapPaletteTypeCustom);
        if(FAILED(hr)){
            return nullptr;
        }

        // copy
        auto image=std::make_shared<Image>(width, height, 4);
        FC->CopyPixels(0, image->Stride(), image->Size(), image->Pointer());
        return image;
    }
    else{
        // copy
        auto image = std::make_shared<Image>(width, height, 4);
        frame->CopyPixels(0, image->Stride(), image->Size(), image->Pointer());
        return image;
    }

WICで大概の画像(tgaは無かった)はロードできる。
GetPixelFormatで画素のフォーマットを得てID3D11Textureで使いやすい形に変換しましょうということであります。
要するにGUID_WICPixelFormat32bppRGBA以外をDXGI_FORMAT_R8G8B8A8_UNORMに相当するGUID_WICPixelFormat32bppRGBAに変換してやるといいのではないか。

ss.png

次回、賢いコンスタントバッファ。予定。

参考

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
10
Help us understand the problem. What are the problem?