DXライブラリでの2D用カメラ作成について

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
イマダニ
記事: 145
登録日時: 8年前

DXライブラリでの2D用カメラ作成について

#1

投稿記事 by イマダニ » 6年前

おはようございます。
ここ最近、DXライブラリとvc++2008で作ったマップエディタでステージ制作ばかりをしているイマダニです。
今回はそのマップエディタに

拡大縮小機能(マウスホイールで画面の拡大縮小ができる。saiなどのペイントソフトについているような機能)

といった、まあ、下記の動画の様な感じの機能をつけようとしたのが発端です。


上記の機能を実現する2Dカメラを作ろうと
以下のサイトや本などを参考にしつつ、

directx メモ – 2Dカメラの作り方(directx9)
http://ookumaneko.wordpress.com/2012/02 ... 9directx9/
ゲーム開発のための数学・物理学入門


以下の様な考えでコードを組んだのですが、

①カメラの位置、注視点、拡大率を設定

コード:

/*カメラクラス*/
class Camera2D{
public:
	Vector2D pos;	//カメラの座標
	Vector2D Lpos;	//カメラの注視点。LookPositionてきな
	Vector2D scale; //拡大率

	Camera2D();		//コンストラクタ
	void Move();    //カメラノムーブ
	MATRIX GetMatrix();//カメラ行列生成
};
②それらの情報を元に行列を生成

コード:

void Camera2D::Move(){
	//移動量
	Vector2D move;
	move.x=2.0;move.y=2.0;

	//カメラの位置移動処理
	if(CheckKey(KEY_INPUT_A)>0){//キー入力で
		pos.x-=move.x;
	}
	if(CheckKey(KEY_INPUT_D)>0){
		pos.x+=move.x;
	}
	if(CheckKey(KEY_INPUT_W)>0){
		pos.y-=move.y;
	}
	if(CheckKey(KEY_INPUT_S)>0){
		pos.y+=move.y;
	}

	//カメラの拡大率走査
	if(CheckMouse(MOUSE_INPUT_LEFT)>0){//マウス左クリックで拡大
		scale.x+=0.1;
		scale.y+=0.1;
	}
	if(CheckMouse(MOUSE_INPUT_RIGHT)>0){//縮小
		scale.x-=0.1;
		scale.y-=0.1;
	}
}

MATRIX Camera2D::GetMatrix(){
	MATRIX m1;
	VECTOR Pos;
	VECTOR LPos;
	VECTOR Scale;

	/*ベクトルを2dから3dに*/
	Pos.x = pos.x;//カメラの位置
	Pos.y = pos.y;
	Pos.z = 0.0;

	Scale.x = scale.x;//拡大率
	Scale.y = scale.y;
	Scale.z = 0.0;

	LPos.x = Lpos.x;
	LPos.y = Lpos.y;
	LPos.z = 1.0;

	/*上記を元に行列を生成*/
	m1 = MMult(MGetScale(Scale),MGetTranslate(Pos));//拡大×平行移動

	return m1;
}

③その行列をもとに描画する

コード:

DrawRotaGraph(/*行列をどうにかして設定*/);

/*ここがどうしてもわからない!!!!!*/
③がわからなくて困ってます。上記のdirectxを用いた解説では、directxの描画機能でどうにかしてますが……

コード:

// 行列をスプライトに設定する
HR( _sprite->SetTransform( &m1 ) );
 
// 実際に描画する
_sprite->Draw( texture, NULL, &ori, NULL, colour );
Dxライブラリでは、カメラの情報が詰まった行列を
どう描画に反映すればいいのでしょうか?

アドバイスお願いします。

アバター
h2so5
副管理人
記事: 2212
登録日時: 9年前
住所: 東京
連絡を取る:

Re: DXライブラリでの2D用カメラ作成について

#2

投稿記事 by h2so5 » 6年前

SetupCamera_Ortho, SetCameraViewMatrix, DrawBillboard3D を組み合わせれば可能だと思います。

イマダニ
記事: 145
登録日時: 8年前

Re: DXライブラリでの2D用カメラ作成について

#3

投稿記事 by イマダニ » 6年前

h2so5 さんが書きました: SetupCamera_Ortho, SetCameraViewMatrix, DrawBillboard3D を組み合わせれば可能だと思います。
アドバイスありがとうございます。
おかげで行列を描画に反映する事ができました。

コード:

/*ベクトルクラス*/
class Vector2D{
public:
	Vector2D();
	Vector2D(int ax,int ay);
	Vector2D(double ax,double ay);
	void operator+=(const Vector2D& a);
	void operator-=(const Vector2D& a);
	void operator=(const Vector2D& a);

	double x;//座標
	double y;
};

/*カメラクラス*/
class Camera2D{
public:
	Vector2D pos;	//カメラの座標
	Vector2D Lpos;	//カメラの注視点。LookPositionてきな
	Vector2D scale; //拡大率
	double rotate;

	Camera2D();		//コンストラクタ
	void Move();    //カメラノムーブ
	MATRIX GetMatrix();//カメラ行列生成
};

