ページ 11

【DirectX】別環境におけるビルボードのサイズが変わる現象について

Posted: 2015年12月21日(月) 16:27
by pico_pico
お世話になります。

【問題】
複数の絵が描かれた一枚の画像から、特定領域をトリミングしてビルボードに貼りつけて描画しています。
開発環境(デスクトップPC)と実行環境(ミニノートPC)が異なる場合、
ソースコードは開発環境と実行環境で同じですが、ビルボードの描画に差異が表れました。(参照画像参照)

テクスチャのトリミングエリアを開発環境では「0.25f」単位にしておりましたが、
試しに実行環境では固有値として「0.178f」に変更したところ、なんとか正常に描画されました。
(しかしこれではこのノートPC専用の値のため、意味がほとんどない対処法となってしまいます)

<質問①>
実行環境ごとにトリミングエリアの幅を自動で調整するプログラムを書ければ解決できると考えますが、
何が原因となっており、どういった要素から適正な値を算出すれば良いのか分からなかったため、
実行環境によって自動でトリミングの単位を算出するコードが書けておりません。
(モニタ解像度、ビデオカード、DirectXのバージョン辺りが怪しそうな雰囲気は有りますが解決策導き出せず…)
このような場合の解決策をご教授頂けないでしょうか。
何卒よろしくお願いいたします。

<質問②>
参照画像の通り、描画する座標も若干ずれてしまっています。
問題①と関連した無いようになりそうですが、なにかコメントを頂けたら幸いです。

<質問③>
開発環境では以下のコードを入れるとユニットビルボードを反転できましたが、
実行環境では反転できませんでした。
推測される原因についてご教示お願いいたします。

コード:

 D3DXMatrixScaling(&m_world, -1.0f, 1.0f, 1.0f); //これを入れると画像を反転できる 

※質問①②③に対して、上記状況だけでも思い当たることがあれば気軽に書いて頂けると嬉しいです。
 (関連コードが煩雑であるため、読む方に負担と思われるため。あと少し急ぎの案件ということもあり)
---------------------------------------------------------------
【開発環境 】
OS : Windows8.1 
コンパイラ名 : VC++ 2008EE
DirectX9で開発しています。VC++のF5でビルドしています。
補足:Direct11もPCにはインストール済

【実行環境】
OS:Windows7
コンパイラ名 : VC++ 2008EE
DirectX9使用。VC++のF5でビルドしたら上記の結果になります。
補足:Direct11もPCには最初からインストール済
---------------------------------------------------------------
【コード】
ビルボードに関するコードの一部を記載いたします。
冗長になるため、必要じゃなさそうな部分は載せていませんが、
必要な部分が他にございましたらご指摘いただければ即コピペします。

コード:

//-----------<テクスチャの読み込み(問題①②③共通)>-----------//

void CBillBoard::load_Image(LPCSTR filename)
{  
//テクスチャの読み込み
	D3DXGetImageInfoFromFile(filename, &Size);
 	D3DXCreateTextureFromFileEx(
		pD3DDevice,
		filename,
		Size.Width,
		Size.Height,
		0,
		0,
		D3DFMT_A8R8G8B8,//D3DFMT_UNKNOWN,
		D3DPOOL_MANAGED,
		D3DX_FILTER_NONE,
		D3DX_FILTER_NONE,
		0,
		NULL,
		NULL,
		&pTex);
}

