トップページ > 過去ログ > 記事閲覧
フレーム内の座標を動かさずに回転…
名前:もんちき 日時: 2010/09/16 01:15

 こんにちは、もんちきと申します。いつも参考にさせていただいています。 今3Dのフレームの制御で悩んでいます。どなたかご教授下さい。  現在、各フレーム内のメッシュをそれぞれその位置で回転させたい…と思っているのですが、 どうもうまくゆきません。私が作ったのは以下の様なコードです。 #include "DxLib.h" int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow ) { int ModelHandle ; float rotation_y; MATRIX Matrix1,Matrix2; rotation_y = 0; ChangeWindowMode(TRUE); if( DxLib_Init() < 0 ) { return -1 ; } ModelHandle = MV1LoadModel( "simplemodel.mqo" ) ; MV1SetPosition( ModelHandle, VGet( 320.0f, 100.0f, 600.0f ) ) ; const VECTOR LOCAL_POS = { 80.0f, 0.0f, 0.0f }; while (ProcessMessage() == 0 && CheckHitKey(KEY_INPUT_ESCAPE) == 0) { rotation_y = rotation_y + 0.01f; if (rotation_y >= 360){ rotation_y = 0; } MV1SetRotationXYZ( ModelHandle, VGet( 0.0f, rotation_y, 0.0f ) ) ; Matrix1 = MV1GetFrameLocalMatrix(ModelHandle,2); Matrix2 = MGetRotY(0.1f); Matrix1 = MMult(Matrix1,Matrix2); MV1SetFrameUserLocalMatrix(ModelHandle,2,Matrix1); ClearDrawScreen(); MV1DrawModel( ModelHandle ) ; ScreenFlip(); } DxLib_End() ; return 0 ; }  これですと、simple.mqoの2番目のフレームがsimple.mqoの(0,0,0)を中心に回転しますが、 そうではなく、他のフレームとの位置関係を保ったまま回転させたいのです。うまく説明できませんが、 太陽の周りを公転しながら自転する地球の様な動きと言いますか…  過去のログにあった「指定した座標を中心に回転」というスレッドが良く似た質問だと思うのですが、 例えばあのソースにあった MV1SetFrameUserLocalMatrix( mh, 2, MGetTranslate( VTransform( LOCAL_POS, MGetRotAxis( REVOLVE_AXIS, REVOLVE_RATE * angle ) ) ) ); は、LOCAL_POSが3軸とも0、つまりオフセット指定ない状態で、その場での回転をさせる事ができるでしょうか?  下手な説明で申し訳ありませんが、どうかご教授下さい。よろしくお願いします。

Page: 1 |

Re: フレーム内の座標を動かさずに回転… ( No.1 )
名前:いっち 日時:2010/09/16 20:39

おそらくモデルの原点を軸にモデルの一部として自転させるのではなく、 フレームに設定した中心点を軸に自転させたいのだと思いますが、 私の知る限りではそういった機能はDXライブラリには無いのではないかと思います。(地道に計算すれば可能だと思いますが) 私は3Dに疎いのでそういったことが普通出来るものなのかわかりませんし、 モデルのフレーム1つ1つに中心点のようなものを設定できるのかどうかもわかりません。
Re: フレーム内の座標を動かさずに回転… ( No.2 )
名前:もんちき 日時:2010/09/16 22:55

 こんばんは、いっちさん。早速のご回答ありがとうございます。  私がやりたい事は、まさにいっちさんのおっしゃる様な事です。  なるほど…私もリファレンスを見ながら、「できないのかも…」と 思ったのですが、考えてみるとサンプルにあるワンスキンメッシュの アニメーションは、ボーンで設定した頂点を関節点にして動いている訳で、 同様にsimple.mqoの様な複数のメッシュがあるモデルの中にも ボーンを設定すれば、そんな事ができるのでは…と思っているのです。  ちなみにフレームではなく、別々のモデルを読み込んで、同じ様な 事をさせられないか…についても考えているのですが、これもうまく できません。それぞれのモデルはそれぞれの原点を中心に回転しますが、 例えば別のモデルの原点を中心に、位置関係を保ったまま連動(公転) させることはできるでしょうか?
Re: フレーム内の座標を動かさずに回転… ( No.3 )
名前:いっち 日時:2010/09/17 20:21

> 例えば別のモデルの原点を中心に、位置関係を保ったまま連動(公転) > させることはできるでしょうか? 可能だと思います。 私が書いたレスで恐縮なのですが、以下のURLのレス(No.1)に他の球体を中心に円を描いて平行移動させています。 モデルについても同じように出来ると思います。(公転はあくまで平行移動なのでMV1SetRotation〜ではなくMV1SetPositionで行います) ttp://hpcgi2.nifty.com/natupaji/bbs/patio.cgi?mode=view&no=1875
Re: フレーム内の座標を動かさずに回転… ( No.4 )
名前:いっち 日時:2010/09/18 13:26

