モデラート - C#とゲーム開発と雑記 このページをアンテナに追加 RSSフィード

2011-06-01

[][]シェーダ(HLSL)でリアルタイムにベクターイメージの描画を行う 23:52 シェーダ(HLSL)でリアルタイムにベクターイメージの描画を行う - モデラート - C#とゲーム開発と雑記 を含むブックマーク シェーダ(HLSL)でリアルタイムにベクターイメージの描画を行う - モデラート - C#とゲーム開発と雑記 のブックマークコメント

f:id:runicalp:20110601234513p:image

開発の環境は次の通りです。

DirectX 9、GeForce 8600 GT、Visual C++ 2010

結論から言うと実用に耐えうるものは作成できませんでした。

これ以上作成を続けても労力に見合ったものが作れる気がしないので中止します。

実用にはなりませんが、なんとなく公開しておきます。


ちなみに、これの作成を思い立ったのは去年の暮れで、

途中まったく作業していませんが5ヶ月ほどかけています。

途中Twitterにはレンダリングしたスクリーンショットをアップしていました。


このベクターイメージの描画で目標としていたのはSVGシェーダでリアルタイムに描画することでした。

達成できたのは、パスの描画、円(楕円)、長方形を個別に描画することのみで、FPSは4.5程度しか出ておりません。

動作環境やシェーダモデルが3.0より新しいものであれば事情は変わるかもしれません。


では、これらの描画の方法について説明します。

まず、シェーダでのリアルタイムなベクター(ベジェ)の描画というのはすでに存在しています。

http://hosok2.com/project/st/st_coloration.html

この実装と特に異なるのは頂点の座標がシェーダに直接記述されているか、外から与えられるかという点です。


私の考えた方法では、頂点座標は浮動小数点数テクスチャに格納し、シェーダから参照するようにしています。

ベクターの形状を識別するためのパラメータは別の整数テクスチャに格納し参照しています。

それぞれのテクスチャのフォーマットは、

浮動小数点数テクスチャ:D3DFMT_G32R32F

整数テクスチャ:D3DFMT_A8R8G8B8

です。

テクスチャへのデータの格納を簡単に行うために、IDirect3DTexture9を以下のクラスでラップしています。

template<class T>
class TextureData{
private:
	IDirect3DTexture9* tex;
	D3DLOCKED_RECT lockRect;
public:
	TextureData(IDirect3DTexture9* tex)
		:tex(tex)
	{
		// サーフェイスロック
		tex->LockRect(0, &lockRect, NULL, D3DLOCK_DISCARD);

		D3DSURFACE_DESC d;
		tex->GetLevelDesc(0, &d);
		// テクスチャサーフェイスの初期化
		FillMemory(lockRect.pBits, lockRect.Pitch * d.Height, 0xff);
	}
	~TextureData(){
		// サーフェイスアンロック
		tex->UnlockRect(0);
	}

	inline T& operator[](int index){
		return static_cast<T*>(lockRect.pBits)[index];
	}
	
	void set2(int index, T arg0, T arg1){
		(*this)[ index*2 ] = arg0;
		(*this)[ index*2 + 1] = arg1;
	}
};

パスの描画

パスはベジェ、直線を連結したものです。

ベジェの座標の指定についてはSVGのフォーマットを参考にしています。

http://www.hcn.zaq.ne.jp/___/REC-SVG11-20030114/paths.html#PathDataCubicBezierCommands

ベジェは始点、終点と2つの制御点から成ります。

浮動小数点数テクスチャには始点、制御点1、制御点2、終点の順に頂点座標を格納します。

直線は始点と終点のみなので、始点、終点の順に格納します。

パスの場合、ベジェに続いてベジェや直線が続くため、重複する頂点が現れます。

続くベジェの始点は、直前のベジェ(もしくは直線)の終点なので、それをそのまま利用します。

続くベジェの制御点1は、直前のベジェの制御点2を直前のベジェの終点に対して反対側にとったものになります。

浮動小数点数テクスチャには制御点2、終点を格納します。

直前が直線だった場合、制御点はその直線の終点とします。


パスの始めがベジェの場合、パスの始めが直線の場合、パスの始めでない部分に現れるベジェ(もしくは直線)

この4つのタイプの識別は整数テクスチャに格納します。

また、整数テクスチャには、それぞれの形状で使用する浮動小数点テクスチャバッファの位置を格納し、

それを用いて座標を取得します。


パスの描画を行う場合、それぞれのテクスチャに以下の様にデータを格納します。

