|
|
2018/2/16(Fri) 10:54:54|NO.82471
CuteHSPには「#include」命令がないので、
例えば以下のような感じでサブルーチン化して出来ないかと。
p1=240 :p2=360 :p3=80 :gosub *d3m
stop
*d3m
;
; 〜 3D処理 〜
;
return
3D処理の部分が難し過ぎて自分にはできません。。
どなたか、動く一例書けませんか?
よろしくお願いします。
|
|
2018/2/16(Fri) 16:47:43|NO.82473
CuteHSPをインストールしていませんがこれですよね?
https://github.com/kikeroga3/tinyhsp
これだけしか命令や関数が使えない状況だと、
率直に言ってCuteHSPで3Dは無謀です。
基本はドット単位でGPUに処理をやってもらう(WindowsのDirectXの場合)のですが
それができない=DirectXが使えないので自前で全てやる事になるのですが、
ドット単位で描画処理するにもpget,psetだけでは処理時間がかかりすぎますし、
peek,pokeでVRAMに直接アクセスしようにもmrefが無いっぽいので無理です。
そもそも三角関数らしきものが一切無いのも厳しいんですが
ラインアート的な物でよければ、前に疑似3Dとしてやったことがあるので
そのソースを少々手直しした物を置いておきます。
不要な変数が複数ありますし、
モジュールも使えないようなので、gosub前後に変数設定が多数ありますが、
後半のモジュールだったものを見ていただくとなんとなくわかるかと思います。
初期値のspeedとvectorを変えると
速度や動く角度が変わりますので適当に数値を入れてみてください。
それと自前のsin値cos値の計算は精度が微妙なのでご了承ください。
// 疑似3D 左手座標系 カメラは原点、カメラベクトルは0, 0, 1(中心から奥を見る)で固定
// 各種初期値 本当は#define等で設定していた値
PI = 3.14159265358979 // 円周率
arg1 = 60.0; // 視野角
arg2 = 30.0; // 視野角(半分)
near = 100.0; // 近視距離
far = 500.0; // 遠視距離
scx = 640.0; // 画面サイズX
scy = 480.0; // 画面サイズY
intscx = 640; // 画面サイズX(int型)
intscy = 480; // 画面サイズY(int型)
schx = 320.0; // 画面サイズX(半分)
schy = 240.0; // 画面サイズY(半分)
intschx = 320; // 画面サイズX(int型半分)
intschy = 240; // 画面サイズY(int型半分)
nearY = tan(deg2rad(arg2)) * near * 2.0; // 近視距離における画面高(3D)
nearX = nearY * scx / scy; // 近視距離における画面幅(3D)
farY = tan(deg2rad(arg2)) * far * 2.0; // 遠視距離における画面高(3D)
farX = farY * scx / scy; // 遠視距離における画面幅(3D)
speed = 2.0; // 回転速度
arg = PI * speed / 180.0; // 回転角度をラジアンに変換
ddim vector, 3; // 回転軸ベクトルX, Y, Z
vector = 0.0, 1.0, 0.0;
ddim cbpc, 3; // 立方体中心座標X, Y, Z
ddim cbpx, 8; // 立方体頂点座標X
ddim cbpy, 8; // 立方体頂点座標Y
ddim cbpz, 8; // 立方体頂点座標Z
cbpc = 0.0, 0.0, 100.0;
cbpx = -50.0, 50.0, 50.0, -50.0, -50.0, 50.0, 50.0, -50.0; // 左上手前 右上手前 右上奥 左上奥 左下手前 右下手前 右下奥 左下奥
cbpy = 50.0, 50.0, 50.0, 50.0, -50.0, -50.0, -50.0, -50.0;
cbpz = 50.0, 50.0, 150.0, 150.0, 50.0, 50.0, 150.0, 150.0;
dim cbx, 8; // 平面座標に変換した立方体頂点座標X
dim cby, 8; // 平面座標に変換した立方体頂点座標Y
screen 0, intscx, intscy, 0;
*main
redraw 0;
color 0, 0, 0: boxf;
color 255, 255, 255;
gosub *calc_point;
gosub *draw_cube;
gosub *rotate_cube;
redraw 1;
await 17;
goto *main;
// 3Dから2Dへ座標変換
*calc_point
repeat 8
p1 = cbpx(cnt);
p2 = cbpy(cnt);
p3 = cbpz(cnt);
gosub *trans3Dto2D;
cbx(cnt) = dx;
cby(cnt) = dy;
loop
return;
// 立方体描画
*draw_cube
// 上面
line cbx(0), cby(0), cbx(1), cby(1);
line cbx(1), cby(1), cbx(2), cby(2);
line cbx(2), cby(2), cbx(3), cby(3);
line cbx(3), cby(3), cbx(0), cby(0);
// 下面
line cbx(4), cby(4), cbx(5), cby(5);
line cbx(5), cby(5), cbx(6), cby(6);
line cbx(6), cby(6), cbx(7), cby(7);
line cbx(7), cby(7), cbx(4), cby(4);
// 側面
line cbx(0), cby(0), cbx(4), cby(4);
line cbx(1), cby(1), cbx(5), cby(5);
line cbx(2), cby(2), cbx(6), cby(6);
line cbx(3), cby(3), cbx(7), cby(7);
return;
// 立方体回転
*rotate_cube
vx = vector(0);
vy = vector(1);
vz = vector(2);
cx = cbpc(0);
cy = cbpc(1);
cz = cbpc(2);
va = arg;
repeat 8
x0 = cbpx(cnt);
y0 = cbpy(cnt);
z0 = cbpz(cnt);
gosub *shift_rotate;
cbpx(cnt) = x1;
cbpy(cnt) = y1;
cbpz(cnt) = z1;
loop
return;
// 以下モジュール等だったもの
// 3D上の座標(p1,p2,p3)を2D上の座標(dx,dy)へ変換する
//#deffunc trans3Dto2D double p1, double p2, double p3, var dx, var dy
*trans3Dto2D
per = p3 / near; // 距離Zと近視距離の比率
dx = int( p1 / per + schx );
dy = int( -(p2 / per - schy) );
return;
// rotate 任意軸周りの空間回転演算 ( x0, y0, z0, vx, vy, vz, cx, cy, cz, va, x1, y1, z1)
// 入力値 x0 y0 z0, 回転軸ベクトル vx vy vz, 回転の中心座標 cx cy cz, 回転角度 va, 出力変数 x1 y1 z1
//#deffunc shift_rotate double x0, double y0, double z0, double vx, double vy, double vz, double cx, double cy, double cz, double va, var x1, var y1, var z1
*shift_rotate
// 座標の平行移動(回転の中心座標を原点に合わせる)
mpx = x0 - cx;
mpy = y0 - cy;
mpz = z0 - cz;
; 回転軸の単位ベクトル化
r = powf(vx*vx + vy*vy + vz*vz, 0.5);
ax = vx/r : ay = vy/r : az = vz/r;
; 回転演算
//sin1 = sin(va);
//cos1 = cos(va);
gosub *calc_sin;
gosub *calc_cos;
l_cos1 = 1.0 - cos1;
x1 = (ax*ax*l_cos1+cos1)*mpx + (ax*ay*l_cos1-az*sin1)*mpy + (az*ax*l_cos1+ay*sin1)*mpz;
y1 = (ax*ay*l_cos1+az*sin1)*mpx + (ay*ay*l_cos1+cos1)*mpy + (ay*az*l_cos1-ax*sin1)*mpz;
z1 = (az*ax*l_cos1-ay*sin1)*mpx + (ay*az*l_cos1+ax*sin1)*mpy + (az*az*l_cos1+cos1)*mpz;
// 座標の平行移動(ずらした分を戻す)
x1 += cx;
y1 += cy;
z1 += cz;
return
// 簡易テイラー展開によるsin値の算出
*calc_sin
x = va;
sin1 = x; // 計算結果が入る
p = x;
i = 1;
repeat 32
p *= -x*x / (2*i*(2*i+1));
sin1 += p;
i++;
loop
return;
// 簡易テイラー展開によるcos値の算出
*calc_cos
x = va;
cos1 = 1.0; // 計算結果が入る
p = 1.0;
i = 1;
repeat 32
p *= -x*x / ((2*i-1)*2*i);
cos1 += p;
i++;
loop
return

