HSPポータル
サイトマップ お問い合わせ


HSPTV!掲示板


未解決 解決 停止 削除要請

2014
0429
(Hgimg)Boxを90度ずつ回転4未解決


リンク

2014/4/29(Tue) 12:07:32|NO.61744

はじめまして。
HgimgでBoxを回転させる方法について質問があります。

目標とする動作は、十字キー入力に応じてBoxを転がすというものです。
サイコロを90度ずつ回転させるイメージです。
また、上面に位置している目を取得したいとも考えています。

現状での問題は、回転を繰り返して軸が変わると、入力に対して理想とする方向に回転してくれないことです。
文章では説明が難しいのですが、例えばx軸を中心(1方向)に転がすだけでしたら、

addang dice,90,0,0

のような処理を繰り返せばいいのですが、一度別の軸に対して回転させると、回転軸がおかしくなる(ねじのような回転をしてしまう、など)ことがあります。 回転軸が変わってしまうので当たり前といえば当たり前なのですが、なにかうまい解決方法はあるでしょうか? 愚直に全パターンについて、if文で処理するということも考えたのであまりにも膨大になってしまうので。 分かりづらいところがあったらすいません。 よろしくお願いします。



この記事に返信する


modelorder

リンク

2014/4/29(Tue) 13:31:04|NO.61745

modelorder命令を使って、軸が回転する順番を変えてあげると、うまくいくかもしれない
 modelorder dice,HGMODEL_ROTORDER_YXZ
ためしてみてっ

あ、それと、addangで角度をいれるときは、
 addang dice,deg2rad(90),0,0




リンク

2014/4/29(Tue) 19:21:29|NO.61771

ありがとうございます!

modelorder命令を試してみます。
回転の順序が関係あるのですね!


>あ、それと、addangで角度をいれるときは
ラジアンでしたね。失礼しました。



暇人

リンク

2014/4/29(Tue) 23:58:35|NO.61773

Hgimg3じゃなくてHgimg?
addangが使えるのはHgimg3だから
Hgimg3で解答

任意軸での回転が出来ないと無理だと思うのでクォータニオンを使って対処