data[0] = 0x00010000; 	//(1)続くデータがパスであることを示す
data[1] = 0xffffffff; 	//(2)線色
data[2] = 0xffff7f00; 	//(3)塗り色
data[3] = 0x1; 			//(4)閉じる

data[4] = 0;	//(5)パスの初めがベジェ

data[5] = 0;	//(6)浮動小数点数テクスチャの位置
data2.set2(0, 0.1f, 0.5f); //(7)浮動小数点数テクスチャの0番目のテクセル
data2.set2(1, 0.1f, 0.9f);
data2.set2(2, 0.4f, 0.9f);
data2.set2(3, 0.5f, 0.5f);

data[6] = 1;	//(8)次はベジェ

data[7] = 4;
data2.set2(4, 0.9f, 0.1f);
data2.set2(5, 0.9f, 0.5f);

data[8] = 3;

data[9] = 6;
data2.set2(6, 0.9f, 0.9f);

data[10] = 0x02000000; //(9)パスの終了

(1)まず、形状を識別するための値を頭に入れます。0x10000はパスのデータが格納されていることを示します。

線の色(2)、塗りの色(3)を指定します。

(4)これはパス始点と終点が結合していない場合の処理で、1であれば始点と終点に直線を引きます。

(5)続く頂点データの意味を指定します。

パスの始めのベジェであれば0、途中に現れるベジェであれば1、パスの始めの直線であれば2、途中に現れる直線であれば3

(6)頂点データの浮動小数点数テクスチャでの位置を指定します。

(7)この場合浮動小数点数テクスチャの0番目のテクセルのRに0.1f、Gに0.5fを格納します。

それぞれシェーダではx,yとして取得することができます。

(8)同様に途中に現れるベジェの指定です。

(9)パスの終了です。


シェーダプログラムでは、まず最初の4つの整数を読み取った後、それぞれの形状によって処理を分けながら

整数を読み進めていきます。パスの場合は0x02000000が現れるまでこの処理を反復しますが、

シェーダプログラムでは無限ループを指定できないため6回のループに制約しています。

0x02000000を読み取る前でも、たくさん接続されたパスは途中で切れてしまうことを意味します。

>パスの描画、円(楕円)、長方形を個別に描画することのみ

冒頭でこのように記述したのも無限ループを作れないため、単独で描画することしかできないためです。

無限ループが作れないのは、おそらく最適化でループを展開しているためだと思うのですが、

6回に制約したループであっても(最適化の所為かわかりませんが)、コンパイルに6分程度の時間がかかってしまいます。

矩形の描画

data[0] = 0x00010001; //矩形
data[1] = 0xffffffff; //線色
data[2] = 0x7f7fff00; //塗り色

data[3] = 0;		//浮動小数点数テクスチャの位置
data2.set2(0, 0.5f, 0.5f); //位置
data2.set2(1, 0.1f, 0.3f); //幅、高さ
data2.set2(2, 3.14f/4.f, 0); //回転(第3引数は未使用)

パスと違いシンプルです。

楕円の描画はdata[0]の0x00010001を0x00010002に置き換えるだけです。

(0x00010000でも0x00010001でもなければ0x00010002でなくてもいいです)



最後にこれらのテクスチャシェーダに設定します。ほかにもいくつかのパラメータを設定します。

eff->SetTexture( "tex0", texture ); //整数テクスチャ
eff->SetTexture( "ftex", texture2 ); //浮動小数点数テクスチャ
eff->SetInt( "TextureResolution", 16 ); //テクスチャ解像度
eff->SetInt( "g_devide", 18 ); //ベジェの分解能

effはID3DXEffectです。

ベジェは直線に分割して描画することになるので、その分割の数がベジェの分解能です。

ベジェの分解能は18以上の値を入れても18に制限されます。



今回作成したシェーダプログラムです。

float4x4 World;
float4x4 View;
float4x4 Projection;
int TextureResolution;
int g_devide;

texture tex0;
sampler tex_sampler = sampler_state
{
    Texture = <tex0>;
    MinFilter = POINT;
    MagFilter = POINT;
    MipFilter = POINT;
    AddressU = Clamp;
    AddressV = Clamp;
};

texture ftex;
sampler ftex_sampler = sampler_state
{
    Texture = <ftex>;
    MinFilter = POINT;
    MagFilter = POINT;
    MipFilter = POINT;
    AddressU = Clamp;
    AddressV = Clamp;
};
float3x3 transform : TRANSFORM;
float2 screen : SCREEN;

