ワールド軸回転?

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
紅葉

ワールド軸回転?

#1

投稿記事 by 紅葉 » 16年前

そのメッシュに対しての回転ではなくワールド軸に対しての回転は出来ないのでしょうか?

回転行列を使い2つまでの軸回転ならおかしくないですが3ついじると狂ってしまいます。

イメージとしてはキーボードの方向キーを押したらカメラから見てその方向に回転します。

今の段階だと90等のきりのいい数字の他で上下の操作が逆になり微妙な回転をします。

原因の理論としてはなんとなくわかるのですが、理解できません><

カメラは移動したり回転したりしません。

Justy

Re:ワールド軸回転?

#2

投稿記事 by Justy » 16年前

 なんか、最近よく似た質問を見かけたような気がしますが。

 具体的なソースとか成果物はないのですか?



>イメージとしてはキーボードの方向キーを押したらカメラから見てその方向に回転します。

 つまりこういうことですか?

ttp://toku.xdisc.net/cgi/up/ttt/nm4018.zip.html
nm4018.zip

キーボード上下X回転、左右でY回転、SHIFTを押しながら左右でZ回転

紅葉

Re:ワールド軸回転?

#3

投稿記事 by 紅葉 » 16年前

そうです><

if(GetInputKEY(kKEYUP)) Box.Rot.Pit--;
if(GetInputKEY(kKEYDOWN)) Box.Rot.Pit++;
if(GetInputKEY(kKEYRIGHT))      Box.Rot.Yaw--;
if(GetInputKEY(kKEYLEFT)) Box.Rot.Yaw++;

描画

// スケール(x、y、z)・角度(y、p、r)
void DrawModel(float x,float y,float z,GsMESH id,float scx,float scy,float scz,float yaw,float pitch,float roll)
{
D3DXVECTOR3 pos;
pos = D3DXVECTOR3(x,y,z);
DrawModel(&GsMeshHang[id],scx,scy,scz,F(RAD(yaw)),F(RAD(pitch)),F(RAD(roll)),pos);
}
DrawModel(0,0,0,BOX_MESH,1,1,1,Box.Rot.Yaw,Box.Rot.Pit,Box.Rot.Rol);

という感じに書いています。
過去のものも見ましたが私ではありません。
類似な質問になってしまってすいません。

Justy

Re:ワールド軸回転?

#4

投稿記事 by Justy » 16年前


>過去のものも見ましたが私ではありません。
>類似な質問になってしまってすいません。

 いえ、失礼しました。



>という感じに書いています。

 んーと、DrawModel()内で別の DrawModel()を呼んでいる、と。
 内部でどう行列を作って表示しているのかはわかりませんが、
なんとなくそれではうまくいかないような気がします。

 少なくとも元の状態のオブジェクトの姿勢の情報と、動かしたい分の x/y/zの
回転量が必要になります。
 つまり、どう変化したのかの情報が必要になります。


 ちなみにさっきのコードはこんな感じでした。
 m_worldは予め単位行列を入れておきます。