//モジュールここから(このモジュールはDirectX9が必須です) #module "mod_D3DXQ" #uselib "d3dx9_39.dll" #func D3DXMatrixRotationX "D3DXMatrixRotationX" var,float #func D3DXMatrixTranslation "D3DXMatrixTranslation" var,float,float,float #func D3DXQuaternionRotationAxis "D3DXQuaternionRotationAxis" int,var,float #func global D3DXMatRotQ "D3DXMatrixRotationQuaternion" var,int #func D3DXQuaternionMultiply "D3DXQuaternionMultiply" int,int,int #func D3DXMatrixMultiply "D3DXMatrixMultiply" var,var,var #func D3DXMatrixRotationYawPitchRoll "D3DXMatrixRotationYawPitchRoll" var,float,float,float #func D3DXQuaternionRotationMatrix "D3DXQuaternionRotationMatrix" int,int #cfunc global D3DXQuaternionN "D3DXQuaternionNormalize" int,int #const H_PI M_PI/2.0 //「----クォータニオンモジュールの初期化----」 //D3DXQuaternion_init qmax //qmax [クォータニオンID使用最大数(省略時1024)]int #deffunc D3DXQ_init int qmax if qmax<=0 {_qmax=1024}else{_qmax=qmax} dim q,4*_qmax q_ptr=varptr(q) dim qid_list,_qmax ddim temp_double,1 dim tq,4 tq_ptr=varptr(tq) dim TurnMat,16 dim temp_Mat,16 dupptr dup_x,varptr(temp_Mat(12)),4,4 dupptr dup_y,varptr(temp_Mat(13)),4,4 dupptr dup_z,varptr(temp_Mat(14)),4,4 dupptr dup_mov,varptr(temp_Mat(12)),4*3,4 return //「--------------クォータニオンから各オイラー角取得----」 //QGetAngXYZ %1 ,%2 ,%3 ,%4 //%1 [クォータニオンID(入力)]int //%2 ,%3 ,%4 [各オイラー角(出力)]double #define global QGetAngXYZ(%1,%2,%3,%4) D3DXMatRotQ TurnMat@mod_D3DXQ,D3DXQuaternionN(tq_ptr@mod_D3DXQ,qid_list@mod_D3DXQ(%1)):MatToEul TurnMat@mod_D3DXQ,%2,%3,%4 //「--------------指定角度から指定QIDにクォータニオン作成----」 //QSetRotXYZ qid, rx, ry, rz // qid [クォータニオンID(入力)]int // rx, ry, rz [各オイラー角(入力)]double //(使用できる最大IDを超えるとstatに-1が返る) #deffunc QSetRotXYZ int qid,double rx,double ry,double rz if qid < _qmax { D3DXMatrixRotationYawPitchRoll temp_Mat,-ry, 0.0, rz D3DXMatrixRotationX TurnMat,rx D3DXMatrixMultiply temp_Mat,temp_Mat,TurnMat D3DXQuaternionRotationMatrix varptr(q(qid*4)),stat qid_list(qid)=stat }else{ return -1 } return 0 //「-------------QIDを指定して入力クォータニオンの姿勢を基準に軸を指定して入力クォータニオンを回転----」 //QAddAxisRot qid, ax ,ay ,az , qrot // qid [クォータニオンID(入力)]int // ax ,ay ,az [回転軸ベクトル(入力)]double // qrot [回転量(入力)]double // World [軸がローカルかワールドか指定 0=ローカル軸 1=ワールド軸 (入力)]int #deffunc QAddAxisRot int qid,double ax,double ay,double az,double qrot,int World D3DXMatrixTranslation temp_Mat,ax ,ay ,az D3DXQuaternionRotationAxis tq_ptr,dup_mov,qrot if World {D3DXQuaternionMultiply qid_list(qid),stat,qid_list(qid)}else{D3DXQuaternionMultiply qid_list(qid),qid_list(qid),stat} return //「-------------QIDを指定して入力クォータニオンの姿勢を基準に軸を指定して入力クォータニオンを回転----」 //GetAxis A_index, Axisx, Axisy, Axisz // A_index [ワールド軸を指定(0=X軸 1=Y軸 2=Z軸)]int // Axisx, Axisy, Axisz [指定された軸に重なるほど1.0に近くなる(出力)]double #deffunc GetAxis int A_index,var Axisx,var Axisy,var Axisz Axisx=ftd(TurnMat(0+A_index*4)) Axisy=ftd(TurnMat(1+A_index*4)) Axisz=ftd(TurnMat(2+A_index*4)) return //「-------------回転行列から各オイラー角取得----(QtoRxyzから使われる事が前提で単体では使用しない)」 //MatToEul Mat, ex, ey, ez // Mat [回転行列4*4(入力)]float // ex ,ey ,ez [各オイラー角(出力)]double #deffunc MatToEul array Mat ,var ex,var ey,var ez Mat8=limitf(ftd(Mat(8)),-1.0,1.0) ey=-atan(Mat8,sqrt(1.0-Mat8*Mat8)) if absf(cos(ey))<0.001{ ex=atan(ftd(Mat(6)),ftd(Mat(5))) if Mat8>0.0 {ey=-H_PI}else{ey=H_PI} ez=0.0 }else{ ex=atan(-ftd(Mat(9)),ftd(Mat(10))) ez=atan(-ftd(Mat(4)),ftd(Mat(0))) } return //「----doubleからfloatに変換----」 //変数 = dtf( double ) #defcfunc dtf double _x D3DXMatrixTranslation temp_Mat,_x return dup_x //「----floatからdoubleに変換----」 //変数 = ftd( float ) #defcfunc ftd int p1 temp=p1 << 29,p1 & 0x80000000 | ((p1 & 0x7fffffff) >> 3) + ((p1 & 0x7fffffff) ! 0) * 0x38000000 memcpy temp_double,temp,8 return temp_double #global //モジュールここまで #include "hgimg3.as" D3DXQ_init //モジュール初期化 screen 0,640,480,0 cls 4 hgini addbox mdid,1,1//中心(親)のボックスモデル regobj mychr,mdid ; 中心(親)のボックスオブジェクト texload dir_exe+"\\sample\\hgimg3\\fontchr.bmp" ; テクスチャの登録 texid=stat //パネルの位置 // 4 1 3 // 2 // 6 // 5 dx=0,0,1,-1,0,0 //パネル配置座標 dy=0,1,0,0,-1,0 dz=1,0,0,0,0,-1 drx=0,-90+180,0,0,90+180,-180 //パネルの角度 dry=0,0,90,-90,180,0 repeat 6 addplate m_plate,0,5,5,16*(1+cnt),16*3,16+16*(1+cnt),16+16*3,texid regobj p_id(cnt),m_plate objchild mychr,p_id(cnt) //パネルを中心のオブジェクトに連結 setpos p_id(cnt),2.5*dx(cnt),2.5*dy(cnt),2.5*dz(cnt) setang p_id(cnt),deg2rad(drx(cnt)),deg2rad(dry(cnt)),0 loop selcpos objset3 6.0, -10.0, 20.0 selcang objset3 -0.3, 0.3, 0.0 R90=M_PI/2 //90度のラジアン //オブジェクトIDを使ってクォータニオン作成(使いやすいようにクォータニオンIDとオブジェクトIDを同じにしてる) QSetRotXYZ mychr, 0.0, 0.0, 0.0 clscolor $4444 *main stick k,0 if k&128 : goto *owari ; [ESC]で終了 if k&1 : QAddAxisRot mychr, 0.0, 1.0, 0.0, R90 ,1 //ワールドY軸を回転(←) if k&4 : QAddAxisRot mychr, 0.0, 1.0, 0.0, -R90 ,1 //(→) if k&2 : QAddAxisRot mychr, 1.0, 0.0, 0.0, -R90 ,1 //ワールドX軸を回転(↑) if k&8 : QAddAxisRot mychr, 1.0, 0.0, 0.0, R90 ,1 //(↓) if k&256 : QAddAxisRot mychr, 0.0, 0.0, 1.0, R90 ,1 //ワールドZ軸を回転(左クリック) if k&512 : QAddAxisRot mychr, 0.0, 0.0, 1.0, -R90 ,1 //(右クリック) //クォータニオンからオイラー角を取得 QGetAngXYZ mychr,rx,ry,rz setang mychr,rx,ry,rz //ローカル軸が向いてる方向を取得(1を指定するとワールドY軸にどのローカル軸が向いてるかが分かる) GetAxis 1, Axisx, Axisy, Axisz //直前にQGetAngXYZされたクォータニオンに対して取得 ax=int(Axisx*1.1) //1.1を掛けてるのはint型にする時に誤差で0になるのを防ぐ ay=int(Axisy*1.1) az=int(Axisz*1.1) //Axisx, Axisy, Axisz の組み合わせで数字が分かる(+-1がワールドY軸に重なってるローカル軸で、符号で上下が分かる) ;0,0,-1 //1 ;0,-1,0 //2 ;-1,0,0 //3 ;1,0,0 //4 ;0,1,0 //5 ;0,0,1 //6 if ax {if ax=1 {no=4}else{no=3}} if ay {if ay=1 {no=5}else{no=2}} if az {if az=1 {no=6}else{no=1}} title strf("X(%.1f) Y(%.1f) Z(%.1f)",rad2deg(rx),rad2deg(ry),rad2deg(rz))+strf(" [軸 ax(%d) ay(%d) ax(%d)]", ax, ay, az)+" サイコロの目="+no hgdraw ; 描画処理 hgsync 16 ; 時間待ち goto *main *owari end
これはワールド軸を基準にして回転させてるけど
サイコロのローカル軸で回転も出来る



暇人

リンク

2014/5/2(Fri) 18:03:50|NO.61814

GetAxisの説明文が他の命令からコピペしたままになってたので修正

//「-------------ワールド軸を指定してローカル軸の傾きを取得----」 //GetAxis A_index, Axisx, Axisy, Axisz // A_index [ワールド軸を指定(0=X軸 1=Y軸 2=Z軸)]int // Axisx, Axisy, Axisz [指定された軸に重なるほど1.0(-1.0は反対を向いてる事になる)に近くなる(出力)]double



ONION software Copyright 1997-2023(c) All rights reserved.