Home > 3D | C言語(Windows) | DXライブラリ > 【DXライブラリ3D入門】2Dに合わせて3Dグラフィックスを描画する その1

【DXライブラリ3D入門】2Dに合わせて3Dグラフィックスを描画する その1

お知らせ:DXライブラリオンライン関数リファレンス付録編の3D関数編を公開しました。まだすべての関数の解説は揃っておりませんが、本記事を読む助けとしていただければ幸いです(足りない関数については本家「DXライブラリ置き場」のリファレンスをご参照ください)。

注:本記事で配布するソースコードにはモデルデータは含めませんので、それぞれの配布元から別途ダウンロードしてください(詳しくは初回記事を参照)。


前回記事で公開したマリオブラザーズ風のゲームデモのグラフィックス処理について解説していきます。このゲームデモはもともと2D向けに作ったものです。3D版ではジャンプ処理のあたりを少し調整しましたが、基本的にはほとんど同じプログラムです。main.hの12行目にある定数B2D_DEBUG_DRAWのコメントを解除してから実行すると……

main.h

#include <DxLib.h>
#include <Box2D/Box2D.h>
#ifdef _DEBUG
	#pragma comment(lib, "Box2D_d.lib")
#endif
#ifndef _DEBUG
	#pragma comment(lib, "Box2D.lib")
#endif
#include "_dxdebugdraw.h"

//定数
#define B2D_DEBUG_DRAW
const int VELOCITYITE = 6;		//速度計算精度
const int POSITIONITE = 2;		//位置計算精度

3Dグラフィックスに重なってBox2Dのデバッグドロー(物理エンジンが管理しているボディやジョイントを表示するデバッグ用機能)が表示されます。これを見ると完全に2Dのプログラムであることがわかると思います。

WS001607

©CRYPTON FUTURE MEDIA, INC.

Copyright (C) 2008-2010 唄音ウタProject, 飴屋/菖蒲 All Rights Reserved.

2Dと3Dの表示を合わせるには?

DXライブラリは2Dと3Dを混在して扱える(というより、もともと2D描画でも3Dグラフィックス機能を利用している)ので、同時に表示すること自体は普通にできます。しかし、座標軸の向きや単位などが違うので、まったく同じように動かすのはそれほど簡単ではありません。

ソースコードを見せる前に、ひとつひとつ理屈を説明していきましょう。

座標軸の方向の違いは比較的簡単に解決できます。2DのYの座標値にマイナスを付けて負の値にしてやればいいのです。2DのY座標値も3Dの負のY座標値も、絶対値が増えるほど下になります。この方式ならX座標値はそのまま使えるので、ちょっとした計算で簡単に座標変換できます。

WS001615

 

次は座標やサイズに使う単位の問題について考えてみます。サンプルプログラムでは2D、3Dの座標系に加えて、もうひとつの座標系があります。それはBox2Dが使う物理演算用の座標系です。この座標系では単位としてメートルが使われています。

2Dグラフィックスではピクセルを単位として使うのがやりやすいので、2D版のプログラムではピクセルでキャラクタの位置や大きさを指定し、それをメートルに換算してからBox2Dに渡し、画面描画を行う際にまたピクセルに戻していました。具体的には「50ピクセル=1メートル」としていたので、Box2Dに渡す前に50で割り、画面表示する前に50を掛けていたのです。

WS001617

これに合わせて3Dグラフィックスを描画するのですが、前に説明したとおり3Dの座標系には単位はありません。ですから理論上はメートル単位やピクセル単位の座標値、サイズ値をそのまま使ってもいいことになります。

しかし、実際に使うとなると色々な問題が出てきます。ひとつはモデルのサイズです。PMDエディタで調べたところ、PMDねんどろ風初音ミクv1.1のサイズはだいたい「13」ということがわかりました。モデルを綺麗に見せるためには拡大縮小を避けたほうがいいので、原寸で表示して2Dとサイズが合うように調整するのが望ましいといえます。

WS001583

ここでもうひとつ問題になってくるのは、元の2D描画のサイズが小さすぎることです。元のプログラムでは、マップを構成する1ブロックのサイズを36ピクセルで作成していましたが、これに合わせて3Dのモデルを表示すると、ディテールがほとんど見えなくなってしまいます。

色々検討した結果、2Dのデバッグドローの表示は元の1.5倍、3D描画はBox2Dのメートル単位の値を10倍して表示することにしました。