| |
|
2018/2/16(Fri) 17:02:48|NO.82474
おっと
sin,cosと平方根の計算はpowfで代用したのですが実装していただいたようですね。
以下訂正
ウェイトは間違えたっぽいのでawaitをwaitに変えてください。
うっかり忘れていましたが
tan等も使えない&使ってないので
nearY = tan(deg2rad(arg2)) * near * 2.0; // 近視距離における画面高(3D)
nearX = nearY * scx / scy; // 近視距離における画面幅(3D)
farY = tan(deg2rad(arg2)) * far * 2.0; // 遠視距離における画面高(3D)
farX = farY * scx / scy; // 遠視距離における画面幅(3D)
この4行は削除してください。
|
|
2018/2/16(Fri) 17:56:29|NO.82475
> dolphiliaさん
> あまらさん
ありがとうございます!回答、早っ!!
回答があったとしてもチャレンジングで力技になりそうな予想はしてましたが、
それにしても、いくらなんでも、お二人の対応が早すぎて感動を禁じえません。。
あまらさんのソースを、ご指摘の箇所と、文法エラーが多少でたので直したら
けっこうな速度ですぐに動きました。
↓CuteHSPで動作する修正版
; 疑似3D 左手座標系 カメラは原点、カメラベクトルは0, 0, 1(中心から奥を見る)で固定
; 各種初期値 本当は#define等で設定していた値
PI = 3.14159265358979 ; 円周率
arg1 = 60.0; ; 視野角
arg2 = 30.0; ; 視野角(半分)
near = 100.0; ; 近視距離
far = 500.0; ; 遠視距離
scx = 640.0; ; 画面サイズX
scy = 480.0; ; 画面サイズY
intscx = 640; ; 画面サイズX(int型)
intscy = 480; ; 画面サイズY(int型)
schx = 320.0; ; 画面サイズX(半分)
schy = 240.0; ; 画面サイズY(半分)
intschx = 320; ; 画面サイズX(int型半分)
intschy = 240; ; 画面サイズY(int型半分)
speed = 2.0; ; 回転速度
arg = PI * speed / 180.0; ; 回転角度をラジアンに変換
ddim vector, 3; ; 回転軸ベクトルX, Y, Z
vector(0) = 0.0;
vector(1) = 1.0;
vector(2) = 0.0;
ddim cbpc, 3; ; 立方体中心座標X, Y, Z
ddim cbpx, 8; ; 立方体頂点座標X
ddim cbpy, 8; ; 立方体頂点座標Y
ddim cbpz, 8; ; 立方体頂点座標Z
cbpc(0) = 0.0;
cbpc(1) = 0.0;
cbpc(2) = 100.0;
cbpx(0) = -50.0; ; 左上手前 右上手前 右上奥 左上奥 左下手前 右下手前 右下奥 左下奥
cbpx(1) = 50.0;
cbpx(2) = 50.0;
cbpx(3) = -50.0;
cbpx(4) = -50.0;
cbpx(5) = 50.0;
cbpx(6) = 50.0;
cbpx(7) = -50.0;
cbpy(0) = 50.0;
cbpy(1) = 50.0;
cbpy(2) = 50.0;
cbpy(3) = 50.0;
cbpy(4) = -50.0;
cbpy(5) = -50.0;
cbpy(6) = -50.0;
cbpy(7) = -50.0;
cbpz(0) = 50.0;
cbpz(1) = 50.0;
cbpz(2) = 150.0;
cbpz(3) = 150.0;
cbpz(4) = 50.0;
cbpz(5) = 50.0;
cbpz(6) = 150.0;
cbpz(7) = 150.0;
dim cbx, 8; ; 平面座標に変換した立方体頂点座標X
dim cby, 8; ; 平面座標に変換した立方体頂点座標Y
; screen 0, intscx, intscy, 0;
*main
redraw 0;
color 0, 0, 0: boxf 0,0,640,480;
color 255, 255, 255;
gosub *calc_point;
gosub *draw_cube;
gosub *rotate_cube;
redraw 1;
wait 1;
goto *main;
; 3Dから2Dへ座標変換
*calc_point
repeat 8
p1 = cbpx(cnt);
p2 = cbpy(cnt);
p3 = cbpz(cnt);
gosub *trans3Dto2D;
cbx(cnt) = dx;
cby(cnt) = dy;
loop
return;
; 立方体描画
*draw_cube
; 上面
line cbx(0), cby(0), cbx(1), cby(1);
line cbx(1), cby(1), cbx(2), cby(2);
line cbx(2), cby(2), cbx(3), cby(3);
line cbx(3), cby(3), cbx(0), cby(0);
; 下面
line cbx(4), cby(4), cbx(5), cby(5);
line cbx(5), cby(5), cbx(6), cby(6);
line cbx(6), cby(6), cbx(7), cby(7);
line cbx(7), cby(7), cbx(4), cby(4);
; 側面
line cbx(0), cby(0), cbx(4), cby(4);
line cbx(1), cby(1), cbx(5), cby(5);
line cbx(2), cby(2), cbx(6), cby(6);
line cbx(3), cby(3), cbx(7), cby(7);
return;
; 立方体回転
*rotate_cube
vx = vector(0);
vy = vector(1);
vz = vector(2);
cx = cbpc(0);
cy = cbpc(1);
cz = cbpc(2);
va = arg;
repeat 8
x0 = cbpx(cnt);
y0 = cbpy(cnt);
z0 = cbpz(cnt);
gosub *shift_rotate;
cbpx(cnt) = x1;
cbpy(cnt) = y1;
cbpz(cnt) = z1;
loop
return;
; 以下モジュール等だったもの
; 3D上の座標(p1,p2,p3)を2D上の座標(dx,dy)へ変換する
;#deffunc trans3Dto2D double p1, double p2, double p3, var dx, var dy
*trans3Dto2D
per = p3 / near; ; 距離Zと近視距離の比率
dx = int( p1 / per + schx );
dy = int( -(p2 / per - schy) );
return;
; rotate 任意軸周りの空間回転演算 ( x0, y0, z0, vx, vy, vz, cx, cy, cz, va, x1, y1, z1)
; 入力値 x0 y0 z0, 回転軸ベクトル vx vy vz, 回転の中心座標 cx cy cz, 回転角度 va, 出力変数 x1 y1 z1
;#deffunc shift_rotate double x0, double y0, double z0, double vx, double vy, double vz, double cx, double cy, double cz, double va, var x1, var y1, var z1
*shift_rotate
; 座標の平行移動(回転の中心座標を原点に合わせる)
mpx = x0 - cx;
mpy = y0 - cy;
mpz = z0 - cz;
; 回転軸の単位ベクトル化
r = powf(vx*vx + vy*vy + vz*vz, 0.5);
ax = vx/r : ay = vy/r : az = vz/r;
; 回転演算
;sin1 = sin(va);
;cos1 = cos(va);
gosub *calc_sin;
gosub *calc_cos;
l_cos1 = 1.0 - cos1;
x1 = (ax*ax*l_cos1+cos1)*mpx + (ax*ay*l_cos1-az*sin1)*mpy + (az*ax*l_cos1+ay*sin1)*mpz;
y1 = (ax*ay*l_cos1+az*sin1)*mpx + (ay*ay*l_cos1+cos1)*mpy + (ay*az*l_cos1-ax*sin1)*mpz;
z1 = (az*ax*l_cos1-ay*sin1)*mpx + (ay*az*l_cos1+ax*sin1)*mpy + (az*az*l_cos1+cos1)*mpz;
; 座標の平行移動(ずらした分を戻す)
x1 = x1 + cx;
y1 = y1 + cy;
z1 = z1 + cz;
return
; 簡易テイラー展開によるsin値の算出
*calc_sin
x = va;
sin1 = x; ; 計算結果が入る
p = x;
i = 1;
repeat 32
p = p * (-x*x / (2*i*(2*i+1)));
sin1 = sin1 + p;
i = i + 1;
loop
return;
; 簡易テイラー展開によるcos値の算出
*calc_cos
x = va;
cos1 = 1.0; ; 計算結果が入る
p = 1.0;
i = 1;
repeat 32
p = p * (-x*x / ((2*i-1)*2*i));
cos1 = cos1 + p;
i = i + 1;
loop
return
命令追加の改造版CuteHSPでの実行はまだ試してないのですが、そちらで動かすともっと処理速度アップするんですかね?

