11月8日(2008)


ID3DX10Font->DrawText()による文字列の表示

便利なようで結構融通が利かないこの関数、…っていうかインターフェース。
指定フォントでテクスチャを生成するのは便利でいいんだけど、色々と問題や
不可解なことが多い。

謎(もしくはまだ理解していないか)
  • 指定した文字セットでテクスチャを作ってくれるのはありがたいのだが、実際に生成されたテクスチャを見てみると無駄なスペースが空いていることがある
  • フォントによっては小さい文字サイズにすると文字がくずれる(TTフォントっぽいのに。しかもTT指定してるのに…。
    ちなみにArialフォントはどんなサイズでも結構イケる。
  • ミップマップ指定でテクスチャを作ってもちゃんと生成されているのか?サブリソース的なアクセスをすることで使用可能なのか?っていうかDrawText()自体サイズも指定できないしミップマップレベルも指定できないから意味がないのでは?
  • z値の指定はどこでやるの?つーかデプステストすらやってないっぽいんですが…。

などなど。
とりあえず何をやってるか知りたいので

ID3DX10Sprite->Begin()
ID3DX10Font->DrawText()
ID3DX10Sprite->End()

の流れで内部ではどうなっているかをPIXで追ってみた。
DirectX処理のみになっちゃうけど…

ID3D10StateBlock::Apply()
ID3D10StateBlock::Capture()
ID3D10Device::IASetInputLayout(0x06DDBB18)
ID3D10Device::IASetPrimitiveTopology(D3D10_PRIMITIVE_TOPOLOGY_POINTLIST)>ID3D10Device::IASetVertexBuffers(0, 1, 0x01EE97D4 --> { 0x06DDC5C0 }, >0x0022EA80, 0x0022EA84)
ID3D10Device::OMSetBlendState(0x06DDCCF0, 0x0022E944, -1)
ID3D10Device::OMSetDepthStencilState(0x06DDFEB0, 0)
ID3D10Device::RSGetViewports(0x0022E96C, 0x0022E71C)
ID3D10Buffer::Map(D3D10_MAP_WRITE_DISCARD, 0, 0x0022EA94 --> 0x0A1D0E00)
ID3D10Buffer::Unmap()
ID3D10Buffer::Map(D3D10_MAP_WRITE_NO_OVERWRITE, 0, 0x0022EAB0 --> 0x0A1FA000)
ID3D10Device::PSSetShaderResources(0, 1, 0x0022EAA0 --> { 0x06DDA278 })
ID3D10Device::VSSetShader(0x06DDA200)
ID3D10Device::GSSetShader(0x06DD8BD0)
ID3D10Device::GSSetConstantBuffers(0, 1, 0x01EE97D8 --> { 0x06DDC468 })
ID3D10Device::PSSetSamplers(0, 1, 0x01EE97C8 --> { 0x06DD4FF0 })
ID3D10ShaderResourceView::GetDesc(0x0022EA7C)
ID3D10Device::PSSetShader(0x06DD5300)
ID3D10ShaderResourceView::GetDesc(0x0022EA7C)
ID3D10ShaderResourceView::GetDesc(0x0022EA7C)
ID3D10ShaderResourceView::GetDesc(0x0022EA7C)
ID3D10ShaderResourceView::GetDesc(0x0022EA7C)
ID3D10Buffer::Unmap()
ID3D10Device::Draw(5, 148)

ちなみにこの処理で1文字ではなく、指定文字列全て表示している。
…ということは、文字列としてのテクスチャを作ってそれを表示という形を取っていることがうかがえる。
それにしてもTopologyの指定がPOINTLISTって…。

ただなんとなく、文字列表示も自作で作ったほうがいいかな、っていう気分。
テクスチャ生成部分だけ使わせてもらおうか…。


ジオメトリシェーダーを使ってみた

ジオメトリシェーダーで頂点が増やせるっていうのがどんなもんか試してみた。
上手く使えてるかどうかは分からないが、個人的には面白い仕組みだなとは思う。

今回試したのは矩形の生ポリ表示。
頂点シェーダーに渡すパラメータとしては

  • 座標(矩形の中心)
  • カラー
  • 矩形サイズ

という感じ。これをジオメトリシェーダーで4頂点のトライアングルストリップに展開する。
ジオメトリシェーダーはプリミティブ単位でデータを受け取る。
そのため、上記の1データを1つのデータとして受け取るために、TopologyはPointListを使う。
ジオメトリシェーダー側としては入力はpointで、出力をTriangleStreamにする。
CPU側でPointList指定していても、シェーダー内で使用するストリームのほうが優先される(当たり前か)。
ジオメトリシェーダー内で4頂点を算出し、ストリームにセットすることで矩形表示が可能となる。

こうすることのメリットはシェーダーへ送るデータ量が激減するのと、それに伴って頂点バッファへの
書き込みも激減することである。

参考までに今回のシェーダー内容をば…

struct VS_InputRect2D {
   float3 pos : POSITION;
   float4 col : COLOR;
   float2 wh  : WH;
};

struct GS_InputRect2D {
   float4 pos : SV_POSITION;
   float4 col : COLOR;
   float2 wh  : WH;
};

struct PS_InputRect2D {
   float4 pos : SV_POSITION;
   float4 col : COLOR;
};

GS_InputRect2D VS_Rect2D( VS_InputRect2D _input )
{
   GS_InputRect2D output;
   
   // 頂点座標(スクリーン座標へ)
   output.pos.x = Client2ScreenX( _input.pos.x );
   output.pos.y = Client2ScreenY( _input.pos.y );
   output.pos.z = _input.pos.z;
   output.pos.w = 1.0f;
   
   output.col = _input.col;
	
   output.wh.x = _input.wh.x / scrn_width;
   output.wh.y = _input.wh.y / scrn_height;

   return output;
}

[maxvertexcount(128)]
void GS_Rect2D( point GS_InputRect2D _input[1], inout TriangleStream<PS_InputRect2D> _stream )
{
   PS_InputRect2D output;
   float w, h;
   
   // 左上
   output.pos.x = _input[0].pos.x - _input[0].wh.x;
   output.pos.y = _input[0].pos.y - _input[0].wh.y;
   output.pos.zw = _input[0].pos.zw;
   output.col = _input[0].col;
   _stream.Append( output );
   
   // 右上
   output.pos.x = _input[0].pos.x + _input[0].wh.x;
   output.pos.y = _input[0].pos.y - _input[0].wh.y;
   output.pos.zw = _input[0].pos.zw;
   output.col = _input[0].col;
   _stream.Append( output );
   
   // 左下
   output.pos.x = _input[0].pos.x - _input[0].wh.x;
   output.pos.y = _input[0].pos.y + _input[0].wh.y;
   output.pos.zw = _input[0].pos.zw;
   output.col = _input[0].col;
   _stream.Append( output );
   
   // 右下
   output.pos.x = _input[0].pos.x + _input[0].wh.x;
   output.pos.y = _input[0].pos.y + _input[0].wh.y;
   output.pos.zw = _input[0].pos.zw;
   output.col = _input[0].col;
   _stream.Append( output );
   
   _stream.RestartStrip();
}

float4 PS_Rect2D( PS_InputRect2D _input ) : SV_Target
{
   return _input.col;
}

technique10 RenderRect2D
{
   pass P0
   {
      SetVertexShader( CompileShader( vs_4_0, VS_Rect2D() ) );
      SetGeometryShader( CompileShader( gs_4_0, GS_Rect2D() ) );
      SetPixelShader( CompileShader( ps_4_0, PS_Rect2D() ) );
      
      // ラスタライザのステート設定
      SetRasterizerState( rs );
      
      // 出力マージャーのステート設定
      SetBlendState( bs[blend_type], float4(0.0f, 0.0f, 0.0f, 0.0f), 0xFFFFFFFF );
      SetDepthStencilState( dss, 0 );
   }
}
最終更新:2008年11月08日 21:01
ツールボックス

下から選んでください:

新しいページを作成する
ヘルプ / FAQ もご覧ください。