Microsoft Visual Studio .NET 2003 Microsoft DirectX 9.0 SDK (December 2004) |
■ミップマップ | Prev Top Next |
今回は、ミップマップについてです。
ミップマップは、もとの画像を徐々を低解像度に変換していき、それらの画像を集めたものです。
低解像度に変換するとき、各画像の高さと幅は、直前のサイズの2分の1になります。
> | > | > | > | > | > | > | > | |||||||||
256 x 128 | 128 x 64 | 64 x 32 | 32 x 16 | 16 x 8 | 8 x 4 | 4 x 2 | 2 x 1 | 1 x 1 |
カメラ位置に近いオブジェクトには、高解像度ミップマップ画像が使われます。オブジェクトが遠ざかるに従って、低解像度のミップマップ画像が使われます。
ミップマップを使用すると、レンダリングしたテクスチャの品質が向上したり、1フレームのレンダリングに要する時間を短縮することができます。
ただし使用するテクスチャーの数が多くなるのでメモリの使用量は多くなります。本来はメモリ容量をチェックしてミップマップを使用するかしないかを決定すべきなんだろうなあ。
---main.cpp---
LPDIRECT3D9 m_pdirect3d9; LPDIRECT3DDEVICE9 m_pd3dDevice; LPDIRECT3DTEXTURE9 m_pMipMap = NULL; int APIENTRY WinMain( HINSTANCE hInstance, HINSTANCE /*hPrevInstance*/, LPSTR /*lpCmpLine*/, INT /*nCmdShow*/) { //**************************************************************** //ここでウィンドウクラスの登録処理とウィンドウの作成を行う。 //**************************************************************** //**************************************************************** //ここでDirect3Dの初期化を行う。なお、ディスプレイフォーマットはD3DFMT_X8R8G8B8を使用する。 //**************************************************************** HRESULT hr = E_FAIL; D3DCAPS9 caps; //**************************************************************** //ミップマップを作成 //**************************************************************** //ミップマップの自動生成をサポートするかを調査する。(注意1) m_pd3dDevice->GetDeviceCaps( &caps ); if( caps.Caps2 & D3DCAPS2_CANAUTOGENMIPMAP ) { //D3DFMT_X8R8G8B8フォーマットのテクスチャでミップマップの自動生成をサポートするかを調査する。 hr = m_pdirect3d9->CheckDeviceFormat( D3DADAPTER_DEFAULT, //調査対象のディスプレイ アダプタ。Direct3Dの初期化で指定した値と同じにする。 D3DDEVTYPE_HAL, //デバイス タイプ。Direct3Dの初期化で指定した値と同じにする。 D3DFMT_X8R8G8B8, //ディスプレイフォーマット。Direct3Dの初期化で指定した値と同じにする。 D3DUSAGE_AUTOGENMIPMAP, //ミップマップの自動生成をサポートするか。 D3DRTYPE_TEXTURE, //テクスチャーについて調査する。 D3DFMT_X8R8G8B8 ); //テクスチャーのフォーマット。 switch( hr ) { case D3DOK_NOAUTOGEN: //テクスチャーの作成は成功するが、ミップマップは生成されないとオンラインヘルプにはあるが、環境がないので未確認。オンラインヘルプを信じるならミップマップレベル1のみ作成される。 break; } } if( SUCCEEDED( hr ) ) { //テクスチャーを作成。 D3DXCreateTextureFromFileEx( m_pd3dDevice, _T("res\\01.bmp"), D3DX_DEFAULT, D3DX_DEFAULT, 0, //作成するミップマップの数。この値が 0 または D3DX_DEFAULT の場合は、ミップマップ サーフェイスのサイズが1 x 1になるまで作成される。 0, D3DFMT_UNKNOWN, D3DPOOL_MANAGED, D3DX_DEFAULT, D3DX_DEFAULT, 0, NULL, NULL, &m_pMipMap ); } else { //ミップマップの自動生成がサポートされていない。この場合は手動で。 } ::ShowWindow(hWnd, SW_SHOW); ::UpdateWindow(hWnd); //**************************************************************** //ここでメッセージループ処理を行う。 //**************************************************************** } BOOL MainLoop() { //**************************************************************** //シーンのクリア //**************************************************************** m_pd3dDevice->Clear( 0L, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER | D3DCLEAR_STENCIL, 0x0, 1.0f, 0L ); m_pd3dDevice->BeginScene(); //**************************************************************** //シーンのレンダリング //**************************************************************** //ライティングを無効にする。 m_pd3dDevice->SetRenderState( D3DRS_LIGHTING, FALSE ); //Zバッファを無効にする。 m_pd3dDevice->SetRenderState( D3DRS_ZENABLE, FALSE ); D3DXMATRIX matProj, matView, matWorld; //射影座標変換 D3DXMatrixPerspectiveFovLH( &matProj, D3DX_PI/4.0f, 4.0f / 3.0f, 0.1f, //0.0fを設定するとワーニングエラーが発生するので少し遠くに設定する。 500.0f ); m_pd3dDevice->SetTransform( D3DTS_PROJECTION, &matProj ); //ビュー座標変換 D3DXMatrixIdentity( &matView ); m_pd3dDevice->SetTransform( D3DTS_VIEW, &matView ); //ワールド座標変換 D3DXMatrixIdentity( &matWorld ); m_pd3dDevice->SetTransform( D3DTS_WORLD, &matWorld ); //拡大フィルター m_pd3dDevice->SetSamplerState( 0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR ); //縮小フィルター m_pd3dDevice->SetSamplerState( 0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR ); //ミップマップ使用時のフィルターを設定する。 //D3DTEXF_NONEを指定するとミップマップを使用しない。デフォルトでD3DTEXF_NONEに設定されているので変更すること。 m_pd3dDevice->SetSamplerState( 0, D3DSAMP_MIPFILTER, D3DTEXF_LINEAR ); //ミップマップの詳細レベル (LOD) バイアスを指定する。(注意2) float LODBias = 0; m_pd3dDevice->SetSamplerState( 0, D3DSAMP_MIPMAPLODBIAS, *((LPDWORD)(&LODBias)) ); m_pd3dDevice->SetFVF( D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_TEX1 ); m_pd3dDevice->SetTexture( 0, m_pMipMap ); typedef struct _VERTEX { D3DXVECTOR3 pos; D3DCOLOR color; float tu; float tv; }VERTEX; VERTEX v[4]; v[0].color = D3DCOLOR_XRGB(255,255,255); v[1].color = D3DCOLOR_XRGB(255,255,255); v[2].color = D3DCOLOR_XRGB(255,255,255); v[3].color = D3DCOLOR_XRGB(255,255,255); v[0].tu = 0.0f; v[0].tv = 0.0f; v[1].tu = 3.0f; v[1].tv = 0.0f; v[2].tu = 0.0f; v[2].tv = 3.0f; v[3].tu = 3.0f; v[3].tv = 3.0f; m_pd3dDevice->DrawPrimitiveUP( D3DPT_TRIANGLESTRIP, 2, v, sizeof( VERTEX ) ); v[0].pos.x = -300.0f; v[0].pos.y = -10.0f; v[0].pos.z = 500.0f; v[1].pos.x = 300.0f; v[1].pos.y = -10.0f; v[1].pos.z = 500.0f; v[2].pos.x = -300.0f; v[2].pos.y = -20.0f; v[2].pos.z = 20.0f; v[3].pos.x = 300.0f; v[3].pos.y = -20.0f; v[3].pos.z = 20.0f; m_pd3dDevice->DrawPrimitiveUP( D3DPT_TRIANGLESTRIP, 2, v, sizeof( VERTEX ) ); m_pd3dDevice->EndScene(); m_pd3dDevice->Present( NULL, NULL, NULL, NULL ); return TRUE; }
上の画像はミップマップ未使用と、ミップマップ使用時のレンダリング結果を表示しています。
上面がミップマップ未使用時パターンで、下面がミップマップ使用時パターンです。ミップマップのサイズが1 x 1になるまで作成されているので、奥のほうがかなりぼけています。
もっとくっきりさせたいときは、ミップマップの作成数を少なくすればよいので、この辺はアプリケーションごとに調整を行ってください。
(注意1) ミップマップの自動生成がハードウェアでサポートされるかを調査します。有効な場合、面倒なことをしなくてもミップマップの作成と使用が可能です。
さて、サポートされてない場合は自分で実装する必要があるのですが、方法が思いつかないなあ。
(注意2) これは、使用するミップマップの範囲をテクスチャーのサイズの大きい方か小さい方どちらか一方に偏らせることです。
バイアスに負の数を指定すると画面奥がくっきりレンダリングされるようになります。逆に正の数を指定すると画面手前がぼけてレンダリングされるようになります。
さて、使い道ですがRPGとかで画面切り替えを行うときのブラー処理でいけるような気もするが、オブジェクトの輪郭は残るよな。びみょー。