サンプル3:座標変換処理を完成させよ。
sample3.cpp

#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){

	DxLib_Init();                    // DXライブラリを初期化する。
	ChangeWindowMode(TRUE);        // ゲーム画面をウィンドウで表示するように指定する。
	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);

	// ◆課題用コード1 (必要な変数の宣言)
	float rx = 2.0f, ry = 0.5f, rz = 0.0f; // 回転の中心
	float sx = rx + 2.0f, sy = ry, sz = rz; // 球体の中心座標
	float theta = 0.1f; // 繰り返し1回毎の回転角度

	// 繰り返し。
	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);

		// ◆課題用コード2(球の描写)
		DrawSphere3D(VGet(sx, sy, sz), 0.2f, 16, GetColor(255, 0, 0), GetColor(0, 0, 0), FALSE);

		// 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;

		// ◆課題用コード3 (座標変換処理)
		// 回転の中心点を原点へ平行移動する(球の中心も同じ量だけ平行移動する)
		// sx を -rx だけずらした txを求める。 sy を -ry だけずらした ty を求める。
		float tx = sx - rx;

		// 原点を中心としてxy平面上で theta ラジアンだけ回転
        // ここで,tx, ty を thetaラジアンだけ回転させた sx2, sy2 を求める。

		// 回転の中心点を元の位置へ平行移動する(球の中心も同じ量だけ平行移動する)
		// sx2 を rx だけずらした sx を求める。 sy2 を ry だけずらした sy を求める。
		sx = sx2 + rx;

	}

	DxLib_End(); // DXライブラリの後処理を行う.

	return 0;
}