CBillBoard::CBillBoard(LPCSTR filename)
{
	//描画リストに纏める時に、ユニットビルボードは変換する必要がある
	//オブジェクトはfalse
	set_UnitBillBoardFlag(false);

	load_Image(filename);

		//ポリゴン設定
	//頂点座標の設定(ローカル)
    VertexData[0].p = D3DXVECTOR3(1.0f, -1.0f, 0.0f );	//右下
    VertexData[1].p = D3DXVECTOR3(1.0f, 1.0f, 0.0f );	//右上
    VertexData[2].p = D3DXVECTOR3(-1.0f, -1.0f, 0.0f );	//左下
    VertexData[3].p = D3DXVECTOR3(-1.0f, 1.0f, 0.0f );	//左上

	// テクスチャ座標の設定(ポリゴンとは座標の種類が違うので注意)
    VertexData[0].t = D3DXVECTOR2(1.0f,1.0f);			//右下
    VertexData[1].t = D3DXVECTOR2(1.0f,0.0f);			//右上
    VertexData[2].t = D3DXVECTOR2(0.0f,1.0f);			//左下
    VertexData[3].t = D3DXVECTOR2(0.0f,0.0f);			//左上


	// 頂点カラーの設定
	VertexData[0].color = VertexData[1].color = VertexData[2].color = VertexData[3].color =(DWORD)D3DXCOLOR(1.0f, 0.0f, 0.0f, 1.0f);

	HRESULT hr;

//頂点バッファ作成(頂点4つ分)
	hr = pD3DDevice->CreateVertexBuffer(
		sizeof(CUSTOMVERTEX)*4,
		D3DUSAGE_WRITEONLY,
		FVF_CUSTOM,
		D3DPOOL_MANAGED,
		&pVertex,
		NULL);

//頂点バッファに登録
void *pData;
hr = pVertex->Lock(0, sizeof(CUSTOMVERTEX)*4, (void**)&pData, 0);

	if(hr == D3D_OK)
	{
		memcpy(pData, VertexData, sizeof(CUSTOMVERTEX)*4);
		pVertex->Unlock();
	}
	else
	{
		return;
	}
}

//------------------------<ここまで>---------------------------//


/-----------------------<ユニットの描画設定(問題①関係)>-----------------------//
void CMapUnitBillBoard::setup_AnimeTexture(int UnitAnimeMode,int TotalTexture, int (*pDrawAnimeArray)[FRONT_BACK])
{
	/*
		中略
	*/


//上記コードを継承しつつ、ユニットビルボードは途中で以下のようにしています。
//0.178fにすると開発環境と同じように描画されます。

		//テクスチャ座標を再セットする
		VertexData[0].t = D3DXVECTOR2(0.25f ,0.25f);//右下
		VertexData[1].t = D3DXVECTOR2(0.25f ,0.0f);	//右上
		VertexData[2].t = D3DXVECTOR2(0.0f ,0.25f);	//左下
		VertexData[3].t = D3DXVECTOR2(0.0f ,0.0f);	//左上

	/*
		中略
	*/
}
//------------------------<ここまで>---------------------------//



//------------------------<木や石の描画(問題②関係)>---------------------------//
void CBillBoard::draw_Model(D3DXMATRIX mat)
{

	ObjectMat = mat;

/////一般的なビルボードの描画設定/////
//テクスチャステージの設定
	// テクスチャステージの:RGBカラー要素の設定 
	pD3DDevice->SetTextureStageState( 0, D3DTSS_COLOROP,   D3DTOP_SELECTARG1);
	pD3DDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE );
	pD3DDevice->SetTextureStageState( 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE );


	// テクスチャステージの:アルファ要素の設定
	pD3DDevice->SetTextureStageState( 0, D3DTSS_ALPHAOP,   D3DTOP_MODULATE );

	//カメラの回転に対する逆行列を取得(正面を向かせるため)
	m_Inv = get_CameraInvMat();

	// 座標変換(モデルの配置) 
	D3DXMatrixIdentity(&m_world);

	D3DXMATRIX ObjectScaling;
	D3DXMatrixScaling(&ObjectScaling, 1.5f, 1.5f, 1.5f);
	D3DXMatrixMultiply( &m_world, &m_world, &m_Inv );
	D3DXMatrixMultiply( &m_world, &m_world, &ObjectScaling );
	D3DXMatrixMultiply( &m_world, &m_world, &ObjectMat );

	pD3DDevice->SetTransform(D3DTS_WORLD, &m_world);

//頂点バッファの更新
	void *pData;
	HRESULT hr;
	hr = pVertex->Lock(0, sizeof(CUSTOMVERTEX)*4, (void**)&pData, 0);

	if(hr == D3D_OK)
	{
		memcpy(pData, VertexData, sizeof(CUSTOMVERTEX)*4);
		pVertex->Unlock();
	}

	pD3DDevice->BeginScene();	// 描画開始
	// テクスチャをパイプラインにセット
	pD3DDevice->SetTexture( 0, pTex);
	pD3DDevice->SetStreamSource(0, pVertex, 0, sizeof(CUSTOMVERTEX));
	pD3DDevice->SetFVF(FVF_CUSTOM);
	pD3DDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);
	pD3DDevice->EndScene();		// 描画終了
}
//------------------------<ここまで>---------------------------//


