★ DirectX Class ★ * Chapter 11: 立体に対するDDSファイルの利用 *
< プリミティブに適用する場合 >
夏です。
そろそろ怪談とかの季節ですね。
幽霊とかオバケとか怖いですね。
幽霊も怖いですが、昨今のモラルハザードを中心とした社会現象一般のほうがよっぽど怖いですね。
そして何より一番怖いのは金曜日まで¥1,800で過ごさなければならないということです。
請求書でも来ようものならひとたまりもありません。
早くもっと景気対策しろよハゲ。

プリミティブに利用する場合は少し複雑です。
プリミティブに半透明テクスチャを利用する場合について解説していきます。
< 必要な処理 >
まず、アルファ合成をするという設定をしなくてはなりません。
この設定は既定で使用しない設定になっているので、使用するように変更します。
それは以下の関数で実現できます。

g_pd3dDevice->SetRenderState( D3DRS_ALPHABLENDENABLE , TRUE );

おなじみのSetRenderStateです。
第一引数に『 D3DRS_ALPHABLENDENABLE 』を指定し、
第二引数に『 TRUE 』を指定します。
これでアルファブレンドが有効になります。

続いて、アルファブレンドをするにあたって、
『 ソースブレンディングステート 』及び『 デスティネーションブレンディングステート 』
設定する必要があります。
それは以下の関数を実行することによって実現できます。

g_pd3dDevice->SetRenderState( D3DRS_SRCBLEND  , D3DBLEND_SRCALPHA );
g_pd3dDevice->SetRenderState( D3DRS_DESTBLEND , D3DBLEND_INVSRCALPHA );

私自身あまり理解していないので上手く説明できませんが、
ブレンドするときの係数を設定するということのようです。

説明書によると、『 D3DBLEND_SRCALPHA 』という定数のブレンディング係数は、( A , A , A , A ) ということだそうです。
この4つの係数はそれぞれRGBAの要素になっていて、
色を表示するときに元にする係数が、全てアルファ値ということになります。

デスティネーションブレンディングステートに関しては割愛します。
祇園祭の宵山が気になってそれでころではありません。


続いて、テクスチャをテクスチャステージに設定した後にアルファの扱いについての設定をしなくてはなりません。
それは以下のコードによって実現します。

g_pd3dDevice->SetTextureStageState( 0 , D3DTSS_ALPHAARG1 , D3DTA_TEXTURE   );
g_pd3dDevice->SetTextureStageState( 0 , D3DTSS_ALPHAARG2 , D3DTA_DIFFUSE   );
g_pd3dDevice->SetTextureStageState( 0 , D3DTSS_ALPHAOP   , D3DTOP_MODULATE );

この『 SetTextureStageState 』メソッドはテクスチャのステージに対して各種設定を行います。
第一引数にはテクスチャのステージを、
第二引数には設定する項目を、
第三ステージには設定内容を指定します。

とりあえず、しばらくここはこのまま丸写しで大丈夫です。

以上で作業は完了です。
それでは早速描画してみましょう。
< サンプル >
このサンプルを実行すると、クライアント領域に不透明なプリミティブと半透明なプリミティブが描画され、回転します。
基盤としたプログラムは第9章のものと同じです。
但し、今回は第4章で利用したZバッファも使用しています。
Zバッファを使用しないと描画した順に重ねられるため、遠くにあるはずのものが近くのプリミティブより前に描画されるという
不具合を発生するからです。
実際にどうなるかは、サンプルプログラムのZバッファを無効にして試してみてください。

そろそろごちゃごちゃとしてきましたが、
『 プリミティブに透過テクスチャを使用する 』という部分以外はすでに以前の章で解説していますので、
諦めずに頑張ってください。
私も今日は忙しくて祇園祭に行けなさそうなのですが、諦めません!

サンプルプログラムをご利用の場合は、この画像を実行ファイルと同じディレクトリに入れて実行してください。

★透過DDS画像はこちら★

豹柄

ポイントはピンク色で示してあります。

//-----------------------------------------------------------------
//
//    DirectX 3D
//
//-----------------------------------------------------------------
#define sqrtf sqrt
#define sinf  sin
#define cosf  cos
#define tanf  tan

#include <stdio.h>
#include <windows.h>
#include <d3d9.h>
#include <d3dx9.h>