| |
|
2018/2/16(Fri) 18:20:49|NO.82477
あー//だとコメントにならないんですね
> ありがとうございます!回答、早っ!!
元々あったものを少し修正しただけなので^^;
> 命令追加の改造版CuteHSPでの実行はまだ試してないのですが、そちらで動かすともっと処理速度アップするんですかね?
速いのはwait値が小さいからというのもありそうですが、可能性はありますね。
なにより三角関数の精度が上がるので変更するのをお勧めします。
形状が単純なのでlineで12本線を描いてるだけというのと、
奥行による明度の変化とか光源とかが全く考慮されていないというのも早さの理由ですね。
立方体の面にグラデーションで色を付けられるともっと立体感が出ると思うのですが、
処理速度的に無理ですね……。
追加版に変更する場合には下記の箇所を
; rotate 任意軸周りの空間回転演算 ( x0, y0, z0, vx, vy, vz, cx, cy, cz, va, x1, y1, z1)
; 入力値 x0 y0 z0, 回転軸ベクトル vx vy vz, 回転の中心座標 cx cy cz, 回転角度 va, 出力変数 x1 y1 z1
;#deffunc shift_rotate double x0, double y0, double z0, double vx, double vy, double vz, double cx, double cy, double cz, double va, var x1, var y1, var z1
*shift_rotate
; 座標の平行移動(回転の中心座標を原点に合わせる)
mpx = x0 - cx;
mpy = y0 - cy;
mpz = z0 - cz;
; 回転軸の単位ベクトル化
r = powf(vx*vx + vy*vy + vz*vz, 0.5);
ax = vx/r : ay = vy/r : az = vz/r;
; 回転演算
;sin1 = sin(va);
;cos1 = cos(va);
gosub *calc_sin;
gosub *calc_cos;
l_cos1 = 1.0 - cos1;
x1 = (ax*ax*l_cos1+cos1)*mpx + (ax*ay*l_cos1-az*sin1)*mpy + (az*ax*l_cos1+ay*sin1)*mpz;
y1 = (ax*ay*l_cos1+az*sin1)*mpx + (ay*ay*l_cos1+cos1)*mpy + (ay*az*l_cos1-ax*sin1)*mpz;
z1 = (az*ax*l_cos1-ay*sin1)*mpx + (ay*az*l_cos1+ax*sin1)*mpy + (az*az*l_cos1+cos1)*mpz;
; 座標の平行移動(ずらした分を戻す)
x1 = x1 + cx;
y1 = y1 + cy;
z1 = z1 + cz;
return
こちらに修正してみてください。
; rotate 任意軸周りの空間回転演算 ( x0, y0, z0, vx, vy, vz, cx, cy, cz, va, x1, y1, z1)
; 入力値 x0 y0 z0, 回転軸ベクトル vx vy vz, 回転の中心座標 cx cy cz, 回転角度 va, 出力変数 x1 y1 z1
;#deffunc shift_rotate double x0, double y0, double z0, double vx, double vy, double vz, double cx, double cy, double cz, double va, var x1, var y1, var z1
*shift_rotate
; 座標の平行移動(回転の中心座標を原点に合わせる)
mpx = x0 - cx;
mpy = y0 - cy;
mpz = z0 - cz;
; 回転軸の単位ベクトル化
;r = powf(vx*vx + vy*vy + vz*vz, 0.5);
r = sqrt(vx*vx + vy*vy + vz*vz);
ax = vx/r : ay = vy/r : az = vz/r;
; 回転演算
sin1 = sin(va);
cos1 = cos(va);
;gosub *calc_sin;
;gosub *calc_cos;
l_cos1 = 1.0 - cos1;
x1 = (ax*ax*l_cos1+cos1)*mpx + (ax*ay*l_cos1-az*sin1)*mpy + (az*ax*l_cos1+ay*sin1)*mpz;
y1 = (ax*ay*l_cos1+az*sin1)*mpx + (ay*ay*l_cos1+cos1)*mpy + (ay*az*l_cos1-ax*sin1)*mpz;
z1 = (az*ax*l_cos1-ay*sin1)*mpx + (ay*az*l_cos1+ax*sin1)*mpy + (az*az*l_cos1+cos1)*mpz;
; 座標の平行移動(ずらした分を戻す)
x1 = x1 + cx;
y1 = y1 + cy;
z1 = z1 + cz;
return
そしてこれらは不要になりますね。
; 簡易テイラー展開によるsin値の算出
*calc_sin
x = va;
sin1 = x; ; 計算結果が入る
p = x;
i = 1;
repeat 32
p = p * (-x*x / (2*i*(2*i+1)));
sin1 = sin1 + p;
i = i + 1;
loop
return;
; 簡易テイラー展開によるcos値の算出
*calc_cos
x = va;
cos1 = 1.0; ; 計算結果が入る
p = 1.0;
i = 1;
repeat 32
p = p * (-x*x / ((2*i-1)*2*i));
cos1 = cos1 + p;
i = i + 1;
loop
return