//------------------------<<反転しない描画(問題③)>---------------------------//

void CMapUnitBillBoard::draw_Model(D3DXMATRIX UnitMat,int UnitDirection,int UnitAnimeMode)
{
	/*
	中略
	*/


/////////////////////<反転しない描画(問題③)>//////////////////////
	// 座標変換(モデルの配置) 
	//※ ほかの座標変換に影響されるのでちゃんと初期化する必要がある ※
	D3DXMatrixIdentity(&m_world);

	if(NowTexDirection == FRONT_RIGHT ||NowTexDirection == BACK_LEFT) 
	{
		D3DXMatrixScaling(&m_world, -1.0f, 1.0f, 1.0f); //これを入れると画像を反転できる
	}

	D3DXMatrixMultiply( &m_world, &m_world, &m_Inv );
	D3DXMatrixMultiply( &m_world, &m_world, &UnitMat );

	pD3DDevice->SetTransform(D3DTS_WORLD, &m_world);


//頂点バッファの更新
	void *pData;
	HRESULT hr;
	hr = pVertex->Lock(0, sizeof(CUSTOMVERTEX)*4, (void**)&pData, 0);

	if(hr == D3D_OK)
	{
		memcpy(pData, VertexData, sizeof(CUSTOMVERTEX)*4);
		pVertex->Unlock();
	}

	pD3DDevice->BeginScene();	// 描画開始
	// テクスチャをパイプラインにセット
	pD3DDevice->SetTexture( 0, pTex);
	pD3DDevice->SetStreamSource(0, pVertex, 0, sizeof(CUSTOMVERTEX));
	pD3DDevice->SetFVF(FVF_CUSTOM);
	pD3DDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);
	pD3DDevice->EndScene();		// 描画終了
}

Re: 【DirectX】別環境におけるビルボードのサイズが変わる現象について

Posted: 2015年12月21日(月) 16:42
by pico_pico
【質問③について】
すみません、質問③については原因に思い当たるフシがあったので無視してください。
①②の調査中にテクスチャのトリミング範囲を固定化した影響のようでした。
(開発環境でも同じ挙動になりましたので)

Re: 【DirectX】別環境におけるビルボードのサイズが変わる現象について

Posted: 2015年12月21日(月) 18:11
by ISLe
環境によって(特にミップマップテクスチャの場合)テクスチャサイズは2の累乗で作成されます。

画像のサイズが2の累乗でなく、
D3DXCreateTextureFromFileExでサイズを指定しているため、
画像サイズとテクスチャサイズの差がズレとなって表れていると思われます。


D3DXCreateTextureFromFileExで
1. 画像サイズを指定しない
2. ミップマップレベルを1にする
としてみてください。

1. テクスチャが2の累乗サイズで作成される場合、自動的にテクスチャサイズに合わせて画像が伸長されます。
フィルタ指定はそのためのものです。
テクスチャサイズと画像サイズが一致していればテクスチャ座標に影響ありません。

2. ミップマップを使わないようにすると、テクスチャサイズが2の累乗に補正される可能性が減ります。
ミップマップは縮小表示の効率を上げるものなのでこのプログラムでは不要でしょうし、ビデオメモリの消費量も減らせます。

Re: 【DirectX】別環境におけるビルボードのサイズが変わる現象について

Posted: 2015年12月21日(月) 19:24
by pico_pico
>>ISLe様

>D3DXCreateTextureFromFileExで
>1. 画像サイズを指定しない
>2. ミップマップレベルを1にする
>としてみてください。

こちら試してみましたが、状況には変化がありませんでした。
ですが、画像サイズを256×256に変更したところ実行環境(ノートPC)でも正常に描画されました。
助かりました、ありがとうございます!
問題①は解決できました。

Re: 【DirectX】別環境におけるビルボードのサイズが変わる現象について

Posted: 2015年12月21日(月) 19:42
by pico_pico
問題②におきましても、木の画像サイズを160×160から、128×128に変更したところ、描画位置のズレは解消されました。
2の累乗のサイズ管理ってこんなに大事だったんですね…いい勉強になりました。
本当にありがとうございます。本件解決とさせていただきます。