struct VSO
{
	float4 Position : POSITION;
	float2 UV : TEXCOORD0;
	float3 Normal : TEXCOORD1;
	float4 Color : COLOR0;
};
 
VSO mainVS(float4 position : POSITION,
                    float2 tex : TEXCOORD0,
					float4 color : COLOR0,
					float3 normal : TEXCOORD1)
{
    VSO output;
    float4 worldPosition = mul(position, World);
    float4 viewPosition = mul(worldPosition, View);
    output.Position = mul(viewPosition, Projection);
	output.UV = tex;
	output.Color = color;
	output.Normal = normal;
    return output;
}

int toint(float4 f4){
	return (int)(f4.a * 256 * 256 * 256 * 255 +
	f4.r * 256 * 256 * 255 +
	f4.g * 256 * 255 +
	f4.b * 255);
}

float4 bezierColor(float2 UV, float4 lc, float4 fc,
				float2 p0, float2 p1, float2 p2, float2 p3) : COLOR0;
int bezierColorFill(float2 UV, float4 lc, float4 fc,
				float2 p0, float2 p1, float2 p2, float2 p3);
float2 getBezier(float2 p0, float2 p1, float2 p2, float2 p3, float t);
bool isinline(float2 v0, float2 v1, float2 p);
float linepoint_closest(float2 v0, float2 v1, float2 p);
bool islinecross_scan(float2 v0, float2 v1, float y);
float linecross_left(float2 v0, float2 v1, float y);

float4 rectangleColor(float2 UV, float4 lc, float4 fc,
				float2 p0, float2 p1, float2 p2) : COLOR0;
float4 circleColor(float2 UV, float4 lc, float4 fc,
				float2 p0, float2 p1, float2 p2) : COLOR0;

int fetchint(int index){
	return toint(tex2D(tex_sampler, float2((float)(index % TextureResolution)/(float)TextureResolution,
								(float)(index / TextureResolution)/(float)TextureResolution)));
}
float4 fetch(int index){
	return tex2D(tex_sampler, float2((float)(index % TextureResolution)/(float)TextureResolution,
								(float)(index / TextureResolution)/(float)TextureResolution));
}
float2 ffetch(int index){
	return tex2D(ftex_sampler, float2((float)(index % TextureResolution)/(float)TextureResolution,
							(float)(index / TextureResolution)/(float)TextureResolution)).xy;
}

float4 mainPS(VSO input) : COLOR0
{
	int maxloop = 6;
	int tag = fetchint(0);
	// path
	if( tag == 0x00010000L ){
		float4 lc = fetch(1);
		float4 fc = fetch(2);
		int close = fetchint(3);
		int index = 4L;
		float2 startpos = float2(0, 0);
		float2 lastp = float2(0, 0);
		float2 controlp = float2(0, 0);
		int crosscnt = 0;
		while(maxloop-- > 0)
		{
			int s = fetchint(index++);
			int startindex = fetchint(index++);
			float2 p0, p1;
			if(s == 0L || s == 1L){
				if(s == 0L){
					p0 = startpos = ffetch(startindex); startindex++;
					p1 = ffetch(startindex); startindex++;
				}else{
					p0 = lastp;
					p1 = controlp;
				}
				float2 p2 = ffetch(startindex); startindex++;
				float2 p3 = lastp = ffetch(startindex);
				controlp = lastp + -(p2 - p3);
				float4 c = bezierColor(input.UV, lc, fc, p0, p1, p2, p3);
				if( c.a != 0 ) return c;
				crosscnt += bezierColorFill(input.UV, lc, fc, p0, p1, p2, p3);
			}else if(s == 2L || s == 3L){
				if( s == 2L ){
					p0 = startpos = ffetch(startindex); startindex++;
					p1 = lastp = controlp = ffetch(startindex);
				}else{
					p0 = lastp;
					p1 = lastp = controlp = ffetch(startindex);
				}
				
				float len = length( input.UV - p0 );
				if( len <= 0.01 )
					return lc;
				
				len = length( input.UV - p1 );
				if( len <= 0.01 )
					return lc;
					
				if( isinline( p0, p1, input.UV ) ){
					if( linepoint_closest( p0, p1, input.UV ) < 0.01 ){
						return lc;
					}
				}
				
				if( islinecross_scan( p0, p1, input.UV.y ) ){
					if( linecross_left( p0, p1, input.UV.y ) < input.UV.x ){
						crosscnt++;
					}
				}
			}else if(s == 0x02000000L){
				break;
			}
		}
		
		// パスが閉じる指定の場合ここでライン描画されるかチェックする
		if( close != 0 && isinline( startpos, lastp, input.UV ) ){
			if( linepoint_closest( startpos, lastp, input.UV ) < 0.01 ){
				return lc;
			}
		}
		
		// 塗りを行う前にパスを閉じるラインを考慮してカウントする
		if( islinecross_scan( startpos, lastp, input.UV.y ) ){
			if( linecross_left( startpos, lastp, input.UV.y ) < input.UV.x ){
				crosscnt++;
			}
		}
		if( (crosscnt % 2) != 0 ) return fc;
	// rectangle & circle
	}else{
		float4 lc = fetch(1);
		float4 fc = fetch(2);
		int startindex = fetchint(3);
		float2 pos = ffetch(startindex++);
		float2 radius = ffetch(startindex++);
		float2 radian = ffetch(startindex);
		float4 c;
		if( tag == 0x00010001L ){ // rectangle
			c = rectangleColor( input.UV, lc, fc, pos, radius, radian );
		}else{ // circle
			c = circleColor( input.UV, lc, fc, pos, radius, radian );
		}
		if( c.a != 0 ) return c;
	}
	
	return float4(0, 0, 0, 0);
}

