気が変わったので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で画像をロード
#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プログラミングでございます。
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に変換してやるといいのではないか。
次回、賢いコンスタントバッファ。予定。