/*ベクトルクラスのメンバ関数定義はこの辺にあるが、省略*/

Camera2D::Camera2D(){
	pos.x = SCREEN_WIDTH/2;  //カメラの初期位置は画面の中央
	pos.y = SCREEN_HEIGHT/2;

	Lpos.x = SCREEN_WIDTH/2;  //画面の中心点
	Lpos.y = SCREEN_HEIGHT/2;

	rotate = 0.0;

	scale.x = 1.0; //拡大率は1
	scale.y = 1.0;
}

void Camera2D::Move(){
	//移動量
	Vector2D move;
	move.x=2.0;move.y=2.0;

	//カメラの位置移動処理
	if(CheckKey(KEY_INPUT_A)>0){
		pos.x-=move.x;
	}
	if(CheckKey(KEY_INPUT_D)>0){
		pos.x+=move.x;
	}
	if(CheckKey(KEY_INPUT_W)>0){
		pos.y-=move.y;
	}
	if(CheckKey(KEY_INPUT_S)>0){
		pos.y+=move.y;
	}

	//カメラの拡大率走査
	if(CheckMouse(MOUSE_INPUT_LEFT)>0){//拡大
		scale.x+=0.1;
		scale.y+=0.1;
	}
	if(CheckMouse(MOUSE_INPUT_RIGHT)>0){//縮小
		scale.x-=0.1;
		scale.y-=0.1;
	}
}

MATRIX Camera2D::GetMatrix(){
	MATRIX m1;
	VECTOR Pos;
	VECTOR LPos;
	VECTOR Scale;

	/*ベクトルを2dから3dに*/
	Pos.x = pos.x*-1;
	Pos.y = pos.y*-1;
	Pos.z = 0.0*-1;

	Scale.x = scale.x;
	Scale.y = scale.y;
	Scale.z = 1.0;

	LPos.x = Lpos.x;
	LPos.y = Lpos.y;
	LPos.z = 0.0;

	/*上記を元に行列を生成*/
	m1 = MMult(MGetTranslate(Pos),MGetScale(Scale));//平行移動(-位置)×拡大

	m1 = MMult(m1,MGetRotZ( rotate ));//それに回転をかける

	m1 = MMult(m1,MGetTranslate(LPos));//さいごに画面の中心をかける

	return m1;
}

int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow )
{
	ChangeWindowMode(TRUE), DxLib_Init(), SetDrawScreen( DX_SCREEN_BACK );

	int haikei;//グラハン
	Camera2D c;
	MATRIX mat;

    // 読み込み
	haikei = LoadGraph("img/1351422467412.jpg")/*("img/0a4f3fd9.png")*/;

	while(!ScreenFlip()&&!ProcessMessage()&&!ClearDrawScreen()&&!UpdateKey()&&!UpdateMouse()){
		c.Move();
		mat = c.GetMatrix();
		
		SetupCamera_Ortho( 480 ) ;

        // カメラクラス行列をビュー行列としてセット
        SetCameraViewMatrix( mat ) ;

		//適当な画像を描画
		DrawBillboard3D( VGet( 800.0f, 0.0f,0.0f), 0.5f, 0.5f, 338.0f, 0.0f, haikei, TRUE ) ;
		
		//行列がどうなってるか表示
		DrawFormatString( 0, 32, GetColor( 255,255,255 ), "m[0][0] %f  m[0][1] %f  m[0][2] %f m[0][3] %f",
			mat.m[0][0], mat.m[0][1], mat.m[0][2],mat.m[0][3] ) ;
		DrawFormatString( 0, 32*2, GetColor( 255,255,255 ), "m[1][0] %f  m[1][1] %f  m[1][2] %f m[1][3] %f",
			mat.m[1][0], mat.m[1][1], mat.m[1][2],mat.m[1][3] ) ;
		DrawFormatString( 0, 32*3, GetColor( 255,255,255 ), "m[2][0] %f  m[2][1] %f  m[2][2] %f m[2][3] %f",
			mat.m[2][0], mat.m[2][1], mat.m[2][2],mat.m[2][3] ) ;
		DrawFormatString( 0, 32*4, GetColor( 255,255,255 ), "m[3][0] %f  m[3][1] %f  m[3][2] %f m[3][3] %f",
			mat.m[3][0], mat.m[3][1], mat.m[3][2],mat.m[3][3] ) ;
	}
    // DXライブラリの後始末
    DxLib_End() ;

    // ソフトの終了
    return 0 ;
}
と、コードはこんな感じになり、行列は反映できたのですが、

カメラをいくら動かしても、画面が真っ暗なままです。

どうやら描画されてるのですが、カメラがそれをとらえてないようです。
行列を以下のようにカメラクラス以外のものにし、回転率をいじってみたら
カメラが描画された画像をとらえました。

コード:

