0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

71歳の... ワイヤーフレームの回転と透視変換でアニメーションをやってみた

Posted at

 ワイヤーフレームの回転、透視変換(2点透視?)をやってみました。80本ほどの線なので簡単にぐりぐり動きます。今回、私としては初の構造体、動的メモリの確保とかを試しました。

WireFrame0.jpg

WireFrame1.jpg

環境等は

1.Windows 11 Pro
2.Visual Studio Community 2022
3.DXライブラリ使用 https://dxlib.xsrv.jp/index.html
4.「C言語による アルゴリズム入門(河西朝雄)」 
https://gihyo.jp/book/2008/978-4-7741-3618-9

4.の第8章グラフィックス Dr59 を参考にしました。VS、DxLibで意図通り動くように少し改変してあります。Y軸周りの回転、目の位置の上下、ズームイン・アウトを、キーやマウスボタンで操作できるようにしてみました。DXライブラリDxLibの使い方は、https://dxlib.xsrv.jp/use/dxuse_vscom2022.html
を参考に。
 コードを示します。

Win_Dr59.c
#define _USE_MATH_DEFINES
#include "DxLib.h"
#include <math.h>

typedef struct {
	int f;
	double x, y, z;
}Data;

Data a[]
={ 
	0,40,82,50, 1,40,97,50, 1,40,95,57, 1,40,95,47, 1,40,92,40, 1,40,98,40, 1,40,95,47, 1,40,95,40,

	0,0,0,0, 1,0,50,0, 1,80,50,0, 1,80,0,0, 1,0,0,0,
	0,5,5,0, 1,5,40,0, 1,25,40,0, 1,25,5,0, 1,5,5,0,
	0,10,25,0, 1,10,35,0, 1,20,35,0, 1,20,25,0, 1,10,25,0,
	0,0,0,100, 1,0,50,100, 1,80,50,100, 1,80,0,100, 1,0,0,100,

	0,0,0,0,  1,0,0,100,
	0,0,50,0, 1,0,50,100,
	0,80,50,0, 1,80,50,100,
	0,80,0,0, 1,80,0,100,

	0,80,30,25, 1,80,30,60, 1,80,40,60, 1,80,40,25,1,80,30,25,

	0,60,15,40, 1,60,15,70, 1,30,15,70, 1,30,15,40, 1,60,15,40,
	0,60,0,40,  1,60,15,40,
	0,60,0,70,  1,60,15,70,
	0,30,0,70,  1,30,15,70,
	0,30,0,40,  1,30,15,40,

	0,0,50,100, 1,40,82,100, 1,80,50,100,
	0,0,50,0, 1,40,82,0, 1,80,50,0,
	0,40,82,0, 1,40,82,100,

	0,50,74,100, 1,50,90,100, 1,65,90,100, 1,65,62,100,
	0,50,74,85,  1,50,90,85,  1,65,90,85,  1,65,62,85,
	0,50,74,100, 1,50,74,85,  1,65,62,85,
	0,50,90,85, 1,50,90,100,
	0,65,90,85, 1,65,90,100,
	0,65,62,85, 1,65,62,100,		-999,0,0,0 };