float4 bezierColor(float2 UV, float4 lc, float4 fc,
				float2 p0, float2 p1, float2 p2, float2 p3) : COLOR0
{
	int devide = min(g_devide, 18);
	int i;
	// line connect circle
	for(i=0; i<devide + 1; i++){
		float2 p = getBezier(p0, p1, p2, p3, (float)i/(float)devide);
		float len = length( UV - p );
		if( len <= 0.01 )
			return lc;
	}
	// line
	float2 p1_ = getBezier(p0, p1, p2, p3, 0);
	for(i=0; i<devide; i++){
		float2 p0_ = p1_;
		p1_ = getBezier(p0, p1, p2, p3, (float)(i+1)/(float)devide);
		if( isinline( p0_, p1_, UV ) ){
			if( linepoint_closest( p0_, p1_, UV ) < 0.01 ){
				return lc;
			}
		}
	}

	return float4(0, 0, 0, 0);
}


int bezierColorFill(float2 UV, float4 lc, float4 fc,
				float2 p0, float2 p1, float2 p2, float2 p3)
{
	int devide = min(g_devide, 18);
	// fill bezier
	int crosscnt = 0;
	float2 p1_ = getBezier(p0, p1, p2, p3, 0);
	for(int i=0; i<devide; i++){
		float2 p0_ = p1_;
		p1_ = getBezier(p0, p1, p2, p3, (float)(i+1)/(float)devide);
		if( islinecross_scan( p0_, p1_, UV.y ) ){
			if( linecross_left( p0_, p1_, UV.y ) < UV.x ){
				crosscnt++;
			}
		}
	}
	return crosscnt;
}

float2 getBezier(float2 p0, float2 p1, float2 p2, float2 p3, float t){
	float2 v0 = p1 - p0;
	float2 v1 = p2 - p1;
	float2 v2 = p3 - p2;

	float2 p4 = (p0 + v0 * t);
	float2 p5 = (p1 + v1 * t);
	float2 p6 = (p2 + v2 * t);

	float2 v3 = p5 - p4;
	float2 v4 = p6 - p5;
	
	float2 p7 = (p4 + v3 * t);
	float2 p8 = (p5 + v4 * t);

	float2 v5 = p8 - p7;
	
	return p7 + v5 * t;
}

bool isinline(float2 v0, float2 v1, float2 p){
	float2 va = v1 - v0;
	float2 va_ = normalize( va );
	float2 vb = p - v0;

	float d = dot( va_, vb );
	if( d < 0 ) return false;

	return d <= length( va );
}
float linepoint_closest(float2 v0, float2 v1, float2 p){
	float2 va = v1 - v0;
	float2 vb = p - v0;
	return abs( va.x * vb.y - va.y * vb.x ) / length( va );	
}

//スキャンラインと線分がy成分的に交差する可能性があるか
bool islinecross_scan(float2 v0, float2 v1, float y){
	return max( v0.y, v1.y ) >= y && min( v0.y, v1.y ) < y;
}
//直線とスキャンラインの最左端取得
float linecross_left(float2 v0, float2 v1, float y){
	if( v1.y == v0.y ) return max(v0.x, v1.x);
	return (-(v0.x - v1.x) * y - v1.x*v0.y + v0.x*v1.y) / (v1.y - v0.y);
}