while(!ScreenFlip()&&!ProcessMessage()&&!ClearDrawScreen()&&!UpdateKey()&&!UpdateMouse()){
		// 左右キーでカメラの回転値を変更
        if( CheckHitKey( KEY_INPUT_LEFT ) == 1 )
        {
            Rot1 -= PHI_F / 60.0f ;
        }
        if( CheckHitKey( KEY_INPUT_RIGHT ) == 1 )
        {
            Rot1 += PHI_F / 60.0f ;
        }
		if( CheckHitKey( KEY_INPUT_UP ) == 1 )
        {
            Rot2 -= PHI_F / 60.0f ;
        }
        if( CheckHitKey( KEY_INPUT_DOWN ) == 1 )
        {
            Rot2 += PHI_F / 60.0f ;
        }
		
		// 回転値を使用してXY軸の回転行列を作成
        mat = MMult(MGetRotX( Rot2 ),MGetRotY( Rot1 )) ;
		
		SetupCamera_Ortho( 480 ) ;

        // 回転行列をビュー行列としてセット
        SetCameraViewMatrix( mat ) ;

		DrawBillboard3D( VGet( 800.0f, 0.0f,0.0f), 0.5f, 0.5f, 338.0f, 0.0f, haikei, TRUE ) ;
画面が真っ暗な状態の直し方はもちろんわからないのですが、それ以前に、画面内の3d空間がどうなってるのかいまいちわかりません。
回転行列でいろいろいじってみましたが、いまいちどうなってるのかがわかりません。

2d画面はxは横、yは縦とわかったのですが、
3d空間はどれがx方向、y方向、z方向なのか、どれもわからず、暗闇にどんと突き落とされたみたいです。
y方向に回転するとなぜか2d画面で言う横、xの動きをするし、x方向にカメラを回転すると縦に動くし、z方向にカメラを回転すると画面が回るし、だんだん頭がおかしく―――(^ω^;)
おかげで図も書けず、画面真っ暗問題をどう直すかも考えられない始末です。
正射角に変えたカメラは、どんな3d空間のどこにあり、どこを向いていて、描画された画像はどこにあるんでしょうか?

3Dははじめてなのでかなり初歩的な事を聞いていると思いますが、この言葉をググれでもかまいません。
アドバイスお願いします。

hide

Re: DXライブラリでの2D用カメラ作成について

#4

投稿記事 by hide » 6年前

3D空間は基本的に 水平方向が x,z 垂直方向が y とするのが普通です。
FPSみたいな感じで 自分自身基準のローカル座標だと z軸の正の方向が前方 真上が y軸となります。
directXだと左手系座標なので自分自身基準で右がx軸の正の方向です。

目の前のPCの画面の左下を基準にして上がy軸、右がx軸 画面の奥行きがz軸 ってイメージです。

y軸で回転と言うと 上を向くイメージを持ってしまうと思いますが、その感覚は捨てましょう。
y軸で回転するというのは、y軸の方向を維持したまま、水平に回転します。 イスに座ってくるくる回るイメージです。
なのでxの動きをした、という感覚はあっています。

正射角という言葉はよくわかりませんね。


DXライブラリのカメラは簡単に行くならば
SetCameraPositionAndTarget_UpVecY がオススメです。
行列を理解する前にこちらで空間とその捉え方を鍛える必要があると思います。

イマダニ
記事: 145
登録日時: 8年前

Re: DXライブラリでの2D用カメラ作成について

#5

投稿記事 by イマダニ » 6年前

>>正射角という言葉はよくわかりませんね。
正射影でした。すみません

正射影・空間の必須手法  
http://www004.upp.so-net.ne.jp/s_honma/ ... ection.HTM
hide さんが書きました: DXライブラリのカメラは簡単に行くならば
SetCameraPositionAndTarget_UpVecY がオススメです。
行列を理解する前にこちらで空間とその捉え方を鍛える必要があると思います。
早速やってみました。そのへんに落ちてるpmdをダウンロードし、それを表示して、カメラでみてます。色々新鮮で楽しいです。

ここまでの話を聞く限り、やはり2D用のカメラを作るというのはちょっとちがうみたいですね。
2D用のカメラを作るというより、3Dの処理、3dのカメラや3dの描画関数を2D用に扱うといったかんじでしょうか。
画面拡大縮小する2Dゲーム、ペイントソフトの拡大縮小、IPhoneの拡大縮小も2Dのように見えていても実際の描画方法は3Dのカメラを使っている、そんな印象を受けます。

というわけで本格的に3Dを勉強してみます。

今回はこれで解決とします。
お二方、アドバイスありがとうございました。

Mana

Re: DXライブラリでの2D用カメラ作成について

#6

投稿記事 by Mana » 6年前

2Dなら表示画面より大きいオフスクリーンに描画して縮小表示すればいいのではなかろうか。
リンク先の動画のように拡大縮小回転自由にできる。
テクスチャをオフスクリーンに見立てて立方体の壁面に映すなんてこともできる。

キーワードはオフスクリーンだ。
カメラに目を付けたのは失敗だったな。

閉鎖

“C言語何でも質問掲示板” へ戻る