goo blog サービス終了のお知らせ 

TECOの技術研究室

TECOです。主に、プログラミングについて、エンタテイメントに繋がる技術研究の一部を書き留めます。

サンプラーステートについて、OpenGL vs DX9 vs DX11

2011-03-30 13:25:26 | プログラミング
いきなりの記事は、作業メモ。
現在の作業についてはおいおいまとめる。

カテゴリーにメモ用とついている記事は、自分用の記事です。
読み手に対して、理解したことを共有するための記事には(メモ用)というカテゴリには入りませんのであしかわらず。

調査案件=================================

テクスチャのサンプラーステート(アドレッシングモード、フィルタリングモードなどなど)の設定は、以下の方法で行うことができる。

OpenGL: glTexParameteri関数
DirectX9: SetSamplerState関数で、要素別に設定
DirectX11: CreateSamplerStateでサンプラーステートを作成して、シェーダ毎にSetSamplerStateで設定。

違いについて調査せよ。
調査結果を追記せよ。

調査現状報告(4/1)========================

OpenGLとDX9とDX11では思想が異なることが判明。

■OpenGLはglGenTextureで生成したテクスチャ毎でサンプラーステートを設定しなければならない。

 → glTexParameterを呼ぶと、その時点でglBindTextureを利用してバインドされているテクスチャにのみ設定は反映される。テクスチャ毎にサンプラーステートを持っているイメージ。
 → glBindTextureでテクスチャを切り替える度に、サンプラーステートも変わる。
 → だからテクスチャを何もバインドしていない状態でglGetTexParameterを呼んでも正しい値は取得できない。
 → マルチテクスチャを利用して複数のステージに同じテクスチャを設定してしかしサンプラーステートは違うよ、ということができるのかは未確認。
 → DirectXと同様の概念は、SampleObjectを利用すれば導入可能。しかしOpenGL3.2以降。



// テクスチャ2つ生成
glEnable( GL_TEXTURE_2D );
GLuint textures[2];
glGenTextures( 2 , &textures );

GLuint result;
glGetTexParameteriv( GL_TEXTURE_2D , GL_TEXTURE_MIN_FILTER , &result ); // 1

// テクスチャ0をバインド
glBindTexture( GL_TEXTURE_2D , textures[0] );
glGetTexParameteriv( GL_TEXTURE_2D , GL_TEXTURE_MIN_FILTER , &result ); // 2
glTexParameteri( GL_TEXTURE_2D , GL_TEXTURE_MIN_FILTER , GL_NEAREST );
glGetTexParameteriv( GL_TEXTURE_2D , GL_TEXTURE_MIN_FILTER , &result ); // 3

// テクスチャ1をバインド
glBindTexture( GL_TEXTURE_2D , textures[1] );
glGetTexParameteriv( GL_TEXTURE_2D , GL_TEXTURE_MIN_FILTER , &result ); // 4
glTexParameteri( GL_TEXTURE_2D , GL_TEXTURE_MIN_FILTER , GL_LINEAR );
glGetTexParameteriv( GL_TEXTURE_2D , GL_TEXTURE_MIN_FILTER , &result ); // 5

// テクスチャ0をバインド
glBindTexture( GL_TEXTURE_2D , textures[0] );
glGetTexParameteriv( GL_TEXTURE_2D , GL_TEXTURE_MIN_FILTER , &result ); // 6




コメント1,2,3,4,5,6でresultに入る値は以下の通り

1.不正値
2.GL_NEAREST_MIPMAP_LINEAR.(デフォルト設定値)
3.GL_NEAREST
4.GL_NEAREST_MIPMAP_LINEAR.(デフォルト設定値)
5.GL_LINEAR
6.GL_NEAREST

よって、サンプラはテクスチャステージ毎ではなくテクスチャ毎に設定されていることが分かる。

注) デフォルト値がGL_NEAREST_MIPMAP_LINEARのため、サンプラーの設定をしていない場合はミップマップ設定をしないと正しくテクスチャが描画されないよ。