float4 rectangleColor(float2 UV, float4 lc, float4 fc,
				float2 p0, float2 p1, float2 p2) : COLOR0
{
	float s = sin(-p2.x);
	float c = cos(-p2.x);
	float2x2 m = { c, s, -s, c };
	UV -= p0;
	UV = mul(UV, m);
	
	UV.x = abs(UV.x) - p1.x;
	UV.y = abs(UV.y) - p1.y;
	
	if( UV.x < - 0.01 && UV.y < - 0.01 ) return fc;		
	if( UV.x < 0.01 && UV.y < 0.01 ) return lc;	
	return float4(0, 0, 0, 0);
}

float4 circleColor(float2 UV, float4 lc, float4 fc,
				float2 p0, float2 p1, float2 p2) : COLOR0
{
	float s = sin(-p2.x);
	float c = cos(-p2.x);
	float2x2 m = { c, s, -s, c };
	UV -= p0;
	UV = mul(UV, m);
	p1 -= float2( 0.01, 0.01 );
	float r = (UV.x * UV.x)/(p1.x * p1.x) + (UV.y * UV.y)/(p1.y * p1.y);
	if( r <= 1 ) return fc;
	p1 += float2( 0.02, 0.02 );
	r = (UV.x * UV.x)/(p1.x * p1.x) + (UV.y * UV.y)/(p1.y * p1.y);
	if( r <= 1 ) return lc;
	return float4(0, 0, 0, 0);
}

technique tec0
{
    pass p0
    {
        VertexShader = compile vs_3_0 mainVS();
        PixelShader   = compile ps_3_0 mainPS();
    }
}

2008-12-09

runicalp2008-12-09

[][][][][]COLLADA-DOM 2.2, Bullet 2.73がリリースされてた 02:15 COLLADA-DOM 2.2, Bullet 2.73がリリースされてた - モデラート - C#とゲーム開発と雑記 を含むブックマーク COLLADA-DOM 2.2, Bullet 2.73がリリースされてた - モデラート - C#とゲーム開発と雑記 のブックマークコメント

Bullet 2.73

COLLADA DOM 2.2

自分はBullet2.72とCOLLADA DOM 2.1をつかってて、それの記事書こうと思ってたらアップデートされてました。でも書くぜー。


まだ使い込んでなくて概要すら見えてないし特に古いバージョンを使い続ける理由もないので、アップデートはします。

それぞれのライブラリにはVCのプロジェクトも同梱されているんですが、1発でうまくいかなかったんでそれだけはちょっと書いておきます。


両方にたぶん共通して言えるんですが、たとえばdebugの構成では

プロジェクトのプロパティの[C/C++]->[コード生成]->[ランタイムライブラリ]がマルチスレッド デバッグ DLL (/MDd)

だったりマルチスレッド デバッグ (/MTd)のどちらかだと思いますが、ライブラリの方もそろえないとリンクできないです。

Bulletのビルドの構成にはDebug,DebugDll,DebugDoublePrecision,Release,ReleaseDll,ReleaseDoublePrecisionとありますが、自分のプロジェクトの構成がマルチスレッド デバッグ DLLだったらDebugDll、マルチスレッド デバッグ だったらDebugを使えばいいということになります。

ちなみに2.71ではビルドの構成はDebugとDllとに分かれていなかったので、Dllをマルチスレッド デバッグ DLLにすれば、

サンプルもそれに合わせる必要がありました。


こっちは確認できてないんですが、COLLADA DOMではstaticライブラリをマルチスレッド デバッグ DLLビルドしてリンクするとDllがないと怒られてしまいます。なので、マルチスレッド デバッグビルドして自分のプロジェクトもマルチスレッド デバッグにしないといけないのかなぁと思ってます。

DLLの方はちゃんとリンクできて動作できてるのでまぁよいのですが。ビルドしたDllを自分のアプリケーション下まで持って来るのを忘れてはいけません。


COLLADA DOMに関してはそれよりもビルドが通ってくれなくて四苦八苦しました。

Dllの方ではプロパティの[リンカ]->[全般]->[ライブラリの追加ディレクトリ]に色々追加して↓のような感じにしました。

"..\..\external-libs\libxml2\win32\lib";"..\..\external-libs\tinyxml\lib\vc9";"..\..\external-libs\pcre\lib\vc9"

プロパティの[リンカ]->[入力]->[追加の依存ファイル]はこんな具合です。

libxml2_a.lib zlib.lib wsock32.lib pcre-d.lib pcrecpp-d.lib

なんかpcre-d.lib pcrecpp-d.libこの辺が足りなくてビルドが通らなかった感じです。