WS001618

2Dのデバッグドローを1.5倍にする処理は、次のように定数DDRAWSCALERATEを定義しておいて……

_dxdebugdraw.h

const float DDRAWSCALERATE = 1.5f;	//表示のみ拡大したいときに使用
class DxDebugDraw :public b2DebugDraw{
private:
	b2Vec2 screen_pos;
	float WLDSC;
	inline int ColorValue(b2Color col){

座標、サイズ値をメートル単位から変換するときに、DDRAWSCALERATEを掛けるようにします。

_dxdebugdraw.cpp

	inline int ColorValue(b2Color col){
		return (int)(col.r * 0xFF0000 + col.g * 0xFF00 + col.b * 0xFF);
	}
	inline int VIWX(float32 x){
		return (int)(x * WLDSC * DDRAWSCALERATE - screen_pos.x);
	}
	inline int VIWY(float32 y){
		return (int)(y * WLDSC * DDRAWSCALERATE - screen_pos.y);
	}
	inline int VIW(float32 v){
		return (int)(v * WLDSC * DDRAWSCALERATE);
	}

3Dグラフィックスを描画する処理では、定数VIEW3DSCALEを定義しておいて……

main.h

//定数
#define B2D_DEBUG_DRAW
const int VELOCITYITE = 6;		//速度計算精度
const int POSITIONITE = 2;		//位置計算精度
const float GRAVITY_Y = 20.0f;	//重力加速度
const float WLDSC = 50.0f;		//世界倍率
const float SCREENAREA = 300.0f;//スクリーン範囲(ステージ外判定用)
const int SCROLL_LIMIT = 100;	//スクロール限界
const float VIEW3DSCALE = 10.0f;	//3D座標への変換に使うスケール値
const float WORLDZPOS = 320.0f;	//X軸の座標(全キャラ固定)
const float UNITSIZE_3D = 7.2f;	//3Dの1モデルのサイズ

2D座標から3D座標を求めるVIW3D関数を定義します。

_utils.cpp

//3D向けの座標変換関数
VECTOR VIW3D(float x, float y, float z3d){
	return VGet(x * VIEW3DSCALE, -y * VIEW3DSCALE, z3d);
}

この関数は、次のように2D座標から3D座標値を納めたVECTOR型の3D座標値を求めます。3つめの引数z3dは省略可能で、省略した場合は定数WORLDZPOS(320.0f)が使われます。

b2Vec2 pos = g_stage.hero.body->GetPosition();
VECTOR heropos = VIW3D(pos.x, pos.y+0.05f);
MV1SetPosition(g_stage.heroanim.model, heropos);
MV1DrawModel(g_stage.heroanim.model);

後はこの設定で2Dと3Dがうまく合うよう、SetupCamera_Ortho関数の値を調整します(今回は70を指定しています)。並行投影カメラを設定するSetupCamera_Orth関数については過去の記事を参照してください。

	SetCameraNearFar(10, 1000);
	SetupCamera_Ortho(70);

ちなみに並行投影カメラを使うと2Dっぽい描画になりますが、完全に一致するわけではありません。カメラの注視点(このゲームの場合は画面中央)に近い場所のみピタリと重なり、そこから遠くなるほど大きくずれていきます。ただし、3D描画全てが同じようにずれるので、注視点の位置で揃うように作成しておけば実用上の問題はありません。

WS001608WS001611

WS001610

 

 

さて、今回は少々ややこしい計算をしましたが、それは元々が2Dのプログラムだったからです。マップデータやキャラクターサイズなどをすべてピクセルで指定していたため、そこを変更するとなると全体にわたる微調整が必要です。

もし最初から3D前提で作るなら、最初からBox2Dのメートル単位で指定した方が簡単でいいかもしれません。

WS001619

 

次回はスクロール処理範囲内のみ描画する方法について解説します。

Comments:0

Comment Form
Remember personal info

Trackbacks:0

Trackback URL for this entry
http://i-libro.net/wpmu/blog/archives/984/trackback
Listed below are links to weblogs that reference
【DXライブラリ3D入門】2Dに合わせて3Dグラフィックスを描画する その1 from わくわくプログラミング自習室 Blogs

Home > 3D | C言語(Windows) | DXライブラリ > 【DXライブラリ3D入門】2Dに合わせて3Dグラフィックスを描画する その1

Amazonリンク

Return to page top