| |
|
2018/2/17(Sat) 00:17:50|NO.82484
素晴らしい。
あまらさんの変更を反映して改造版CuteHSPで試してみましたが立方体が回転しませんでした。
簡易テイラー展開サブルーチン版は改造版CuteHSPでも立方体は回転します。
> dolphiliaさん
何となくですがsin、cos関数が実数を返していないような気がします。
サブルーチン *calc_sin、*calc_cos では sin1には0.0348、cos1には0.9993が返ってますが
改造版のsin、cos関数では sin1には0、cos1には1が返ってます。
しかし、素晴らしい。JELDAぐらいなら作れちゃうような気がしてきました。
|
|
2018/2/17(Sat) 01:10:30|NO.82486
> 何となくですがsin、cos関数が実数を返していないような気がします。
それは残念ですね、返り値からして角度0になってるというのは
もしかして角度をラジアンで渡したのがまずかったでしょうか?
とりあえず修正(?)されるまでの繋ぎとしてsin,cosの精度を上げた物を作っておきました。
少ししか変更してないんですが、repeatにマイナス値を渡して
無限ループになるかわからないので出来なかったら申し訳ありません。
; 簡易テイラー展開によるsin値の算出
*calc_sin
x = va;
sin1 = x; 計算結果が入る
p = x;
i = 1;
repeat -1
p = p * (-x*x / (2*i*(2*i+1)));
sin1 = sin1 + p;
i = i + 1;
;absが実数で使えるか不明の為、if,elseで代用
if(p2<0):p2 = -p: else:p2 = p;
if(p2<=0.000000000000001):break;
loop
return;
; 簡易テイラー展開によるcos値の算出
*calc_cos
x = va;
cos1 = 1.0; 計算結果が入る
p = 1.0;
i = 1;
repeat -1
p = p * (-x*x / ((2*i-1)*2*i));
cos1 = cos1 + p;
i = i + 1;
;absが実数で使えるか不明の為、if,elseで代用
if(p2<0):p2 = -p: else:p2 = p;
if(p2<=0.000000000000001):break;
loop
return
今更気づいたのですが*=,+=,++などが使えないのは地味に不便ですね。
たしかに最小限の機能と言えるかもしれませんが……。
|
|
2018/2/18(Sun) 17:04:28|NO.82507
すみません。
3D座標と2D座標を変換する箇所なんですが、
手抜きだったため距離による歪みが大きすぎるのが気になりまして修正致しました。
それと修正中に気がついたのですが、
修正前・修正後のどちらもZ値が0.0だと0で除算となりエラーになってしまうので
0.0のときは1.0として扱う事にしました。
修正に伴い計算に必要な変数が増え、
いくつかの変数(near,farと立方体頂点座標のZ値)の数値も変わっています。
そしておまけで
vector値(回転軸)も変えています。
0.0, 1.0, 0.0はただのY軸回転と同じで
作業中に見飽きたので、XYZ全ての向きに回ってもらいました。
; 疑似3D 左手座標系 カメラは原点、カメラベクトルは0, 0, 1(中心から奥を見る)で固定
; 各種初期値 本当は#define等で設定していた値
PI = 3.14159265358979323846; 円周率
arg1 = 60.0; ; 視野角
arg2 = 30.0; ; 視野角(半分)
argp = PI * arg2 / 180.0; arg2をラジアンに変換
tanp = sin(argp) / cos(argp); 射影変換行列用tan値
near = 10.0; ; 近視距離
far = 1000.0; ; 遠視距離
fmn = far-near; 遠視距離と近視距離の差
scx = 640.0; ; 画面サイズX
scy = 480.0; ; 画面サイズY
intscx = 640; ; 画面サイズX(int型)
intscy = 480; ; 画面サイズY(int型)
schx = 320.0; ; 画面サイズX(半分)
schy = 240.0; ; 画面サイズY(半分)
intschx = 320; ; 画面サイズX(int型半分)
intschy = 240; ; 画面サイズY(int型半分)
speed = 2.0; ; 回転速度(という名の1フレーム当たりの回転角度)
arg = PI * speed / 180.0; ; 回転角度をラジアンに変換
; 0.0, 1.0, 0.0 はただのY軸回転
ddim vector, 3; ; 回転軸ベクトルX, Y, Z
vector(0) = 0.3;
vector(1) = 0.6;
vector(2) = 0.9;
ddim cbpc, 3; ; 立方体中心座標X, Y, Z
ddim cbpx, 8; ; 立方体頂点座標X
ddim cbpy, 8; ; 立方体頂点座標Y
ddim cbpz, 8; ; 立方体頂点座標Z
cbpc(0) = 0.0;
cbpc(1) = 0.0;
cbpc(2) = 200.0;
cbpx(0) = -50.0; ; 左上手前 右上手前 右上奥 左上奥 左下手前 右下手前 右下奥 左下奥
cbpx(1) = 50.0;
cbpx(2) = 50.0;
cbpx(3) = -50.0;
cbpx(4) = -50.0;
cbpx(5) = 50.0;
cbpx(6) = 50.0;
cbpx(7) = -50.0;
cbpy(0) = 50.0;
cbpy(1) = 50.0;
cbpy(2) = 50.0;
cbpy(3) = 50.0;
cbpy(4) = -50.0;
cbpy(5) = -50.0;
cbpy(6) = -50.0;
cbpy(7) = -50.0;
cbpz(0) = 150.0;
cbpz(1) = 150.0;
cbpz(2) = 250.0;
cbpz(3) = 250.0;
cbpz(4) = 150.0;
cbpz(5) = 150.0;
cbpz(6) = 250.0;
cbpz(7) = 250.0;
dim cbx, 8; ; 平面座標に変換した立方体頂点座標X
dim cby, 8; ; 平面座標に変換した立方体頂点座標Y
; screen 0, intscx, intscy, 0;
*main
redraw 0;
color 0, 0, 0: boxf 0,0,640,480;
color 255, 255, 255;
gosub *calc_point;
gosub *draw_cube;
gosub *rotate_cube;
redraw 1;
wait 1;
goto *main;
; 3Dから2Dへ座標変換
*calc_point
repeat 8
p1 = cbpx(cnt);
p2 = cbpy(cnt);
p3 = cbpz(cnt);
gosub *trans3Dto2D;
cbx(cnt) = dx;
cby(cnt) = dy;
loop
return;
; 立方体描画
*draw_cube
; 上面
line cbx(0), cby(0), cbx(1), cby(1);
line cbx(1), cby(1), cbx(2), cby(2);
line cbx(2), cby(2), cbx(3), cby(3);
line cbx(3), cby(3), cbx(0), cby(0);
; 下面
line cbx(4), cby(4), cbx(5), cby(5);
line cbx(5), cby(5), cbx(6), cby(6);
line cbx(6), cby(6), cbx(7), cby(7);
line cbx(7), cby(7), cbx(4), cby(4);
; 側面
line cbx(0), cby(0), cbx(4), cby(4);
line cbx(1), cby(1), cbx(5), cby(5);
line cbx(2), cby(2), cbx(6), cby(6);
line cbx(3), cby(3), cbx(7), cby(7);
return;
; 立方体回転
*rotate_cube
vx = vector(0);
vy = vector(1);
vz = vector(2);
cx = cbpc(0);
cy = cbpc(1);
cz = cbpc(2);
va = arg;
repeat 8
x0 = cbpx(cnt);
y0 = cbpy(cnt);
z0 = cbpz(cnt);
gosub *shift_rotate;
cbpx(cnt) = x1;
cbpy(cnt) = y1;
cbpz(cnt) = z1;
loop
return;
; 以下モジュール等だったもの
; 3D上の座標(p1,p2,p3)を2D上の座標(dx,dy)へ変換する
;#deffunc trans3Dto2D double p1, double p2, double p3, var dx, var dy
*trans3Dto2D
; 0除算回避のため、Z値が0.0のときは1.0にする
if(p3==0.0):p3 = 1.0;
; 座標*射影行列*ビューポート行列を一括で行う(ワールド行列とビュー行列は固定値のため省略)
dx1 = schx*p1*scy/(scx*tanp) + p3*schx;
dy1 = -schy*p2/tanp + p3*schy;
dz1 = p3*far/fmn -(near*far)/fmn;
dw1 = p3;
dx = int(dx1 / dw1);
dy = int(dy1 / dw1);
return;
; rotate 任意軸周りの空間回転演算 ( x0, y0, z0, vx, vy, vz, cx, cy, cz, va, x1, y1, z1)
; 入力値 x0 y0 z0, 回転軸ベクトル vx vy vz, 回転の中心座標 cx cy cz, 回転角度 va, 出力変数 x1 y1 z1
;#deffunc shift_rotate double x0, double y0, double z0, double vx, double vy, double vz, double cx, double cy, double cz, double va, var x1, var y1, var z1
*shift_rotate
; 座標の平行移動(回転の中心座標を原点に合わせる)
mpx = x0 - cx;
mpy = y0 - cy;
mpz = z0 - cz;
; 回転軸の単位ベクトル化
;r = powf(vx*vx + vy*vy + vz*vz, 0.5);
r = sqrt(vx*vx + vy*vy + vz*vz);
ax = vx/r : ay = vy/r : az = vz/r;
; 回転演算
sin1 = sin(va);
cos1 = cos(va);
;gosub *calc_sin;
;gosub *calc_cos;
l_cos1 = 1.0 - cos1;
x1 = (ax*ax*l_cos1+cos1)*mpx + (ax*ay*l_cos1-az*sin1)*mpy + (az*ax*l_cos1+ay*sin1)*mpz;
y1 = (ax*ay*l_cos1+az*sin1)*mpx + (ay*ay*l_cos1+cos1)*mpy + (ay*az*l_cos1-ax*sin1)*mpz;
z1 = (az*ax*l_cos1-ay*sin1)*mpx + (ay*az*l_cos1+ax*sin1)*mpy + (az*az*l_cos1+cos1)*mpz;
; 座標の平行移動(ずらした分を戻す)
x1 = x1 + cx;
y1 = y1 + cy;
z1 = z1 + cz;
return;
これを投降するのは2度目ですが、
int値の2D座標をdouble値で返すなんていう凡ミスがあったので
前の投稿は削除しミスした箇所を修正した上で投降し直しました。
HSPだとdoubleでline命令をやってもそのまま実行できるので気づきませんでした。