#pragma comment( lib , "d3d9.dll" )
#pragma comment( lib , "d3dx9.dll" )



//-----------------------------------------------------------------
//    Grobal Variables.
//-----------------------------------------------------------------
LPDIRECT3D9             g_pD3D       = NULL;
LPDIRECT3DDEVICE9       g_pd3dDevice = NULL;
LPDIRECT3DVERTEXBUFFER9 g_pVB        = NULL;
LPDIRECT3DVERTEXBUFFER9 g_pVBBG      = NULL;
LPDIRECT3DTEXTURE9      g_pTexture   = NULL;
LPDIRECT3DTEXTURE9      g_pTextureBG = NULL;

struct CUSTOMVERTEX
{
	FLOAT x , y , z;
	DWORD color;
	float tu , tv;
};

#define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZ|D3DFVF_DIFFUSE|D3DFVF_TEX1)



//-----------------------------------------------------------------
//    Prototypes.
//-----------------------------------------------------------------
HWND    InitApp( HINSTANCE , int );
BOOL    InitDirect3D( HWND );
BOOL    CleanupDirect3D();
BOOL    InitGeometry();
BOOL    SetupMatrices();
BOOL    RenderDirect3D();
LRESULT CALLBACK WndProc( HWND , UINT , WPARAM , LPARAM );



//-----------------------------------------------------------------
//    Main.
//-----------------------------------------------------------------
int WINAPI WinMain( HINSTANCE hInst , HINSTANCE hPrevinst , LPSTR nCmdLine , int nCmdShow )
{
	MSG msg;
	HWND hWnd;
	
	hWnd = InitApp( hInst , nCmdShow );
	if ( !hWnd ) return FALSE;
	
	if ( !InitDirect3D( hWnd ) ) return FALSE;
	if ( !InitGeometry() ) return FALSE;
	
	while( msg.message != WM_QUIT ){
		if ( PeekMessage( &msg , NULL , 0 , 0 , PM_REMOVE ) ){
			TranslateMessage( &msg );
			DispatchMessage( &msg );
		}else{
			RenderDirect3D();
		}
		Sleep( 1 );
	}
	
	return msg.wParam;
}



//-----------------------------------------------------------------
//    Initialize Application.
//-----------------------------------------------------------------
HWND InitApp( HINSTANCE hInst , int nCmdShow )
{
	WNDCLASS wc;
	HWND hWnd;
	char szClassName[] = "Direct3D Test";
	
	wc.style         = CS_HREDRAW | CS_VREDRAW;
	wc.hInstance     = hInst;
	wc.hCursor       = LoadCursor( NULL , IDC_ARROW );
	wc.hIcon         = LoadIcon( NULL , IDI_APPLICATION );
	wc.hbrBackground = (HBRUSH)GetStockObject( WHITE_BRUSH );
	wc.lpszClassName = szClassName;
	wc.lpszMenuName  = NULL;
	wc.lpfnWndProc   = WndProc;
	wc.cbWndExtra    = 0;
	wc.cbClsExtra    = 0;
	if ( !RegisterClass( &wc ) ) return FALSE;
	
	hWnd = CreateWindow( szClassName , "Direct3D Test" , WS_OVERLAPPEDWINDOW ,
						CW_USEDEFAULT , CW_USEDEFAULT , 640 , 480,
						NULL , NULL , hInst , NULL );
	if ( !hWnd ) return FALSE;
	
	ShowWindow( hWnd , nCmdShow );
	UpdateWindow( hWnd );
	
	return hWnd;
}



