【座標計算の基礎】
【座標系】
(1) 2次元座標系
コンピュータ画面上の2次元座標系は,「ゲームソフトウェア設計論」でも学習したように,一般にはy軸は下向きである。
描画対象領域の左上が原点となり,たいていは整数値で表され,単位としては pixel が使われる。

(2) 3次元座標系
・
右手座標系と左手座標系
3次元座標系は,左手座標系または右手座標系で表される(下図)。ここでは,親指がX軸,人差し指がY軸,中指がZ軸である。
![]() |
![]() |
※ここでは,y軸を上方向としたが,zjik卯を上方向とする場合もある。
※座標値は実数値で表されるが,単位は決まっていないことが多く,決まっていてもソフトによってまちまちである(1.0が1.0mを表しているものもあれば,1.0cmを表してることもある)。
なお,XYZの座標軸は光の三原色のRGBになぞらえて,X軸が赤(R),Y軸が緑(G),Z軸が青(B)で表示されるのが一般的である。
| x | y | z |
| 親指 | 人差し指 | 中指 |
| 赤(R) | 緑(G) | 青(B) |
・ソフトによる座標系の違い
各ソフトウェアによっての採用している座標系は以下のとおり。
| ソフトウェア | DirectX/DXライブラリ | Unity | MMD | OpenGL | Metasequoia | Blender |
| 座標系 | 左手座標系 | 右手座標系 |
右手座標系 | |||
| 上向き | y軸 | z軸 | ||||
【ベクトルと座標変換】
ベクトル(vector,英語読みだとベクタ)とは,基本的には
・複数の数値を組にしたもの
(数ベクトル) 例:(1.0, 2.0, 3.0)
であるが,幾何学的には
・向きと大きさをもったもの (幾何ベクトル) (下図の矢印)

を言う。幾何ベクタは,「どこにあるか」は問題にならず,あくまで「向き」と「大きさ」だけをもったものである。
したがって,座標系で扱う時はその始点を原点に合わせて扱う(下図)。

上図の様に,幾何ベクトルの始点を原点に揃えると,幾何ベクトルの終点の座標(これ自体は数ベクトル)で表現できる。
3次元でも同様である。
【DXライブラリでのベクトル表現】
・ DXライブラリでは,3次元座標値は単精度浮動小数点数型 ( float型 ) で表されている。
C/C++では, 1.2 というように小数点を含んだリテラル定数値を書くと double 型の値として扱われる。これをDXライブラリが float型値を要求するところに渡すと,
double→float の型変換作業が行われることになるので効率が悪い。 1.2f のように,末尾に f を付けると float型の実数値リテラルになるので, DXライブラリ用の
実数リテラルは,できるだけ末尾に f をつけておくこと。
・VECTOR構造体
DXライブラリでは,ヘッダファイル DxLib.h 内で 3次元ベクトルを表す VECTOR 構造体を次の様に定義している。
また,手軽に VECTOR構造体型の値を作成することができるVGet( ) 関数が用意されている(下図)。