| |
|
2018/2/18(Sun) 17:25:14|NO.82509
> 距離による歪み
あのパースはわざとなのかと思ってました(^^;
バッチリ動いております!
https://youtu.be/uLyqVMl7S8Y
おかげさまでCuteHSPでワイヤーフレームのゲームでも作ってみようかという気持ちが沸いてきました(^^)/
あまらさんのソース大変参考になります。
|
|
2018/2/19(Mon) 10:44:06|NO.82514
CuteHSPでもワイヤーフレーム程度であれば十分実用速度で動くようですね。
思いがけずCuteHSPの機能拡張(関数追加)までしていただいてしまい恐縮ですが、
簡易テイラー展開によるサブルーチン版でも十分な速度で動いているようです。
実用に耐えない遅さになるかもと思ってもいたので、あらためてそのポテンシャルに感心してしまいました。
皆様、ありがとうございましたm(_ _)m
|
|
2018/2/21(Wed) 20:15:22|NO.82523
あまらさんの素晴らしいソースを参考に
マジでCuteHSPでワイヤーフレームのゲームでも作ってみようかとトライ中なのですが
以下"d3obj.bin"に3Dオブジェクトの形状データ(x,y,z,link...)をもたせて
回転処理をさせてみましたところ微妙な動き…何かが間違ってるような…(^^;
でも動いてるので見ていただいて何か指摘してもらおうかと思い、コメントしました。
※形状データは中心を(0,0,0)としてx,y,zの値を-128〜127の値でもつようにしています。
4番目のlink値は1なら開始点、2なら線を連携、3ならデータエンドの意味にしています。
実行動画
https://youtu.be/N8dzj_N27ho
ソース
https://github.com/kikeroga3/Random-Quest/blob/master/junk/cutehsp_d3s2.zip
ちなみにCuteHSPのコードは本家HSPでもそのまま動きますです。念の為。
; 疑似3D 左手座標系 カメラは原点、カメラベクトルは0,0,1(中心から奥を見る)で固定
sdim bf,65000
bload "d3obj.bin",bf
; 各種初期値
PI=3.14159265358979323846 ; 円周率
argp=PI*30.0/180.0 ; 視野角(半分)をラジアンに変換
tanp=sin(argp)/cos(argp) ; 射影変換行列用tan値
near=10.0 :far=1000.0 ; 近視距離、遠視距離
fmn=far-near ; 遠視距離と近視距離の差
scx=640.0 :scy=480.0 ; 画面サイズXY
schx=320.0 :schy=240.0 ; 画面サイズXY(半分)
; 3Dオブジェクトの位置
ox=0.0 :oy=0.0 :oz=200.0
*main
redraw 0
color 0,0,0: boxf 0,0,640,480
color 255,255,255
gosub *obj_draw
redraw 1 :wait 1
ang = ang + 2.0
if ang > 360.0 :ang = 0.0
goto *main
*obj_draw
vx = 0.3
vy = 0.6
vz = 0.9
va = PI*ang/180.0 ; 回転角度をラジアンに変換
n=1 :i=0
*rep
; 形状データ取得
mpx=double(peek(bf,i)-128)
mpy=double(peek(bf,i+1)-128)
mpz=double(peek(bf,i+2)-128)
gosub *shift_rotate
p1=x1+ox :p2=y1+oy :p3=z1+oz
gosub *trans3Dto2D :xx2=dx :yy2=dy
if n>1 {
if n=3 :return
line xx1,yy1,xx2,yy2
}
n=peek(bf,i+3)
xx1=xx2 :yy1=yy2 :i=i+4
goto *rep
; 以下モジュール等だったもの
; 3D上の座標(p1,p2,p3)を2D上の座標(dx,dy)へ変換する
*trans3Dto2D
; 0除算回避のため、Z値が0.0のときは1.0にする
if(p3==0.0):p3 = 1.0
; 座標*射影行列*ビューポート行列を一括で行う(ワールド行列とビュー行列は固定値のため省略)
dx1 = schx*p1*scy/(scx*tanp) + p3*schx
dy1 = -schy*p2/tanp + p3*schy
dz1 = p3*far/fmn -(near*far)/fmn
dw1 = p3
dx = int(dx1 / dw1)
dy = int(dy1 / dw1)
return
; rotate 任意軸周りの空間回転演算 ( x0, y0, z0, vx, vy, vz, cx, cy, cz, va, x1, y1, z1)
; 入力値 mpx mpy mpz, 回転軸ベクトル vx vy vz, 回転角度 va, 出力変数 x1 y1 z1
*shift_rotate
; 回転軸の単位ベクトル化
r = sqrt(vx*vx + vy*vy + vz*vz)
ax = vx/r : ay = vy/r : az = vz/r
; 回転演算
sin1 = sin(va)
cos1 = cos(va)
l_cos1 = 1.0 - cos1
x1 = (ax*ax*l_cos1+cos1)*mpx + (ax*ay*l_cos1-az*sin1)*mpy + (az*ax*l_cos1+ay*sin1)*mpz
y1 = (ax*ay*l_cos1+az*sin1)*mpx + (ay*ay*l_cos1+cos1)*mpy + (ay*az*l_cos1-ax*sin1)*mpz
z1 = (az*ax*l_cos1-ay*sin1)*mpx + (ay*az*l_cos1+ax*sin1)*mpy + (az*az*l_cos1+cos1)*mpz
return

| |
|
2018/2/22(Thu) 08:04:50|NO.82530
> kikerogaさん
とりあえずこのスレッドは解決済みですし、
スレッドを作ったNyankrouさんの質問とは微妙に違うので
新しくスレッド作った方がいいのでは?と思いました。
発言の半分近くを占めた私が言うのも「お前が言うな」と思われそうですが。。。
私がスレッドを作るのも何か違う気がするので
今回はここで回答させていただきます。
どういう旋回をしたいのかわかりませんが、
こういう回り方でしょうか?
; 疑似3D 左手座標系 カメラは原点、カメラベクトルは0,0,1(中心から奥を見る)で固定
sdim bf,65000
bload "d3obj.bin",bf
; 各種初期値
PI=3.14159265358979323846 ; 円周率
argp=PI*30.0/180.0 ; 視野角(半分)をラジアンに変換
tanp=sin(argp)/cos(argp) ; 射影変換行列用tan値
near=10.0 :far=1000.0 ; 近視距離、遠視距離
fmn=far-near ; 遠視距離と近視距離の差
scx=640.0 :scy=480.0 ; 画面サイズXY
schx=320.0 :schy=240.0 ; 画面サイズXY(半分)
ang = 0.0 ; double型で初期化
; 3Dオブジェクトの位置
ox=-100.0 :oy=0.0 :oz=200.0
*main
redraw 0
color 0,0,0: boxf 0,0,640,480
color 255,255,255
gosub *obj_draw
redraw 1 :wait 1
ang = (ang + 0.5) \ 360.0
;if ang > 360.0 :ang = 0.0
goto *main
*obj_draw
vx = 0.0
vy = 0.0
vz = 1.0
va = PI*ang/180.0 ; 回転角度をラジアンに変換
n=1 :i=0
*rep
; 形状データ取得
mpx=double(peek(bf,i)-128)+ox
mpy=double(peek(bf,i+1)-128)+oy
mpz=double(peek(bf,i+2)-128)+oz
gosub *shift_rotate
p1=x1 :p2=y1 :p3=z1
gosub *trans3Dto2D :xx2=dx :yy2=dy
if n>1 {
if n=3 :return
line xx1,yy1,xx2,yy2
}
n=peek(bf,i+3)
xx1=xx2 :yy1=yy2 :i=i+4
goto *rep
; 以下モジュール等だったもの
return;
; 3D上の座標(p1,p2,p3)を2D上の座標(dx,dy)へ変換する
*trans3Dto2D
; 0除算回避のため、Z値が0.0のときは1.0にする
if(p3==0.0):p3 = 1.0
; 座標*射影行列*ビューポート行列を一括で行う(ワールド行列とビュー行列は固定値のため省略)
dx1 = (schx*p1*scy + p3*schx*scx*tanp) / (scx*tanp)
dy1 = (p3*schy*tanp - schy*p2) / tanp
dx = int(dx1 / p3)
dy = int(dy1 / p3)
return
; rotate 任意軸周りの空間回転演算 ( x0, y0, z0, vx, vy, vz, cx, cy, cz, va, x1, y1, z1)
; 入力値 mpx mpy mpz, 回転軸ベクトル vx vy vz, 回転角度 va, 出力変数 x1 y1 z1
*shift_rotate
; 回転軸の単位ベクトル化
r = sqrt(vx*vx + vy*vy + vz*vz)
ax = vx/r : ay = vy/r : az = vz/r
; 回転演算
sin1 = sin(va)
cos1 = cos(va)
l_cos1 = 1.0 - cos1
x1 = (ax*ax*l_cos1+cos1)*mpx + (ax*ay*l_cos1-az*sin1)*mpy + (az*ax*l_cos1+ay*sin1)*mpz
y1 = (ax*ay*l_cos1+az*sin1)*mpx + (ay*ay*l_cos1+cos1)*mpy + (ay*az*l_cos1-ax*sin1)*mpz
z1 = (az*ax*l_cos1-ay*sin1)*mpx + (ay*az*l_cos1+ax*sin1)*mpy + (az*az*l_cos1+cos1)*mpz
return
付け足したり変更した箇所は
ang = 0.0 ; double型で初期化(ang+0.5などにするとint型のままになりang値が0で固定されてしまうため)
; 3Dオブジェクトの位置
ox=-100.0 :oy=0.0 :oz=200.0 ; X座標の変更
〜省略〜
ang = (ang + 1.0) \ 360.0 ; こうすると360を超えない&2.0だと速すぎる為1.0に変更
;if ang > 360.0 :ang = 0.0 ; 上記の行により不要
〜省略〜
vx = 0.0 ; Z軸回転にする
vy = 0.0
vz = 1.0
〜省略〜
*rep
; 形状データ取得 この時点で位置を変更しておく
mpx=double(peek(bf,i)-128)+ox
mpy=double(peek(bf,i+1)-128)+oy
mpz=double(peek(bf,i+2)-128)+oz
gosub *shift_rotate
p1=x1 :p2=y1 :p3=z1 ; 上記の変更により、ここでの加算は必要なし
gosub *trans3Dto2D :xx2=dx :yy2=dy
〜省略〜
; 3D上の座標(p1,p2,p3)を2D上の座標(dx,dy)へ変換する
*trans3Dto2D
; 0除算回避のため、Z値が0.0のときは1.0にする
if(p3==0.0):p3 = 1.0
; 座標*射影行列*ビューポート行列を一括で行う(ワールド行列とビュー行列は固定値のため省略)
dx1 = (schx*p1*scy + p3*schx*scx*tanp) / (scx*tanp)
dy1 = (p3*schy*tanp - schy*p2) / tanp
dx = int(dx1 / p3)
dy = int(dy1 / p3)
return
*trans3Dto2Dではdz1とdw1が無意味だったので削除したのと、
(座標変換の計算でX,Y,Z,Wの4つが必要だったけど、
ZとWは計算の後では使わない。というか自分でもなぜ残してたのかわからない)
dx1とdy1は除算を最後にしてできるだけ誤差を減らしてみました。
以上です。

| |
|
2018/2/22(Thu) 09:44:17|NO.82531
> あまらさん、Kikerogaさん
有意義な情報を展開していただき、有難いです。
確かに内容が深く具体的になってきたような気もするので
新しくスレッド作った方がいいかもしれませんね。
期待しております!
|
|