■DX9は、テクスチャステージ毎にサンプラーステートを設定すればよいイメージ?
 → SetSamplerStateでサンプラーインデックス0で設定した値は、SetTextureでステージ0に設定したテクスチャに反映されるぽい。
 → SetTextureで、ステージ0に別のテクスチャを設定してもサンプラーステートの設定は変わらない。あくまでもステージ0に設定しているテクスチャのサンプラーステートというイメージ。
 → なのでOpenGLみたいに、テクスチャをバインドする前に設定も可能。



LPDIRECT3DDEVICE9 device = GetCurrentDevice();

// テクスチャを二つ生成
LPDIRECT3DTEXTURE9 texture[2];
D3DXCreateTextureFromFile( device, "test0.bmp", &texture );
D3DXCreateTextureFromFile( device, "test1.bmp", &texture );

DWORD result;
device->GetSamplerState( 0 , D3DSAMP_MINFILTER , &result ); // 1

// テクスチャ0
device->SetTexture( 0 , texture[0] );
device->GetSamplerState( 0 , D3DSAMP_MINFILTER , &result ); // 2
device->SetSamplerState( 0 , D3DSAMP_MINFILTER , D3DTEXF_POINT );
device->GetSamplerState( 0 , D3DSAMP_MINFILTER , &result ); // 3

// テクスチャ1
device->SetTexture( 0 , texture[1] );
device->GetSamplerState( 0 , D3DSAMP_MINFILTER , &result ); // 4
device->SetSamplerState( 0 , D3DSAMP_MINFILTER , D3DTEXF_LINEAR );
device->GetSamplerState( 0 , D3DSAMP_MINFILTER , &result ); // 5

// テクスチャ0をバインド
device->SetTexture( 0 , texture[0] );
device->GetSamplerState( 0 , D3DSAMP_MINFILTER , &result ); // 6




コメント1,2,3,4,5,6でresultに入る値は以下の通り

1.D3DTEXF_POINT(デフォルト設定値)
2.D3DTEXF_POINT
3.D3DTEXF_POINT
4.D3DTEXF_POINT
5.D3DTEXF_LINEAR
6.D3DTEXF_LINEAR

よって、サンプラはテクスチャ毎ではなくテクスチャステージ毎に設定されていることが分かる。

■DX11は、テクスチャとサンプラーステートが完全に独立している。
→ シェーダ側で、任意のテクスチャを任意のサンプラーを利用してサンプリングできる。
 → シェーダ毎にサンプラーステートを設定する必要がある



ID3D11Device* device = GetCurrentDevice();

// サンプラーステートを生成
ID3D11SamplerState* samplerState = NULL;
D3D11_SAMPLER_DESC samplerDesc;
setDefault( samplerDesc ); // 適当に初期化
device->CreateSamplerState( &samplerDesc , samplerState );

// サンプラーステートをピクセルシェーダのスロット0に設定
device->PSSetSamplers( 0, 1, &samplerState );




 テクスチャとサンプラーステートの関連性は一切ないのでシェーダ側でどれを利用するかは決める必要がある。
 以下にそのサンプルコードを記述しておく。



Texture2D inputTexture
SamplerState inputSampler

float psMain( VS_OUT In ) : SV_TARGET
{
float col = inputTexture.Sample( inputSampler , In.texcoord );
return col;
}




■ ラッピングの方針
 OpenGL4.0の資料を見ていると、サンプラーについての概念はDirectXの概念と同じになろうとしている。
 なので、基本的にはDX11を意識したAPIにする。
 OpenGLとDX9の挙動は同じにする。ただスロット0に設定したサンプラーステートは、テクスチャステージ0に設定したテクスチャに関連付くことにする。

 OpenGLのglTexParameteriの挙動に関して確認しなければならないことがある。
  → 異なるテクスチャステージに同じテクスチャをバインドした場合、サンプラステートを別々に設定することは可能かどうか
   → もし別々に設定できない場合、DX9と挙動が違う部分になってしまう。
    → ただ異なるテクスチャステージに同じテクスチャをバインドすることは無いと思うので、複数のテクスチャステージに一つのテクスチャを設定できなくするのも手。


=============================