//-----------------------------------------------------------------
//    Initialize Direct3D.
//-----------------------------------------------------------------
BOOL InitDirect3D( HWND hWnd )
{
	D3DPRESENT_PARAMETERS d3dpp;
	HRESULT hr;
	
	if ( NULL == ( g_pD3D = Direct3DCreate9( D3D_SDK_VERSION ) ) ){
		MessageBox( hWnd , "Can't create Direct3D." , "Error" , MB_OK );
		return FALSE;
	}
	ZeroMemory( &d3dpp , sizeof( d3dpp ) );
	d3dpp.Windowed         = TRUE;
	d3dpp.SwapEffect       = D3DSWAPEFFECT_DISCARD;
	d3dpp.BackBufferFormat = D3DFMT_UNKNOWN;
	d3dpp.EnableAutoDepthStencil = TRUE;
	d3dpp.AutoDepthStencilFormat = D3DFMT_D16;
	
	hr = g_pD3D->CreateDevice( D3DADAPTER_DEFAULT , D3DDEVTYPE_HAL , hWnd ,
	                           D3DCREATE_SOFTWARE_VERTEXPROCESSING ,
	                           &d3dpp , &g_pd3dDevice );
	if ( FAILED( hr ) ){
		MessageBox( hWnd , "Can't create device." , "Error" , MB_OK );
		return FALSE;
	}
	
	g_pd3dDevice->SetRenderState( D3DRS_CULLMODE         , D3DCULL_NONE );
	g_pd3dDevice->SetRenderState( D3DRS_LIGHTING         , FALSE );
	
	g_pd3dDevice->SetRenderState( D3DRS_ZENABLE , TRUE );
	
	g_pd3dDevice->SetRenderState( D3DRS_ALPHABLENDENABLE , TRUE );
	g_pd3dDevice->SetRenderState( D3DRS_SRCBLEND         , D3DBLEND_SRCALPHA );
	g_pd3dDevice->SetRenderState( D3DRS_DESTBLEND        , D3DBLEND_INVSRCALPHA );
	
	D3DXCreateTextureFromFile( g_pd3dDevice , "sample0011.dds"   , &g_pTexture );
	D3DXCreateTextureFromFile( g_pd3dDevice , "sample0011_1.bmp" , &g_pTextureBG );
	
	return TRUE;
}



//-----------------------------------------------------------------
//    Cleanup Direct3D.
//-----------------------------------------------------------------
BOOL CleanupDirect3D()
{
	if ( g_pTexture != NULL )
		g_pTexture->Release();
	
	if ( g_pTextureBG != NULL )
		g_pTextureBG->Release();
	
	if ( g_pVB != NULL )
		g_pVB->Release();
	
	if ( g_pVBBG != NULL )
		g_pVBBG->Release();
	
	if ( g_pd3dDevice != NULL )
		g_pd3dDevice->Release();
	
	if ( g_pD3D != NULL )
		g_pD3D->Release();
	
	return TRUE;
}



//-----------------------------------------------------------------
//    Window Proc.
//-----------------------------------------------------------------
LRESULT CALLBACK WndProc( HWND hWnd , UINT msg , WPARAM wp , LPARAM lp )
{
	switch( msg ){
		case WM_DESTROY:
			CleanupDirect3D();
			PostQuitMessage( 0 );
			break;
		default:
			return DefWindowProc( hWnd , msg , wp , lp );
	}
	
	return 0L;
}



//-----------------------------------------------------------------
//    Initialize Geometry.
//-----------------------------------------------------------------
BOOL InitGeometry()
{
	HRESULT hr;
	VOID *pVertices;
	
	CUSTOMVERTEX Vertices[] =
	{
		{ -1.0f , -1.0f , 0.0f , 0xFFFFFFFF , 0.0f , 1.0f } ,
		{ -1.0f ,  1.0f , 0.0f , 0xFFFFFFFF , 0.0f , 0.0f } ,
		{  1.0f ,  1.0f , 0.0f , 0xFFFFFFFF , 1.0f , 0.0f } ,
		{  1.0f , -1.0f , 0.0f , 0xFFFFFFFF , 1.0f , 1.0f } ,
	};
	
	hr = g_pd3dDevice->CreateVertexBuffer(
		4 * sizeof( CUSTOMVERTEX ) ,
		0 ,
		D3DFVF_CUSTOMVERTEX ,
		D3DPOOL_DEFAULT ,
		&g_pVB ,
		NULL
	);
	if ( FAILED( hr ) ){
		MessageBox( NULL , "Couldn't create vertex buffer" , "Error" , MB_OK );
	}
	
	g_pVB->Lock( 0 , sizeof( Vertices ) , ( void** )&pVertices , 0 );
	memcpy( pVertices , Vertices , sizeof( Vertices ) );
	g_pVB->Unlock();
	
	CUSTOMVERTEX VerticesBG[] =
	{
		{ -1.0f , -1.0f , 1.0f , 0xFFFFFFFF , 0.0f , 1.0f } ,
		{ -1.0f ,  1.0f , 1.0f , 0xFFFFFFFF , 0.0f , 0.0f } ,
		{  1.0f ,  1.0f , 1.0f , 0xFFFFFFFF , 1.0f , 0.0f } ,
		{  1.0f , -1.0f , 1.0f , 0xFFFFFFFF , 1.0f , 1.0f } ,
	};
	
	hr = g_pd3dDevice->CreateVertexBuffer(
		4 * sizeof( CUSTOMVERTEX ) ,
		0 ,
		D3DFVF_CUSTOMVERTEX ,
		D3DPOOL_DEFAULT ,
		&g_pVBBG ,
		NULL
	);
	if ( FAILED( hr ) ){
		MessageBox( NULL , "Couldn't create vertex buffer" , "Error" , MB_OK );
	}
	
	g_pVBBG->Lock( 0 , sizeof( VerticesBG ) , ( void** )&pVertices , 0 );
	memcpy( pVertices , VerticesBG , sizeof( VerticesBG ) );
	g_pVBBG->Unlock();
	
	return TRUE;
}