void Z_yR_Parse(
	double ay, // Rotation around y-Axis
	double x, double y, double z,
	double* px, double* py,
	double vp, double l, double m, double n )
{
	double h = (-x * sin(ay) + z * cos(ay) + n - vp) /(0 -  vp) ; // distance ratio in pojecting to x-y plane
	*px = (x * cos(ay) + z * sin(ay) + l) / h;	// x on screen at z=0
	*py = (y + m) / h;							// y on screen at z=0
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
	const int Width = 960, Height = 640, WHITE = GetColor(255, 255, 255);
	const int K = 3;		// 元データの拡大率
	const int WXC = Width / 2, WYC = Height / K + 100; // 表示基準位置
	const double RAD=M_PI / 180;
	bool au = false;
	const int H_X = 80 * K, H_Z = 100 * K, H_Y = 90 * K; // データ(家)の縦、横の長さ
	double vp = H_Z * 2;	// Eye position
	double l = 0.0, m = 0.0, n = 0.0; // x,y,z方向の平行移動量

	int a_size = sizeof a / sizeof a[0]; // データ数を知る
	Data *b;
	b = (Data*)malloc(a_size * sizeof(Data)); // 拡大データ格納用
	for (int i = 0; i < a_size;i++) { // 表示用にデータを拡大
		b[i].f = a[i].f;
		b[i].x = a[i].x * K; b[i].y = a[i].y * K; b[i].z = a[i].z * K;
	}

	SetWindowText("DxLib Sample. Home Wire Frame"); SetGraphMode(Width, Height, 32); ChangeWindowMode(TRUE);
	if (DxLib_Init() == -1) return -1;
	SetBackgroundColor(0, 0, 0); SetDrawScreen(DX_SCREEN_BACK);

	int beta = 15; // y軸周りの回転初期値
	double ay, bx, by, px=0.0, py=0.0;
	int dx=0, dy=0;
	while (1) {
		ClearDrawScreen();
		DrawFormatString(0, 0, WHITE, "%d°", beta);
		DrawFormatString(0, 16, WHITE, "(%d lines)", a_size);
		DrawFormatString(110, 0, GetColor(200, 0, 255), "[Mouse] L_Button  or R_Button Rotate  [SP]:Auto Right Rotate");
		DrawFormatString(110, 16, GetColor(200, 100, 200), "[up]:Eye Point Up   [down]:Eye Point Down");
		DrawFormatString(110, 32, GetColor(200, 200, 100), "[left]:Left translate   [right]:Right translate  [I]:Zoom In   [O]:Zoom Out");

		ay = beta * RAD;
		for (int k = 0;b[k].f != -999; k++) {
			Z_yR_Parse(ay, b[k].x - H_X / 2, b[k].y - 130, b[k].z - H_Z / 2, &px, &py, vp, l, m, n);
			if (a[k].f != 0) {
				DrawLine(bx + WXC + dx, WYC - by + m, px + WXC + dx , WYC - py + m, GetColor(255-8*k, 8*k, 128*4*k));
			}
			bx = px; by = py;
		}

		if (CheckHitKey(KEY_INPUT_LEFT)) dx = dx - 5;
		if (CheckHitKey(KEY_INPUT_RIGHT)) dx = dx + 5;
		if ((GetMouseInput() & MOUSE_INPUT_LEFT))beta = beta - 5;	// Left Rotation
		if ((GetMouseInput() & MOUSE_INPUT_RIGHT))beta = beta + 5;	// Right Rotation
		if (CheckHitKey(KEY_INPUT_SPACE)) au = !au;		// on/off for Right auto Rotation
		if (CheckHitKey(KEY_INPUT_I)) {
			vp = vp - 10;
			if (vp < H_Z + 30)vp = H_Z + 30;}	// Zoom In
		if (CheckHitKey(KEY_INPUT_O)) {
			vp = vp + 10;
			if (vp > H_Z * 3)vp = H_Z * 3;}		// Zoom Out
		if (CheckHitKey(KEY_INPUT_DOWN)) {
			m = m + 10;
			if (m > H_Y * 2)m = H_Y * 2;}		// Eye Point Up
		if (CheckHitKey(KEY_INPUT_UP)) {
			m = m - 10;
			if (m < -H_Y)m = -H_Y;}				// Eye Point Down

		if(au == true) beta++;
		if (beta > 359) beta = 0;
		else if (beta < 0)beta = 360;

		ScreenFlip();
		WaitTimer(66);
		if (ProcessMessage() == -1)break;
		if (CheckHitKey(KEY_INPUT_ESCAPE) == 1)break;
	}

	DxLib_End();
	return 0;
}

 以前からやってみたい透視変換のアニメーション(?)でした。公式についてよくわかっていないですが、まあ意図通り動かせたので結果オーライというところです。最後まで見ていただきありがとうございました。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?