ワイヤーフレームの回転、透視変換(2点透視?)をやってみました。80本ほどの線なので簡単にぐりぐり動きます。今回、私としては初の構造体、動的メモリの確保とかを試しました。
環境等は
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;
}
以前からやってみたい透視変換のアニメーション(?)でした。公式についてよくわかっていないですが、まあ意図通り動かせたので結果オーライというところです。最後まで見ていただきありがとうございました。