DxChara.x でやってみましたが、ボーンの設定されているモデルの場合、 フレームを自転させると設定されている関節(?)を中心にそれぞれ自転するようです。 (MV1GetFramePositionの戻り値もおそらく関節の位置) ただ、回転軸は自前で設定する必要がありました。 私は自分でモデルを作ったことが無いのでやり方を知らないのですが、 とりあえず、ボーンを設定すれば、フレーム単位の自転は可能なようです。
Re: フレーム内の座標を動かさずに回転… ( No.5 )
名前:もんちき 日時:2010/09/19 02:07

 いっちさん、色々とアドバイス。ありがとうございます。 >可能だと思います。 >私が書いたレスで恐縮なのですが、以下のURLのレス(No.1)に他の球体を中心に円を描いて平行移動させています。  はい。このスレッドをたてる前に、いっちさんのお作りになったサンプルも、勿論試させていただきました。 Sphereを他の3Dデータに置き換えて、動作の確認もしました。  とても参考になったのですが、あれですと公転するSphereの座標系は、平行に移動し回転しない様に思えます。 例えばフレームを持つモデルをアニメーションさせずに回転させる場合、各フレームのローカル座標系は、一番親の 原点を中心に回転します。同様に、公転するSphereを自転させない場合、中央のSphereと公転するSphereは、常に 同じ面で向き合ったまま回転させたいのです。  相変わらず分かりにくい説明で済みません>ω<、 >とりあえず、ボーンを設定すれば、フレーム単位の自転は可能なようです。  という事は、私の作ったプログラムかデータが間違っているのですね…  恐れ入りますが、可能でしたらいっちさんがDxChar.xで試されたプログラムを、見せていただけますか?  ちなみに、今私が試しに使っているのがこのデータです。アニメーションもするのでボーンの設定はできていると 思います。(公転するSphereのフレームは(恐らく)4番、そのボーンのフレームは11番の様です。) 無理でなくてかまいませんので、もしお時間があれば、このデータでも同じ事が可能かご確認いただけますか?   ttp://homepage2.nifty.com/essex/temp/earth.zip
Re: フレーム内の座標を動かさずに回転… ( No.6 )
名前:いっち 日時:2010/09/19 20:56

ご提供頂いたモデルを使ってやってみました。 ご要望にお応えできていると良いのですが、 途中で訳が分からなくなりかけたので自信がありません。 //- 以下、テストコード "earth.x"を使用 -// #include <math.h> #include "DxLib.h" // 地球の自転 const float EARTH_ROTATION_RATE = -TWO_PHI_F / 60.0f; // 1秒で一周 const VECTOR EARTH_ROTATION_AXIS = { 0.0f, 1.0f, 0.0f }; // 月の公転 const float MOON_REVOLUTION_RATE = EARTH_ROTATION_RATE / 27.3f; // 地球が大体27周すると一周 const VECTOR MOON_REVOLUTION_AXIS = { 0.0f, 1.0f, 0.0f }; // 月の自転 const float MOON_ROTATION_RATE = -MOON_REVOLUTION_RATE; // この値はモデルの補正により発生する自転を打ち消す・・・はず const VECTOR MOON_ROTATION_AXIS = { 0.0f, 1.0f, 0.0f }; // 値を変えると独自な自転に調節できる const int EARTH_FRAME = 8; const int MOON_FRAME = 10; int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow ) { ChangeWindowMode( TRUE ); if ( DxLib_Init( ) == -1 ) return -1; SetDrawScreen( DX_SCREEN_BACK ); int StrColor = GetColor( 255, 255, 255 ); int mh = MV1LoadModel( "earth.x" ); MV1SetPosition( mh, VGet( 320.0f, 240.0f, 800.0f ) ); MV1SetScale( mh, VGet( 0.20f, 0.20f, 0.20f ) ); MATRIX mat_earth = MV1GetFrameLocalMatrix( mh, EARTH_FRAME ); MATRIX mat_moon = MV1GetFrameLocalMatrix( mh, MOON_FRAME ), mat_temp; float earth_rot = 0.0f, moon_rot = 0.0f, moon_rev = 0.0f; while ( ProcessMessage( ) == 0 && CheckHitKey( KEY_INPUT_ESCAPE ) == 0 ) { earth_rot += EARTH_ROTATION_RATE; moon_rev += MOON_REVOLUTION_RATE; moon_rot += MOON_ROTATION_RATE; if ( abs( earth_rot ) >= TWO_PHI_F ) earth_rot = 0.0f; if ( abs( moon_rev ) >= TWO_PHI_F ) moon_rev = 0.0f; if ( abs( moon_rot ) >= TWO_PHI_F ) moon_rot = 0.0f; MV1SetFrameUserLocalMatrix( mh, EARTH_FRAME, MMult( MGetRotAxis( EARTH_ROTATION_AXIS, earth_rot ), mat_earth ) ); mat_temp = mat_moon; mat_temp = MMult( mat_temp, MGetRotAxis( MOON_REVOLUTION_AXIS, moon_rev ) ); // 月の公転を設定 mat_temp = MMult( MGetRotAxis( MOON_ROTATION_AXIS, moon_rot ), mat_temp ); // 月の自転を設定 コメントにすると 公転周期=自転周期 となる自転を行う MV1SetFrameUserLocalMatrix( mh, MOON_FRAME, mat_temp ); ClearDrawScreen( ); DrawFormatString( 0, 0, StrColor, "test" ); MV1DrawModel( mh ); ScreenFlip( ); } DxLib_End( ); return 0; }
Re: フレーム内の座標を動かさずに回転… ( No.7 )
名前:もんちき 日時:2010/09/20 17:51

 いっちさん、コードをありがとうございました。またモデルをダウンロードして試して 下さり、重ねてありがとうございました。  なるほど…私は単純にフレームのローカル配列に、MGetRotYで得られる回転の配列を 掛け合わせていましたが、回転軸を示すベクトルの設定が無かったり、公転運動の配列を 掛け合わせていなかったり、色々足りなかったのですね。DxLibの問題じゃなくて、私の 理解が足りなかったのが原因でしたね^^;  いっちさん、色々ありがとうございました。おかげさまでフレームごとの制御が可能な事も 分かり、色々勉強になりました。ありがとうございました。  ところで質問なのですが、いっちさんのプログラムを次の様にすると //MV1SetFrameUserLocalMatrix( mh, EARTH_FRAME, MMult( MGetRotAxis( EARTH_ROTATION_AXIS, earth_rot ), mat_earth ) ); mat_temp = mat_moon; //mat_temp = MMult( mat_temp, MGetRotAxis( MOON_REVOLUTION_AXIS, moon_rev ) ); mat_temp = MMult( MGetRotAxis( MOON_ROTATION_AXIS, moon_rot ), mat_temp ); MV1SetFrameUserLocalMatrix( mh, MOON_FRAME, mat_temp );  当然ながら、月の自転だけが起こりますよね。そこに MV1SetRotationXYZ( mh, VGet( 0.0f, 90.0f * PHI_F / 180.0f, 0.0f ) ) ;  この行を追加してモデル自体を回転させようとすると、予想ではいっちさんのお作りになった プログラムと同じ事ができるかと思ったのですが、想像したのと異なることが起こります。 これは何が違うのでしょうか?  質問ばかりで済みません。急ぎませんのでご教授下さい。よろしくお願いします。