staticライブラリの方は[ライブラリアン]->[全般]->[追加の依存関係],同じく->[追加のライブラリディレクトリ]にそれぞれ

pcre-d.lib pcrecpp-d.libと..\..\external-libs\pcre\lib\vc9を指定しました。

これで両方ビルドは通るようになりました。

staticライブラリはリンクして実行するとDllがないと言われますが(さっきの話へ戻る)


最新版だといろいろいい感じになってたりってことがあるんで、それに期待しつつ深追いはせずに行きます。



COLLADA DOM(とDirectX)を使ったコリジョンツールを作成中です。(COLLADAモデルはBlenderやXSIのCrossWalkで吐き出したバージョン1.4.1を表示できています。)

f:id:runicalp:20081209015348p:image

球とかAABBとかをグラフィカルに設定できるツール。そんなツールがほしかったので。

実際のモデルデータとオーバーラップさせて表示すれば操作性もいい感じになると思われます。

バイナリ出力されたコリジョン形状を読み込めるコリジョンシステムも同時に開発してます。

こいつらとエフェクト作成ツール(妄想段階)を絡めさせればすごいことができると思う。



参考

COLLADA DOM使ったとき参考にしたサイト

CodeZine - COLLADA DOMを使った3Dモデルデータの読み込み

Shader.jp Articles-COLLADA DOM: 第1回「COLLADA DOMをDirect3Dで使う」

東方3DSTGにBulletを導入したときに参考にしたサイト

もんしょの巣穴Bullet Physics Engineを使ってみよう 第01回

Bullet: Bullet 第1回「Direct3Dと一緒にBulletを使ってみる」

2008-11-14

[][][]Waterサンプルをビルドする 01:38 Waterサンプルをビルドする - モデラート - C#とゲーム開発と雑記 を含むブックマーク Waterサンプルをビルドする - モデラート - C#とゲーム開発と雑記 のブックマークコメント

ふと水面のシミュレーションをしてみようを思い立ち、偶然にもちょうどいいサンプルがあるということを以下のページで発見した。

3D エフェクトのスクリプティング〜 Cutting Edge DX 8 - 第 2 回目 〜

DirectX 8のころのサンプルのようで、サンプルだけでも配布していないか探したところ、MSDN DirectX 9 サンプルの項にWaterサンプルがあるのを確認。

しかし、Directx 9.0c SDK (March 2008)には含まれていなかった。


その後調べた結果DirectX SDK ダウンロードページにある、DirectX 9.0b SDK (2002)に含まれていることがわかった。(さらに新しいバージョンに含まれているかも知れないが)


推測だけど、9.0のSDKから8時代のものを排除して、10へ置き換えていく過程でサンプルも整理したのかな。


今回はDirectX 9.0b SDK (2002)をインストールせずに、展開しただけの状態でビルドします。

Directx 9.0c SDK (March 2008)などそれ以降のバージョンでビルドするってことですね。


プロジェクトの変換とビルド

無事サンプルを発見することができたので、プロジェクトをVC++2008用に変換してビルドする。

ちなみにVisual C++ 2008 Express Editionです。

プロジェクトは6と7(.NET 2002?)が用意してあったので、7をVC++2008で開き、そのまま[完了]を押して変換を終了する。変換は問題なし。


続いてビルド

今回Warningは無視。

エラーは大きく分けて5点ほどの修正で済むはずです。


  • error C2051: case 式は、整数型定数でなければなりません。 c:\development\sdk\temp\sdk (c++)\samples\c++\common\src\d3dapp.cpp 1582

筆者環境ではHRESULT_FROM_WIN32がインライン関数として定義されていたため、これをマクロに置き換えます。

SDK(C++)\Samples\C++\Common\Src\d3dapp.cpp 1582行

    case HRESULT_FROM_WIN32( ERROR_FILE_NOT_FOUND ):

    case __HRESULT_FROM_WIN32( ERROR_FILE_NOT_FOUND ):


  • fatal error C1083: include ファイルを開けません。'rmxfguid.h': No such file or directory c:\development\sdk\temp\sdk (c++)\samples\c++\common\src\d3dfile.cpp 14

インストールしたSDKには含まれないヘッダがあるので、それらのみ相対パスで指定してあげます。

SDK(C++)\Samples\C++\Common\Src\d3dfile.cpp

#include <rmxfguid.h>
#include <rmxftmpl.h>