[color=#d0d0ff" face="monospace]
    D3DXMATRIX rx, ry, rz;
    D3DXMatrixIdentity(&rx);
    D3DXMatrixIdentity(&ry);
    D3DXMatrixIdentity(&rz);

    if(非shift && 左)
        D3DXMatrixRotationY(&rx, D3DXToRadian(2.0f));
    else
    if(非shift && 右)
        D3DXMatrixRotationY(&rx, -D3DXToRadian(2.0f));
    if(上)
        D3DXMatrixRotationX(&ry, D3DXToRadian(2.0f));
    else
    if(下)
        D3DXMatrixRotationX(&ry, -D3DXToRadian(2.0f));
    if(shift && 左)
        D3DXMatrixRotationZ(&rz, D3DXToRadian(2.0f));
    else
    if(shift && 右)
        D3DXMatrixRotationZ(&rz, -D3DXToRadian(2.0f));

    D3DXMatrixMultiply(&m_world, &m_world, &rz);
    D3DXMatrixMultiply(&m_world, &m_world, &ry);
    D3DXMatrixMultiply(&m_world, &m_world, &rx);
    
    pD3DDevice->SetTransform(D3DTS_WORLD, &m_world);[/color]
 m_worldが行列なのですが、前のフレームの行列をそのまま使って、
そのフレームで動かしたい分だけを rx/ry/rzなどの行列を作り、
掛け合わせていきました。

 或いは多分こっちでも動くと思います。
[color=#d0d0ff" face="monospace]    float yaw=0, pitch=0, roll=0;

    if(非shift && 左)
        yaw = D3DXToRadian(2.0f);
    else
    if(非shift && 右)
        yaw = -D3DXToRadian(2.0f);
    if(上)
        pitch = D3DXToRadian(2.0f);
    else
    if(下)
        pitch = -D3DXToRadian(2.0f);
    if(shift && 左)
        roll = D3DXToRadian(2.0f);
    else
    if(shift && 右)
        roll = -D3DXToRadian(2.0f);

    D3DXMatrixRotationYawPitchRoll(&m, yaw, pitch, roll);
    D3DXMatrixMultiply(&m_world, &m_world, &m);
    
    pD3DDevice->SetTransform(D3DTS_WORLD, &m_world);[/color]

紅葉

Re:ワールド軸回転?

#5

投稿記事 by 紅葉 » 16年前

これがソースになります><
チャレンジしてみたのですが勉強不足でできません><

Justy

Re:ワールド軸回転?

#6

投稿記事 by Justy » 16年前

 なるほど、こうなっていたわけですね。

 うーん、この描画ライブラリは姿勢を角度だけで表現しているので、
ちょっと厄介ですね。

 なので、行列を直接渡して描画する関数を追加してしまいましょう。

1 Ci-Libに以下の関数を追加します。
[color=#d0d0ff" face="monospace]
void Gs_DrawModelMat(GsMESH id, const MAT &m);
{
    lpD3DDev->SetTransform(D3DTS_WORLD,&m);
    DrawMyMesh(&GsMeshHang[id]);
}[/color]
 Ci-Libに数ある描画関数の中でも、非常にシンプルです。


2 構造体 MOD_TESに
[color=#d0d0ff" face="sans-serif ]
D3DXQUATERNION Quat;[/color]

 を追加して、
[color=#d0d0ff" face="sans-serif ]
D3DXMATRIX Mat[/color]

 を消します。

 見ての通り、クォータニオンです。
 これはオブジェクトの姿勢を保持します。


3 GameMainの GameInit()で以下を追加します。
[color=#d0d0ff" face="sans-serif ]
D3DXQuaternionIdentity(&Box.Quat);[/color]

 クォータニオンの初期化ですね。


4 GameMainの関数 PlayControl()と GameDraw3D()を以下のように書き換えます。
[color=#d0d0ff" face="monospace]void    PlayControl(void)
{
    DIR3& rot = Box.Rot;
    rot.Yaw = rot.Pit = rot.Rol = 0;
    
    const float rotateAngle = D3DXToRadian(5.0f);
    if(Gs_GetKEY(kKEYRIGHT))    rot.Yaw -= rotateAngle;
    if(Gs_GetKEY(kKEYLEFT))     rot.Yaw += rotateAngle;
    if(Gs_GetKEY(kKEYUP))       rot.Pit-= rotateAngle;
    if(Gs_GetKEY(kKEYDOWN))     rot.Pit += rotateAngle;
}[/color]
 Box.Rotは毎回必ず全て 0で初期化しています。これで、このフレームでどれだけ動くかの
情報を保持します。
 あと、余力があれば、Rollコントロールも追加してみて下さい。
[color=#d0d0ff" face="monospace]void    GameDraw3D(void)
{   
    // 前のフレームまでの回転と今の回転を合成
    D3DXQUATERNION q;
    D3DXQuaternionRotationYawPitchRoll(&q, Box.RotOffset.Yaw, Box.RotOffset.Pit, Box.RotOffset.Rol);
    D3DXQuaternionMultiply(&Box.Quat, &Box.Quat, &q);
    
    // このモデルの行列
    D3DXMATRIX m, boxMat;
    D3DXMatrixIdentity(&boxMat);
    
    // 回転
    D3DXMatrixRotationQuaternion(&m, &Box.Quat);
    D3DXMatrixMultiply(&boxMat, &boxMat, &m);
    
    // 移動
    D3DXMatrixTranslation(&m, Box.Pos.x, Box.Pos.y, Box.Pos.z);
    D3DXMatrixMultiply(&boxMat, &boxMat, &m);
    
    // 表示
    Gs_DrawModelMat(M_BOX, boxMat);
}[/color]
 これは位置と前のフレームまでの姿勢と、このフレームでの回転量を元に行列を作ります。
 そして、1で作った Gs_DrawModelMat()に引き渡して描画を行います。

 これで一応動きます。

Justy

Re:ワールド軸回転?

#7

投稿記事 by Justy » 16年前

 あー、見たらこの Ci-Libには Gs_DrawModelAxis()という任意の軸回転をサポートした
関数がありますね。

 だとすると、4の GameDraw3D()は1で追加した関数を使わなくても
これで表示できます。
[color=#d0d0ff" face="monospace]void    GameDraw3D(void)
{   
    D3DXQUATERNION q;
    D3DXQuaternionRotationYawPitchRoll(&q, Box.Rot.Yaw, Box.Rot.Pit, Box.Rot.Rol);
    D3DXQuaternionMultiply(&Box.Quat, &Box.Quat, &q);

    float angle;
    D3DXVECTOR3 axis;
    D3DXQuaternionToAxisAngle(&Box.Quat, &axis, &angle);
    Gs_DrawModelAxis(Box.Pos.x, Box.Pos.y, Box.Pos.z, M_BOX, 1, 1, 1,
        0, 0, 0, D3DXToDegree(angle), axis.x, axis.y, axis.z);
}[/color]

紅葉

Re:ワールド軸回転?

#8

投稿記事 by 紅葉 » 16年前

ハッカーさん
何度も回答ありがとうございます。

最初の意見の方をしてみたのですが
毎フレーム場所が初期化されてしまいだめでした。

次の意見もしてみましたが
D3DXQuaternionRotationYawPitchRoll(&q, Box.RotOffset.Yaw, Box.RotOffset.Pit, Box.RotOffset.Rol);
のoffsetがみつからず(用意していない?)
Box.RotOffset.Yaw を Box.Rot.Yaw にすると
なぜか回転し続けてしまいます・・・
ライブラリが配布されたもの+オリジナルなので理解できない所が多々あります。

できれば後者で上げた方の完成版?をいただけないでしょうか
甘えた発言で申し訳ありません。

Justy

Re:ワールド軸回転?

#9

投稿記事 by Justy » 16年前

 あ、失礼しました。
 RotOffsetは Rotですね。

>毎フレーム場所が初期化されてしまいだめでした
 こっちはどういう意味かよくわかりませんが、

>なぜか回転し続けてしまいます・
 rot.Yaw = rot.Pit = rot.Rol = 0;がないからだったりしませんか?

 とりあえず、GameMainの方を添付しておきます。
 GameDraw3D()は #ifdefで分けられていますが、どちらでもいけると思います。

紅葉

Re:ワールド軸回転?

#10

投稿記事 by 紅葉 » 16年前

ありがとうございます>< できました。

このサイトは本当にいい場所で感謝しています。

Justy

Re:ワールド軸回転?

#11

投稿記事 by Justy » 16年前


>できました。

 出来たのはいいのですが、どうやってやっているかはしっかりと見ておいて下さい。
 Gs_DrawModelMat()版と Gs_DrawModelAxis()版の両方で。
 
 
 どっちを使った方がいいのかというのについては、将来を見据えるなら前者、
今のライブラリと調和させるなら後者となります。

 でも、なんでもかんでも Yaw/Pitch/Rollでは辛いような・・・。

閉鎖

“C言語何でも質問掲示板” へ戻る