・色の指定
DXライブラリでは, RGBそれぞれ 0〜255 で指定できる
色を利用できる。その際, GetColor( )関数でRGB値を指定し, unsigned int 型の色コードを返す関数
GetColor( ) が便利である。
・ベクトル演算関数
DXライブラリには,様々なベクトル演算関数が用意されている(「DXライブラリ 関数リファレンスページ 3D関係関数リファレンス」ページの「算術演算関数」の項を参照のことほうこう)。
#include <DxLib.h>
#include <cmath>
// 三次元の原点(VECTOR型はDXライブラリのヘッダで定義されている三次元座標を表す構造体)
VECTOR theOrigin = {0.0f, 0.0f, 0.0f};
/***
*** void draw3DArrow( float x0 = 0.0f, float y0 = 0.0f, float z0 = 0.0f,
*** float x1 = 1.0f, float y1 = 1.0f, float z1 = 1.0f, unsigned int theColor = VGet(255,0,0), float coneSize = 0.0f );
***
*** 三次元の矢印を始点( x0, y0, z0 ) 終点( x1, y1, z1 )間に描写する。色は色コードtheColor。
*** 矢印の先の円錐の高さを coneSize で指定する。coneSize の値が 0.0f の場合は、円錐の高さは自動調整される。
*** withArrow が true なら矢印の先の円錐を描画し、false なら描画しない。
***/
void draw3DArrow( float x0 = 0.0f, float y0 = 0.0f, float z0 = 0.0f,
float x1 = 1.0f, float y1 = 1.0f, float z1 = 1.0f, unsigned int theColor = GetColor(255,0,0), float coneSize = 0.0f, bool withArrow = true );
void draw3DArrow( float x0, float y0, float z0,
float x1, float y1, float z1, unsigned int theColor, float coneSize, bool withArrow ) {
VECTOR p0 = VGet( x0, y0, z0 );
VECTOR p1 = VGet( x1, y1, z1 );
DrawLine3D( p0, p1, theColor );
float len = sqrt( (x1-x0)* (x1-x0) + (y1-y0)*(y1-y0) + (z1-z0)*(z1-z0) );
if( withArrow ) {
if( coneSize <= 0.0f ) coneSize = len / 10.0f; // 矢印先の円錐の長さが0.0f以下に指定された場合は自動調整する。
float r = (len - coneSize) / len;
float xp = x0 + (x1-x0)*r;
float yp = y0 + (y1-y0)*r;
float zp = z0 + (z1-z0)*r;
DrawCone3D(VGet(x1, y1, z1), VGet( xp, yp, zp), coneSize / 4.0f, 12, theColor, theColor, TRUE);
}
}
/***
*** draw3DArrow( VECTOR p0 = VGet( 0.0f, 0.0f, 0.0f ), VECTOR p1 = VGet( 1.0f, 1.0f, 1.0f ),
*** unsigned int theColor = GetColor(255,0,0), float coneSize = 0.0f, bool withArrow = true );
***
*** 三次元の矢印を始点p0 終点p1間に描写する。色は色コードtheColor。矢印の先の円錐の高さを coneSize で指定する。
*** coneSize の値が 0.0f の場合は、円錐の高さは自動調整される。
*** withArrow が true なら矢印の先の円錐を描画し、false なら描画しない。
***/
void draw3DArrow( VECTOR p0 = VGet( 0.0f, 0.0f, 0.0f ), VECTOR p1 = VGet( 1.0f, 1.0f, 1.0f ), unsigned int theColor = GetColor(255,0,0), float coneSize = 0.0f, bool withArrow = true );
void draw3DArrow( VECTOR p0, VECTOR p1, unsigned int theColor, float coneSize, bool withArrow ) {
draw3DArrow(p0.x, p0.y, p0.z, p1.x, p1.y, p1.z, theColor, coneSize, withArrow );
}
/***
*** draw3DAxisArrow( float x0 = 0.0f, float y0 = 0.0f, float z0 = 0.0f, float length = 1.0f, bool withArrow = true );
*** (x0, y0, z0) を始点としたXYZ座標軸を描写する。X軸は赤、Y軸は緑、Z軸は青。
*** length は座標軸の長さ。withArrow が true の場合は、座標軸を円錐を使った矢印として描写する。
***/
void draw3DAxisArrow( float x0 = 0.0f, float y0 = 0.0f, float z0 = 0.0f, float length = 1.0f, bool withArrow = true );
void draw3DAxisArrow( float x0, float y0, float z0, float length, bool withArrow ) {
draw3DArrow( x0, y0, z0, x0 + length, y0, z0, GetColor(255, 0, 0), 0.0f, withArrow );
draw3DArrow( x0, y0, z0, x0, y0 + length, z0, GetColor(0, 255, 0), 0.0f, withArrow );
draw3DArrow( x0, y0, z0, x0, y0, z0 + length, GetColor(0, 0, 255), 0.0f, withArrow );
}
/***
*** void drawXZPlane( int numOfMesh, float meshInterval, bool FillFlag = true );
*** numOfMesh 個の格子(一辺の長さは meshInterval )で、原点を中心としたXZ平面を描写する。
*** FillFlag が true の場合は、平面を白く塗りつぶし、false の場合は塗りつぶさない。
***/
void drawXZPlane( int numOfMesh, float meshInterval, bool FillFlag = true );
void drawXZPlane( int numOfMesh, float meshInterval, bool FillFlag ) {
float width = numOfMesh * meshInterval;
float x0 = - width / 2.0f;
float z0 = x0;
unsigned int lineColor = GetColor(220, 220, 220);
// FillFlag が true なら、平面(原点を中心とした一辺が width の正方形領域)を白で塗りつぶす(実際には白い三角ポリゴンを2個描写する)。
if( FillFlag ) {
DrawTriangle3D( VGet( x0, 0.0f, z0), VGet(x0, -0.0f, -z0), VGet(-x0, 0.0f, z0), GetColor(255,255,255), true );
DrawTriangle3D( VGet(-x0, 0.0f, -z0), VGet(x0, -0.0f, -z0), VGet(-x0, 0.0f, z0), GetColor(255,255,255), true );
lineColor = GetColor(220, 220, 220);
}
// 格子線を描写する。
for(int n = 0; n <= numOfMesh; n++ ) {// Z軸に平行な平行線分を書く。
float ratio = n / (1.0f * numOfMesh);
float offset = ratio * width;
DrawLine3D( VGet(x0 + offset, 0.0f, z0), VGet(x0 + offset, 0.0f, -z0), lineColor );
}
for(int n = 0; n <= numOfMesh; n++ ) {// X軸に平行な平行線分を書く。
float ratio = n / (1.0f * numOfMesh);
float offset = ratio * width;
DrawLine3D( VGet(x0, 0.0f, z0 + offset), VGet(-x0, 0.0f, z0 + offset), lineColor );
}
}
/***
*** void drawRectangle( VECTOR p0, VECTOR p1, VECTOR p2, VECTOR p3, unsigned int color = GetColor(255,255,255) );
*** 4頂点を p0, p1, p2, p3 とする color 色の矩形を描写する。なお、頂点 p0とp2 は対角頂点である事。
***
***/
void drawRectangle( VECTOR p0, VECTOR p1, VECTOR p2, VECTOR p3, unsigned int color = GetColor(255,255,255) );
void drawRectangle( VECTOR p0, VECTOR p1, VECTOR p2, VECTOR p3, unsigned int color ) {
DrawTriangle3D( p0, p1, p2, color, true );
DrawTriangle3D( p2, p3, p0, color, true );
}
/***
*** void drawCube( VECTOR center, float width, unsigned int color = GetColor(255,255,255) );
*** 中心点 center を囲む一辺の長さが width の立方体を描写する。面の色は color で指定する。
*** 尚、各面はXY平面、YZ平面、XZ平面のいずれかに平行である。
***
***/
void drawCube( VECTOR center, float width, unsigned int color = GetColor(255,255,255) );
void drawCube( VECTOR center, float width, unsigned int color ) {
float x = center.x;
float y = center.y;
float z = center.z;
float s = width / 2.0f;
// 立方体の8頂点を取得する。
VECTOR v_XYZ = VGet( x + s, y + s, z + s );
VECTOR v_XYz = VGet( x + s, y + s, z - s );
VECTOR v_XyZ = VGet( x + s, y - s, z + s );
VECTOR v_xYZ = VGet( x - s, y + s, z + s );
VECTOR v_Xyz = VGet( x + s, y - s, z - s );
VECTOR v_xYz = VGet( x - s, y + s, z - s );
VECTOR v_xyZ = VGet( x - s, y - s, z + s );
VECTOR v_xyz = VGet( x - s, y - s, z - s );
// 立方体の面を描画する。
drawRectangle( v_XYZ, v_XYz, v_Xyz, v_XyZ, color );
drawRectangle( v_XYZ, v_xYZ, v_xYz, v_XYz, color );
drawRectangle( v_xyz, v_Xyz, v_XYz, v_xYz, color );
drawRectangle( v_Xyz, v_XyZ, v_xyZ, v_xyz, color );
drawRectangle( v_XYZ, v_xYZ, v_xyZ, v_XyZ, color );
drawRectangle( v_xyz, v_xyZ ,v_xYZ, v_xYz, color );
}
int WINAPI WinMain( HINSTANCE, HINSTANCE, LPSTR, int ){
ChangeWindowMode( TRUE ); // ゲーム画面をウィンドウで表示するように指定する。
DxLib_Init(); // DXライブラリを初期化する。
SetDrawScreen( DX_SCREEN_BACK ); // 描写先を裏画面にする。
//カメラの描写範囲(奥行)を0.1〜10000.0に設定する。
SetCameraNearFar( 0.1f, 10000.0f );
//( 0.0, 9.0, -22.0 )の位置にカメラを設置し、視線を( 0.0, 10.0, 0.0 )にあるターゲットへ向ける。
VECTOR cameraPos = VGet( 0.0f, 9.0f, -22.0f );
VECTOR theTarget = VGet( 0.0f, 10.0f, 0.0f );
bool targeIsOrigin = false;
SetCameraPositionAndTarget_UpVecY( cameraPos, theTarget );
//Zバッファを使って図形描写を行う。
SetUseZBuffer3D( TRUE );
SetWriteZBuffer3D( TRUE );
// 繰り返し。
while( ! ProcessMessage() ){
// 描写先の画面(裏画面)を消去する。
ClearDrawScreen();
// 原点を囲むように、一辺が 100.f の白い立方体を描写する。
drawCube( VGet(0.0f, 0.0f, 0.0f), 200.0f );
// XZ平面を描写する。
drawXZPlane( 100, 1.0, false );
// 座標軸を描写する。
draw3DAxisArrow( 0.0f, 0.0f, 0.0f, 8.0f );
// カメラの座標を画面左下に表示する。
DrawFormatString( 0, 460, GetColor(0,0,0), "%6.2f, %6.2f, %6.2f", cameraPos.x, cameraPos.y, cameraPos.z );
// 完成した裏画面の内容を表画面(ゲームのウィンドウ)に転写する。
ScreenFlip();
// キー(ゲームコントローラー)の状態を得る。
int keyInput = GetJoypadInputState( DX_INPUT_KEY_PAD1 );
// カメラ(とターゲット)の位置を変更する
if( keyInput == PAD_INPUT_DOWN ) {
cameraPos.z = cameraPos.z - 0.5; theTarget.z = theTarget.z - 0.5f;
}
if( keyInput == PAD_INPUT_UP ) {
cameraPos.z = cameraPos.z + 0.5; theTarget.z = theTarget.z + 0.5f;
}
if( keyInput == PAD_INPUT_LEFT ) {
cameraPos.x = cameraPos.x - 0.5; theTarget.x = theTarget.x - 0.5f;
}
if( keyInput == PAD_INPUT_RIGHT ) {
cameraPos.x = cameraPos.x + 0.5; theTarget.x = theTarget.x + 0.5f;
}
char c = GetInputChar( TRUE );
if( c == 'u' ) {
cameraPos.y = cameraPos.y + 0.5f; theTarget.y = theTarget.y + 0.5f;
}
if( c == 'n' ) {
cameraPos.y = cameraPos.y - 0.5f; theTarget.y = theTarget.y - 0.5f;
}
if( c == 't' ) { // カメラのターゲットを標準位置にするか原点にするか切り替える。
targeIsOrigin = !targeIsOrigin;
}
// カメラの位置を設定しなおす。
if( targeIsOrigin ) { // targeIsOrigin が true なら、カメラをターゲットに向ける。
SetCameraPositionAndTarget_UpVecY( cameraPos, VGet(0.0f, 0.0f, 0.0f) );
}
else { // targeIsOrigin が false なら、カメラを標準位置に向ける。
SetCameraPositionAndTarget_UpVecY( cameraPos, theTarget );
}
}
DxLib_End(); // DXライブラリの後処理を行う.
return 0 ;
}
#include <DxLib.h>
#include <cmath>
// 三次元の原点(VECTOR型はDXライブラリのヘッダで定義されている三次元座標を表す構造体)
VECTOR theOrigin = { 0.0f, 0.0f, 0.0f };
/***
*** void draw3DArrow( float x0 = 0.0f, float y0 = 0.0f, float z0 = 0.0f,
*** float x1 = 1.0f, float y1 = 1.0f, float z1 = 1.0f, unsigned int theColor = VGet(255,0,0), float coneSize = 0.0f );
***
*** 三次元の矢印を始点( x0, y0, z0 ) 終点( x1, y1, z1 )間に描写する。色は色コードtheColor。
*** 矢印の先の円錐の高さを coneSize で指定する。coneSize の値が 0.0f の場合は、円錐の高さは自動調整される。
*** withArrow が true なら矢印の先の円錐を描画し、false なら描画しない。
***/
void draw3DArrow(float x0 = 0.0f, float y0 = 0.0f, float z0 = 0.0f,
float x1 = 1.0f, float y1 = 1.0f, float z1 = 1.0f, unsigned int theColor = GetColor(255, 0, 0), float coneSize = 0.0f, bool withArrow = true);
void draw3DArrow(float x0, float y0, float z0,
float x1, float y1, float z1, unsigned int theColor, float coneSize, bool withArrow) {
VECTOR p0 = VGet(x0, y0, z0);
VECTOR p1 = VGet(x1, y1, z1);
DrawLine3D(p0, p1, theColor);
float len = sqrt((x1 - x0)* (x1 - x0) + (y1 - y0)*(y1 - y0) + (z1 - z0)*(z1 - z0));
if (withArrow) {
if (coneSize <= 0.0f) coneSize = len / 10.0f; // 矢印先の円錐の長さが0.0f以下に指定された場合は自動調整する。
float r = (len - coneSize) / len;
float xp = x0 + (x1 - x0)*r;
float yp = y0 + (y1 - y0)*r;
float zp = z0 + (z1 - z0)*r;
DrawCone3D(VGet(x1, y1, z1), VGet(xp, yp, zp), coneSize / 4.0f, 12, theColor, theColor, TRUE);
}
}
/***
*** draw3DArrow( VECTOR p0 = VGet( 0.0f, 0.0f, 0.0f ), VECTOR p1 = VGet( 1.0f, 1.0f, 1.0f ),
*** unsigned int theColor = GetColor(255,0,0), float coneSize = 0.0f, bool withArrow = true );
***
*** 三次元の矢印を始点p0 終点p1間に描写する。色は色コードtheColor。矢印の先の円錐の高さを coneSize で指定する。
*** coneSize の値が 0.0f の場合は、円錐の高さは自動調整される。
*** withArrow が true なら矢印の先の円錐を描画し、false なら描画しない。
***/
void draw3DArrow(VECTOR p0 = VGet(0.0f, 0.0f, 0.0f), VECTOR p1 = VGet(1.0f, 1.0f, 1.0f), unsigned int theColor = GetColor(255, 0, 0), float coneSize = 0.0f, bool withArrow = true);
void draw3DArrow(VECTOR p0, VECTOR p1, unsigned int theColor, float coneSize, bool withArrow) {
draw3DArrow(p0.x, p0.y, p0.z, p1.x, p1.y, p1.z, theColor, coneSize, withArrow);
}
/***
*** draw3DAxisArrow( float x0 = 0.0f, float y0 = 0.0f, float z0 = 0.0f, float length = 1.0f, bool withArrow = true );
*** (x0, y0, z0) を始点としたXYZ座標軸を描写する。X軸は赤、Y軸は緑、Z軸は青。
*** length は座標軸の長さ。withArrow が true の場合は、座標軸を円錐を使った矢印として描写する。
***/
void draw3DAxisArrow(float x0 = 0.0f, float y0 = 0.0f, float z0 = 0.0f, float length = 1.0f, bool withArrow = true);
void draw3DAxisArrow(float x0, float y0, float z0, float length, bool withArrow) {
draw3DArrow(x0, y0, z0, x0 + length, y0, z0, GetColor(255, 0, 0), 0.0f, withArrow);
draw3DArrow(x0, y0, z0, x0, y0 + length, z0, GetColor(0, 255, 0), 0.0f, withArrow);
draw3DArrow(x0, y0, z0, x0, y0, z0 + length, GetColor(0, 0, 255), 0.0f, withArrow);
}
/***
*** void drawXZPlane( int numOfMesh, float meshInterval, bool FillFlag = true );
*** numOfMesh 個の格子(一辺の長さは meshInterval )で、原点を中心としたXZ平面を描写する。
*** FillFlag が true の場合は、平面を白く塗りつぶし、false の場合は塗りつぶさない。
***/
void drawXZPlane(int numOfMesh, float meshInterval, bool FillFlag = true);
void drawXZPlane(int numOfMesh, float meshInterval, bool FillFlag) {
float width = numOfMesh * meshInterval;
float x0 = -width / 2.0f;
float z0 = x0;
unsigned int lineColor = GetColor(220, 220, 220);
// FillFlag が true なら、平面(原点を中心とした一辺が width の正方形領域)を白で塗りつぶす(実際には白い三角ポリゴンを2個描写する)。
if (FillFlag) {
DrawTriangle3D(VGet(x0, 0.0f, z0), VGet(x0, -0.0f, -z0), VGet(-x0, 0.0f, z0), GetColor(255, 255, 255), true);
DrawTriangle3D(VGet(-x0, 0.0f, -z0), VGet(x0, -0.0f, -z0), VGet(-x0, 0.0f, z0), GetColor(255, 255, 255), true);
lineColor = GetColor(220, 220, 220);
}
// 格子線を描写する。
for (int n = 0; n <= numOfMesh; n++) {// Z軸に平行な平行線分を書く。
float ratio = n / (1.0f * numOfMesh);
float offset = ratio * width;
DrawLine3D(VGet(x0 + offset, 0.0f, z0), VGet(x0 + offset, 0.0f, -z0), lineColor);
}
for (int n = 0; n <= numOfMesh; n++) {// X軸に平行な平行線分を書く。
float ratio = n / (1.0f * numOfMesh);
float offset = ratio * width;
DrawLine3D(VGet(x0, 0.0f, z0 + offset), VGet(-x0, 0.0f, z0 + offset), lineColor);
}
}
/***
*** void drawRectangle( VECTOR p0, VECTOR p1, VECTOR p2, VECTOR p3, unsigned int color = GetColor(255,255,255) );
*** 4頂点を p0, p1, p2, p3 とする color 色の矩形を描写する。なお、頂点 p0とp2 は対角頂点である事。
***
***/
void drawRectangle(VECTOR p0, VECTOR p1, VECTOR p2, VECTOR p3, unsigned int color = GetColor(255, 255, 255));
void drawRectangle(VECTOR p0, VECTOR p1, VECTOR p2, VECTOR p3, unsigned int color) {
DrawTriangle3D(p0, p1, p2, color, true);
DrawTriangle3D(p2, p3, p0, color, true);
}
/***
*** void drawCube( VECTOR center, float width, unsigned int color = GetColor(255,255,255) );
*** 中心点 center を囲む一辺の長さが width の立方体を描写する。面の色は color で指定する。
*** 尚、各面はXY平面、YZ平面、XZ平面のいずれかに平行である。
***
***/
void drawCube(VECTOR center, float width, unsigned int color = GetColor(255, 255, 255));
void drawCube(VECTOR center, float width, unsigned int color) {
float x = center.x;
float y = center.y;
float z = center.z;
float s = width / 2.0f;
// 立方体の8頂点を取得する。
VECTOR v_XYZ = VGet(x + s, y + s, z + s);
VECTOR v_XYz = VGet(x + s, y + s, z - s);
VECTOR v_XyZ = VGet(x + s, y - s, z + s);
VECTOR v_xYZ = VGet(x - s, y + s, z + s);
VECTOR v_Xyz = VGet(x + s, y - s, z - s);
VECTOR v_xYz = VGet(x - s, y + s, z - s);
VECTOR v_xyZ = VGet(x - s, y - s, z + s);
VECTOR v_xyz = VGet(x - s, y - s, z - s);
// 立方体の面を描画する。
drawRectangle(v_XYZ, v_XYz, v_Xyz, v_XyZ, color);
drawRectangle(v_XYZ, v_xYZ, v_xYz, v_XYz, color);
drawRectangle(v_xyz, v_Xyz, v_XYz, v_xYz, color);
drawRectangle(v_Xyz, v_XyZ, v_xyZ, v_xyz, color);
drawRectangle(v_XYZ, v_xYZ, v_xyZ, v_XyZ, color);
drawRectangle(v_xyz, v_xyZ, v_xYZ, v_xYz, color);
}
int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int){
ChangeWindowMode(TRUE); // ゲーム画面をウィンドウで表示するように指定する。
DxLib_Init(); // DXライブラリを初期化する。
SetDrawScreen(DX_SCREEN_BACK); // 描写先を裏画面にする。
// MMDキャラクタモデルと背景モデルをモーション付きで描画するために必要な変数群
int modelHandle1, modelHandle_BG; // 読み込んだ3Dモデルデータの番号を記録しておく変数
int attachIndex; // アタッチされたアニメーションの番号を記録しておく変数
float animTime000; // アニメーションの総再生時間を記録しておく変数
float theTime; // アニメーションの再生時間を記録しておく変数
// 以下,(1)〜(8)は, MMDキャラクタモデルと背景モデルを描写するための処理
// (1)3Dモデルデータの読み込み
modelHandle1 = MV1LoadModel("那珂ver1.01/那珂ver1.0.1.pmd");
modelHandle_BG = MV1LoadModel("かぼちゃステージ/カボチャステージ(空セット).pmx");
// (2) 3Dモデル1に対してアニメーション0番をアタッチする
attachIndex = MV1AttachAnim(modelHandle1, 0, -1, FALSE);
// (3) アタッチしたアニメーションの再生時間を得る
animTime000 = MV1GetAttachAnimTotalTime(modelHandle1, attachIndex);
// (4) ゲーム内時間の初期化
theTime = 0.0;
//カメラの描写範囲(奥行)を0.1〜10000.0に設定する。
SetCameraNearFar(0.1f, 10000.0f);
//( 0.0, 9.0, -22.0 )の位置にカメラを設置し、視線を( 0.0, 10.0, 0.0 )にあるターゲットへ向ける。
VECTOR cameraPos = VGet(0.0f, 9.0f, -22.0f);
VECTOR theTarget = VGet(0.0f, 10.0f, 0.0f);
bool targeIsOrigin = false;
SetCameraPositionAndTarget_UpVecY(cameraPos, theTarget);
//Zバッファを使って図形描写を行う。
SetUseZBuffer3D(TRUE);
SetWriteZBuffer3D(TRUE);
// 繰り返し。
while (!ProcessMessage()){
// 描写先の画面(裏画面)を消去する。
ClearDrawScreen();
// 原点を囲むように、一辺が 100.f の白い立方体を描写する。
drawCube(VGet(0.0f, 0.0f, 0.0f), 200.0f);
// (5) 現在の再生時間をセットする
MV1SetAttachAnimTime(modelHandle1, attachIndex, theTime);
// (6) 3Dモデルの描画
MV1DrawModel(modelHandle_BG);
MV1DrawModel(modelHandle1);
// XZ平面を描写する。
drawXZPlane(100, 1.0, false);
// 座標軸を描写する。
draw3DAxisArrow(0.0f, 0.0f, 0.0f, 20.0f);
// カメラの座標を画面左下に表示する。
DrawFormatString(0, 460, GetColor(0, 0, 0), "%6.2f, %6.2f, %6.2f", cameraPos.x, cameraPos.y, cameraPos.z);
// 完成した裏画面の内容を表画面(ゲームのウィンドウ)に転写する。
ScreenFlip();
// キー(ゲームコントローラー)の状態を得る。
int keyInput = GetJoypadInputState(DX_INPUT_KEY_PAD1);
// カメラ(とターゲット)の位置を変更する
if (keyInput == PAD_INPUT_DOWN) {
cameraPos.z = cameraPos.z - 0.5; theTarget.z = theTarget.z - 0.5f;
}
if (keyInput == PAD_INPUT_UP) {
cameraPos.z = cameraPos.z + 0.5; theTarget.z = theTarget.z + 0.5f;
}
if (keyInput == PAD_INPUT_LEFT) {
cameraPos.x = cameraPos.x - 0.5; theTarget.x = theTarget.x - 0.5f;
}
if (keyInput == PAD_INPUT_RIGHT) {
cameraPos.x = cameraPos.x + 0.5; theTarget.x = theTarget.x + 0.5f;
}
char c = GetInputChar(TRUE);
if (c == 'u') {
cameraPos.y = cameraPos.y + 0.5f; theTarget.y = theTarget.y + 0.5f;
}
if (c == 'n') {
cameraPos.y = cameraPos.y - 0.5f; theTarget.y = theTarget.y - 0.5f;
}
if (c == 't') { // カメラのターゲットを標準位置にするか原点にするか切り替える。
targeIsOrigin = !targeIsOrigin;
}
// カメラの位置を設定しなおす。
if (targeIsOrigin) { // targeIsOrigin が true なら、カメラをターゲットに向ける。
SetCameraPositionAndTarget_UpVecY(cameraPos, VGet(0.0f, 0.0f, 0.0f));
}
else { // targeIsOrigin が false なら、カメラを標準位置に向ける。
SetCameraPositionAndTarget_UpVecY(cameraPos, theTarget);
}
// (7) 次の描写のためにゲーム内時間を更新する
theTime = theTime + 0.4;
// (8) ゲーム内時間がアニメーションの再生時間を超えたら再生時間をリセットする
if (theTime >= animTime000) theTime = 0.0;
}
DxLib_End(); // DXライブラリの後処理を行う.
return 0;
}

●座標変換を組み合わせた例

●提出課題 第15回(2024/01/19)課題 2024/01/26(金) 23:59 締切
List 2に処理を追加し,点A(2.0, 0.5, 0.0)を中心としてXY平面と平行な面の上で半径0.2の球を反時計回りに回転させるように表示せよ。なお,Aからこの球の中心までの距離は2.0とする。
球を描写するには,DXライブラリリファレンスページの3D関係関数のDrawSphere3D関数を使えば良い。
こちらのリンク先から提出せよ。締切は 2024/01/26(金) 23:59。
ヒント:
(0)まず,このサンプル1で,処理を書く場所を確認する(3箇所。1箇所目は必要な変数の宣言。2箇所目は球の描写。3箇所目は座標の変換)。
(1)次に,原点を中心に半径0.2の球を描写してみよう(サンプル2)。
(2)次に,以下の様な処理を書き直す。サンプル3は,処理1のX座標に関する処理と処理3のX座標に関する処理だけ記入済み。
処理1:回転の中心点を原点へ平行移動する(球の中心も同じ量だけ平行移動する)
処理2:原点を中心としてxy平面上で theta ラジアンだけ回転
処理3:回転の中心点を元の位置へ平行移動する(球の中心も同じ量だけ平行移動する)