#include "..\..\..\..\Include\rmxfguid.h"
#include "..\..\..\..\Include\rmxftmpl.h"


  • fatal error LNK1104: ファイル 'd3dx9dt.lib' を開くことができません。 Water
  • error C2664: 'D3DXLoadMeshFromXof' : 1 番目の引数を 'LPDIRECTXFILEDATA' から 'LPD3DXFILEDATA' に変換できません。(新しい機能 ; ヘルプを参照) c:\development\sdk\temp\sdk (c++)\samples\c++\common\src\d3dfile.cpp 151

VisualC++でDirectX9は大変を参考にさせていただきました。


まず追加の依存ファイルのd3dx9dt.libをDebug(ソリューション構成)でd3dx9d.lib に置き換えてください。

Releaseはなにもしなくていいです。

次にSDK(C++)\Samples\C++\Common\Include\d3dfile.h にdxfile.hをインクルード

そしてSDK(C++)\Samples\C++\Common\Src\d3dfile.cpp CD3DMesh::Create内のpFileDataをLPD3DXFILEDATAにキャスト

d3dfile.h〜〜〜
#include <d3d9.h>
#include <d3dx9.h>
〜〜〜


d3dfile.cpp〜〜〜
// Load the mesh from the DXFILEDATA object
if( FAILED( hr = D3DXLoadMeshFromXof( pFileData, D3DXMESH_SYSTEMMEM, pd3dDevice,
                                      &pAdjacencyBuffer, &pMtrlBuffer, NULL,
                                      &m_dwNumMaterials, &m_pSysMemMesh ) ) )
〜〜〜

d3dfile.h〜〜〜
#include <d3d9.h>
#include <d3dx9.h>
#include <dxfile.h>
〜〜〜


d3dfile.cpp〜〜〜
// Load the mesh from the DXFILEDATA object
if( FAILED( hr = D3DXLoadMeshFromXof( (LPD3DXFILEDATA)pFileData, D3DXMESH_SYSTEMMEM, pd3dDevice,
                                      &pAdjacencyBuffer, &pMtrlBuffer, NULL,
                                      &m_dwNumMaterials, &m_pSysMemMesh ) ) )
〜〜〜


  • error C2039: 'Pass' : 'ID3DXEffect' のメンバではありません。 c:\development\sdk\temp\sdk (c++)\samples\c++\direct3d\water\water.cpp 748

DirectX9.0c Direct3D Tips 第1回「 頂点テクスチャによるディスプレースメントマッピング : Displacement Mapping」を参考にさせていただきました。

ID3DXEffectの9.0cでの変更について注目した記事です。


Water.cpp 748行

            m_pEffect->Pass(uPass);
            m_Water.DrawSurface();

            m_pEffect->BeginPass(uPass);
            m_Water.DrawSurface();
            m_pEffect->EndPass();

あってるのかな?とりあえず動かすことが目標なのでいつか見直すとします。


  • fatal error CVT1100: duplicate resource. type:MANIFEST, name:1, language:0x0409 CVTRES
  • fatal error LNK1123: COFF への変換中に障害が発生しました: ファイルが無効であるか、または壊れています。 Water

http://forum.minidx.com/thread-8-1-1.htmlから引用

アプリケーションウィザードで"Add Common Control Manifest"のチェックを外す、

もしくはプロジェクトのプロパティ→構成プロパティ→マニフェストツール→入力と出力→埋め込みマニフェストを”いいえ”に設定すると解決出来ます。(−−)!

とのこと。

もしくは、

winmain.rcの27行目をコメントアウト

CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST "Water.manifest"

//CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST "Water.manifest"

リソースファイルと構成のプロパティ双方でマニフェストを埋め込む設定になっていたためですかね。

前者の場合は、Debug、Release双方の設定を変更する必要があります。


ビルドできたら実行ファイルをSDK (C++)\Samples\Mediaに持っていけば、ちゃんと走るはずです。

デバッガで起動したら起こられました。データが見えないんですね。

2008-11-11

[][][][][]デバッグカメラと物理エンジン(Bullet)の組み込み 00:59 デバッグカメラと物理エンジン(Bullet)の組み込み - モデラート - C#とゲーム開発と雑記 を含むブックマーク デバッグカメラと物理エンジン(Bullet)の組み込み - モデラート - C#とゲーム開発と雑記 のブックマークコメント

前回は次回スレッドをやるとかなんとか言っていましたね・・・。わすれてました。

それよりも先に、デバッグカメラを使えるようにしようと思います。

勢いあまってBulletも組み込みます。

D

高画質で見る

今回は動画でお届け。

デバッグカメラと物理エンジンBulletの組み込みを行いました。