//-----------------------------------------------------------------
//    Setup Matrices.
//-----------------------------------------------------------------
BOOL SetupMatrices()
{
	D3DXMATRIXA16 matWorld , matView , matProj;
	D3DXVECTOR3 vEyePt , vLookatPt , vUpVec;
	
	// World Matrix.
	D3DXMatrixRotationY( &matWorld , timeGetTime()/1000.0f );
	g_pd3dDevice->SetTransform( D3DTS_WORLD , &matWorld );
	
	// Camera.
	vEyePt.x    = 0.0f;
	vEyePt.y    = 3.0f;
	vEyePt.z    = 0.0f-5.0f;
	vLookatPt.x = 0.0f;
	vLookatPt.y = 0.0f;
	vLookatPt.z = 0.0f;
	vUpVec.x    = 0.0f;
	vUpVec.y    = 1.0f;
	vUpVec.z    = 0.0f;
	D3DXMatrixLookAtLH( &matView , &vEyePt , &vLookatPt , &vUpVec );
	g_pd3dDevice->SetTransform( D3DTS_VIEW , &matView );
	
	// Projection Matrix.
	D3DXMatrixPerspectiveFovLH( &matProj , 3.0f / 4.0f , 1.0f , 1.0f , 100.0f );
	g_pd3dDevice->SetTransform( D3DTS_PROJECTION , &matProj );
	
	return TRUE;
}



//-----------------------------------------------------------------
//    Render Direct3D.
//-----------------------------------------------------------------
BOOL RenderDirect3D()
{
	RECT rc;
	D3DXVECTOR3 center , position;
	
	g_pd3dDevice->Clear( 0 , NULL , D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER ,
	                     0x00000000 , 1.0f , 0 );
	
	g_pd3dDevice->BeginScene();
	
	SetupMatrices();
	
	// Leopard
	g_pd3dDevice->SetTexture( 0 , g_pTextureBG );
	g_pd3dDevice->SetStreamSource( 0 , g_pVBBG , 0 , sizeof( CUSTOMVERTEX ) );
	g_pd3dDevice->SetFVF( D3DFVF_CUSTOMVERTEX );
	g_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLEFAN , 0 , 2 );
	
	// Fractal
	g_pd3dDevice->SetTexture( 0 , g_pTexture );
	g_pd3dDevice->SetTextureStageState( 0 , D3DTSS_ALPHAARG1 , D3DTA_TEXTURE   );
	g_pd3dDevice->SetTextureStageState( 0 , D3DTSS_ALPHAARG2 , D3DTA_DIFFUSE   );
	g_pd3dDevice->SetTextureStageState( 0 , D3DTSS_ALPHAOP   , D3DTOP_MODULATE );
	
	g_pd3dDevice->SetStreamSource( 0 , g_pVB , 0 , sizeof( CUSTOMVERTEX ) );
	g_pd3dDevice->SetFVF( D3DFVF_CUSTOMVERTEX );
	g_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLEFAN , 0 , 2 );
	
	g_pd3dDevice->EndScene();
	
	g_pd3dDevice->Present( NULL , NULL , NULL , NULL );
	
	return TRUE;
}

実行結果

クリックすると実物大で表示されます。
執筆: 2009/07/16 (THU)