Re: フレーム内の座標を動かさずに回転… ( No.8 )
名前:いっち 日時:2010/09/20 18:59

> MGetRotYで得られる回転の配列を掛け合わせていましたが、回転軸を示すベクトルの設定が無かったり 私が MGetRotY を使わずに MGetRotAxis を使うのは、私自身が回転の軸を強く意識することができるので、 プログラムをしやすいためです。それと、たとえば以下の行を > const VECTOR EARTH_ROTATION_AXIS = { 0.0f, 1.0f, 0.0f }; ↓↓↓↓ > const VECTOR EARTH_ROTATION_AXIS = { 0.25f, 1.0f, 0.0f }; 等のように変えると簡単に地軸を変更できるのでサンプルとしてちょっと面白いかなと思ったという理由もあります。 ですので、XYZのそれぞれの軸に垂直な平面上でしか回転を行わないのであれば、MGetRotYなどを使用するほうが良いと思います。 > MV1SetRotationXYZ( mh, VGet( 0.0f, 90.0f * PHI_F / 180.0f, 0.0f ) ) ; > >  この行を追加してモデル自体を回転させようとすると、予想ではいっちさんのお作りになった > プログラムと同じ事ができるかと思ったのですが、想像したのと異なることが起こります。 > これは何が違うのでしょうか? まず、1点として、Y軸の回転量として与えられている値が定数になっています。 回転"運動"を行う場合はこの値を刻々と変化させる必要があります。(最初のソースではそのようになっているのでお分かりだとは思いますが) 具体的には以下のようにすることで、月の公転が復活するはずです。 > MV1SetRotationXYZ( mh, VGet( 0.0f, moon_rev, 0.0f ) ); ただ、MV1SetRotationXYZはモデル全体を回転させるので、この場合もまったく同じ動作ではありません。 テストコードの月の公転速度が遅いため気づきにくいですが、微妙に地球の自転にも影響しています。 以下のように変更すると、よりはっきり分かると思います。 > const float MOON_REVOLUTION_RATE = EARTH_ROTATION_RATE / 27.3f; ↓↓↓↓ > const float MOON_REVOLUTION_RATE = EARTH_ROTATION_RATE; 対処法としては、地球の自転速度をうまく調整するか、今回のようにフレームごとの制御にする必要があります。
Re: フレーム内の座標を動かさずに回転… ( No.9 )
名前:もんちき(解決) 日時:2010/09/21 00:18

 なるほど!  いっちさんのアドバイスの通り、回転量の与え忘れはうっかりでした^^; ワールド座標とローカル座標の事とか考えて、そちらにばかり頭が行って 足元見ていませんでした。  色々ありがとうございました。フレームの制御を行うか別々のモデルを連動させるのか 迷っていましたが、フレームありのモデルをアニメーション以外で制御するというのも、 色々面白そうですね。

Page: 1 |