デバッグカメラの実装

デバッグカメラと呼んでいるのはこれがゲームでの視点になるわけではなく、

単に3Dシーンの確認にしか使わないからです。


注視点の上下左右の移動、注視点に対してカメラの位置の回転と距離の変更ができるようになっています。

左上のtarが注視点で、posがカメラの位置です。

カメラの回転はクォータニオンを使っています。


3D上の注視点には、xyz軸に沿った3本のラインが引かれています。動画では確認できないと思うので、

高画質の方を見てきてください。



物理エンジン Bullet

物理エンジンのBulletを組み込みました。

弾幕が物理演算で跳ね回ったらよだれたれますわ。

そんな妄想を抱いたがための物理エンジンの組み込みです。

当たり判定や、エフェクトにも使えるので、何千発の弾幕を物理演算させられなくてもいいんです。

物理演算ってほんといいですよね。キューブが高速にスピンしてるの見るとよだれたれますわ。


Xファイルがなくなる?

僕はまだDirectX10には触れていないのですが、Xファイルがサポートされなくなったんですね。

ゲームつくろー! DirectX10技術編 その4 Xファイルからモデルを読み込んでみる

ファイル周りや、アニメーション周りはまだ手をつけていないので、COLLADA

にも手を出しておこうかなと思います。

COLLADAですべていけそうならXファイルは捨てるという感じで。(捨てるとか言うほど手は突っ込んでないけど)



今後の展開

まずはスレッド&ファイル周辺を整理して、モデルのアニメーションを行うところまでやりましょう。

そしていろいろデータの作成。

データの作成といってもシナリオや舞台なんか大して考えてないんで、キャラとかスペカとかしか作らないですけど。

コリジョンのためのプリミティブ作成ツールや、エフェクト作成ツール、弾幕スクリプト、シーケンス管理のスクリプト(Luaの組み込み)とか妄想してます。


次回はカメラの実装方法や、Bulletを組み込むときに困ったこととかを書きたい。

2008-09-01

[][][][]カメラクラスとXファイルのモデルの表示 00:46 カメラクラスとXファイルのモデルの表示 - モデラート - C#とゲーム開発と雑記 を含むブックマーク カメラクラスとXファイルのモデルの表示 - モデラート - C#とゲーム開発と雑記 のブックマークコメント

f:id:runicalp:20080902004712p:image

カメラクラスの作成が終わったので、モデルの表示まで行いました。

カメラクラスと言ってもDXUTのカメラクラスの足元にも及ばないようなものですが。

SetPos()でカメラの座標を設定し、SetTar()でカメラの注視点を設定し、

Calc()でD3DXMatrixLookAtなんたらしてビューマトリクスを計算し、GetMtx()で取得するクラス。

後はモデル(メッシュ)の描画ごとにモデルローカルマトリクス*GetMtxしたビューマトリクスをdevice->SetTransform(D3DTS_VIEW, mtx );で設定して描画するだけ。

しかしこれは固定機能パイプラインを用いた場合の話であって頂点シェーダを用いた場合はそうではない。

いや頂点シェーダ触ったことないから勢いで適当に言い切ったけど。

頂点シェーダが使えない環境に長いこといたのだからしょうがない。しょうがないよな。

カメラはそんな感じ。カメラの位置と、注視点だけ変更できれば問題ない。画角なんかは変えられたほうがいいかな。


Xファイルからモデル(メッシュ)の表示

とりあえず拾ってきたコードを使う。

Xファイルからメッシュの生成と、マテリアルの生成、そのマテリアルで使われているテクスチャの生成。

ライトを適当に設定してメッシュの描画と。そんな感じで今日の1枚の出来上がりです。

ライトもカメラのようにクラスとして扱ったほうが便利そうです。

ライトをゴリゴリ動かしたりはしないですけどね。

モデルの表示は何とかなったとして、問題はモデル、と言うかXファイルの読み込みです。

でかいと読み込みでブロックするでしょう。

これはスレッドを分けて、ロードはロードで勝手にやって、描画は描画でしっかりやらなけらばいけないです。メンドイ

ゲームを起動して真っ暗画面でしばらく動かないゲームとかありますが、壊れてんのかと心配になります。

短い時間だと特に問題はないのですが、せめてNow Loadingの文字くらいは動かしておきたいものです。

と言うわけで次のテーマはスレッド

スレッドの次はアニメーション、プログラマブルシェーダ・・・と続いていく予定です。


スクリーンショットのモデルはこのゲームと全然関係ないです。