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


HSPTV!掲示板


未解決 解決 停止 削除要請

2021
1030
youdaiHGIMG4で基点を原点にした拡大縮小、及び回転を実装したい2解決


youdai

リンク

2021/10/30(Sat) 12:14:21|NO.94254

●HGIMG4で基点を原点にした拡大縮小、及び回転を実装したい

HGIMG4で基点を原点にしたノード(オブジェクト)の拡大縮小、及び回転を実装したいです。

イメージとしては、blenderのトランスフォームピボットポイントの
「3Dカーソルを中心に操作する」トランスフォームモードです。

HGIMG4の拡大縮小や回転は「それぞれの原点」を基点とした拡大縮小や回転だと思いますが、

基点を原点にした(基点の位置を変えられる)拡大縮小、及び回転が使えれば便利だと思いました。

基点を原点にした拡大縮小命令と回転命令のイメージ


/* 通常の拡大と、基点からの拡大の違い 3つの頂点がある2mの線のオブジェクトを例えとする。 拡大元のスケール(左の頂点の位置,中心の頂点の位置,右の頂点の位置) -1.0, 0.0, 1.0 通常の拡大後(setscale 2.0) -2.0, 0.0, 2.0 基点からの拡大 基点が-1.0にあった場合のscale 2.0 -1.0, 1.0, 3.0 横のスケールと位置の関係について スケールX倍率 1.0 の場合 -> 位置変わらず、スケールも変わらず スケールX倍率 2.0 の場合 -> 位置は変化する、スケールは2倍 これをどうやってHGIMG4で実装したらいいのだろうか? */ #module #include "hspmath.as" ; 3次元の距離を取得する関数 ; 対象のノード間の距離を取得する ; この関数も正確かどうかは自信がない ; u_id0 = ノードID ; u_id1 = ノードID #defcfunc dist3node var u_id0, var u_id1 getpos u_id0, x0, y0, z0 getpos u_id1, x1, y1, z1 xy0 = x0, y0 xy1 = x1, y1 yz0 = y0, z0 yz1 = y1, z1 zx0 = z0, x0 zx1 = z1, x1 return ( distance2(xy0,xy1) + distance2(yz0,yz1) + distance2(zx0,zx1) ) * 0.5 ; 基点からのsetscale命令をイメージした仮の命令 ; u_objID = スケール及びポジションを変更する対象のノード ; u_pivID = 基点のノード ; u_w = u_objIDの寸法の横幅 ; u_h = u_objIDの寸法の縦幅 ; u_d = u_objIDの寸法の奥行幅 ; u_x = スケールX倍率 ; u_y = スケールY倍率 ; u_z = スケールZ倍率 #deffunc pivOriginSetScale var u_objID, var u_pivID, double u_w, double u_h, double u_d, double u_x, double u_y, double u_z ; pivIDのposを取得 ; これが基点になる getpos u_pivID, px, py, pz ; 対象のノードのposを取得 getpos u_objID, tx, ty, tz w = u_w * u_x ; 実際の寸法の横幅(ケージ) h = u_h * u_y ; 実際の寸法の縦幅(ケージ) d = u_d * u_z ; 実際の寸法の奥行幅(ケージ) ; pivIDのposを原点にu_objIDのposを拡大分ズラす? ; ズラすためには、スケールの倍率の取得だけではなく、実際のオブジェクトの寸法の入力が必要? ; もしくは距離も使用する? ; (setposかaddposを使った何らかの処理?) ; スケールの拡大率は通常と同じ? setscale u_id, u_x, u_y, u_z return ; 基点からのsetang命令をイメージした仮の命令 ; u_objID = スケール及びポジションを変更する対象のノード ; u_pivID = 基点のノード ; u_x = 回転X倍率 ; u_y = 回転Y倍率 ; u_z = 回転Z倍率 #deffunc pivOriginSetRotate var u_objID, var u_pivID, double u_x, double u_y, double u_z ; pivIDのposとangを取得 ; これが基点になる getpos u_pivID, pPosX, pPosY, pPosZ getang u_pivID, pAngX, pAngY, pAngZ ; 対象のノードのposを取得 getpos u_objID, tPosX, tPosY, tPosZ getang u_objID, tAngX, tAngY, tAngZ ; 位置をcos()やsin()を角度で計算し、移動した上で、 ; 対象のノードのangをその回転分、回転させる? ; (sin()やcos()や距離取得関数を使った何らかの処理?) ; 処理の結果を設定する setpos u_objID, result_posX, result_posY, result_posZ setangZ u_objID, result_angX, result_angY, result_angZ return #global

おそらく、基点からの拡大縮小はスケールの拡大率は通常と同じで、
基点の位置と関係したなんらかのポジションの変更の処理が必要なのではないかと思いました。

基点からの回転の方は位置をcos()やsin()を角度で計算し、移動した上で、
対象のノードのangをその回転分、回転させるのだと思いました。

これらを、実際にスクリプトにしようとしてみると難しくて、
どうやればいいのかよく分かりませんでした。

距離関数については使うかどうか分からなかったのですが、
とりあえずdistance2の3次元版のようなものも添付したのですが、
これ自体も正しいアルゴリズムなのかどうかは自信がありません。

ぜひアドバイスお願い致します。



この記事に返信する


砂時 計

リンク

2021/10/30(Sat) 19:16:43|NO.94259

こんなイメージでしょうか。

※quaternion積ができたので再投稿。


#include "hgimg4.as" #module #deffunc _fvqmul array _dst, double _qx, double _qy, double _qz, double _qw, local _re, local _cv // _dst: 左の quaternion かつ結果を格納する // _qx, _qy, _qz, _qw: 右の quaternion _re = _dst.3 * _qw - _dst.0 * _qx - _dst.1 * _qy - _dst.2 * _qz ddim _cv, 3 fvset _cv, _dst.0, _dst.1, _dst.2 fvouter _cv, _qx, _qy, _qz fvadd _cv, _dst.0 * _qw + _qx * _dst.3, _dst.1 * _qw + _qy * _dst.3, _dst.2 * _qw + _qz * _dst.3 _dst.0 = _cv.0 _dst.1 = _cv.1 _dst.2 = _cv.2 _dst.3 = _re return #deffunc _rotxyz array _result, array _src, double _rx, double _ry, double _rz, local _cs, local _sn, local _tv2, local _tv3 // _result: 結果を書き出す先の 3要素のdouble配列 // _src: 回転される方向ベクトル 3要素のdouble配列 // _rx, _ry, _rz: getang と一致するオイラー回転 [rad] _cs = cos(_rx) // X回転 _sn = sin(_rx) ddim _tv2, 3 _tv2.0 = _src.0 _tv2.1 = _src.1 * _cs - _src.2 * _sn _tv2.2 = _src.1 * _sn + _src.2 * _cs _cs = cos(_ry) // Y回転 _sn = sin(_ry) ddim _tv3, 3 _tv3.0 = _tv2.0 * _cs + _tv2.2 * _sn _tv3.1 = _tv2.1 _tv3.2 = - _tv2.0 * _sn + _tv2.2 * _cs _cs = cos(_rz) // Z回転 _sn = sin(_rz) _result.0 = _tv3.0 * _cs - _tv3.1 * _sn _result.1 = _tv3.0 * _sn + _tv3.1 * _cs _result.2 = _tv3.2 return #deffunc pivOriginSetRotate int u_objID, int u_pivID, double u_x, double u_y, double u_z ; pivIDのposとangを取得 ; これが基点になる getpos u_pivID, pPosX, pPosY, pPosZ getang u_pivID, pAngX, pAngY, pAngZ getquat u_pivID, pqx, pqy, pqz, pqw ; 対象のノードのposを取得 getpos u_objID, tPosX, tPosY, tPosZ getang u_objID, tAngX, tAngY, tAngZ getquat u_objID, tqx, tqy, tqz, tqw ddim tv, 3 fvset tv, tPosX, tPosY, tPosZ fvsub tv, pPosX, pPosY, pPosZ // 基点の分引く ddim v, 3 _rotxyz v, tv, pAngX, pAngY, pAngZ // 回転する fvmul v, u_x, u_y, u_z // スケール反映する fvadd v, pPosX, pPosY, pPosZ // 基点の分足して戻す result_posX = v.0 result_posY = v.1 result_posZ = v.2 // quaternion 積 ddim q, 4 q.0 = pqx q.1 = pqy q.2 = pqz q.3 = pqw _fvqmul q, tqx, tqy, tqz, tqw ; 処理の結果を設定する setpos u_objID, result_posX, result_posY, result_posZ setquat u_objID, q.0, q.1, q.2, q.3 return #global randomize gpreset setcls CLSMODE_SOLID, 0x404040 setpos GPOBJ_CAMERA, 1,1,12 gplookat GPOBJ_CAMERA, 0,0,0 gpfloor floorid, 10,10, 0x333333 // zx 平面 gpbox id, 0.1, 0xffffff // 原点 dim ids, 3 gpbox idleft, 0.2, 0xff0000 setpos idleft, -1.0, 0.0, 0 setang idleft, 0,0,0 gpbox idcenter, 0.2, 0x00ff00 setpos idcenter, 0,0,0 setang idcenter, 0,0, M_PI * 45.0 / 180.0 gpload idright, "res/tamane2" setscale idright, 0.01, 0.01, 0.01 setpos idright, 1,0,0 setang idright, 0, M_PI * double(rnd(360)) / 180.0, 0 ids.0 = idleft ids.1 = idcenter ids.2 = idright gpbox pivid, 0.5, 0xffffff // 基点と回転量のためのオブジェクト setpos pivid, -1,0,0 setang pivid, 0,0, M_PI * double(rnd(90)) / 180 setalpha pivid, 32 repeat 3 pivOriginSetRotate ids.cnt, pivid, 2,2,2 loop // pivid に対して回転と拡大移動を適用 repeat redraw 0 gpdraw redraw 1 await 1000/60 loop



youdai

リンク

2021/10/31(Sun) 16:07:53|NO.94268

アドバイスありがとうございます。
大変参考になりました。

回転精度についてですが、


; 処理の結果を設定する setpos u_objID, result_posX, result_posY, result_posZ setangZ u_objID, result_angX, result_angY, result_angZ ; setangからsetangZに変更

こうするとイメージ通りの回転になると思いました。
この時重要なのは、


; 確認のため、値はすこし変えてあります gpbox pivid, 1, 0xffffff // 基点と回転量のためのオブジェクト setpos pivid, 0.0, 0.0, 0.0 setangZ pivid, -m_pi * 0.25, 0.0, -m_pi * 0.25 ; setangからsetangZに変更 setalpha pivid, 32

このように、基点となるpivid側のangもsetangZに変更することでした。
大変勉強になりました。
ありがとうございました!



記事削除

記事NO.パスワード
(質問が解決したスレッドは他の利用者に活用してもらうため、削除しないようお願いします)

NO.94254への返信

マスコット

好きなマスコットを選んでください。

名前

e-mail
HOME
  1. 初めて利用する方は、HSP3掲示板の使い方をお読みください。
  2. 不要部分の多い長いスクリプトの投稿は ご遠慮ください。
  3. 書き込みは自動改行されません。適度に改行を入れてください。
  4. スクリプトは小文字の<pre>〜</pre>で囲むと見やすく表示できます。

削除用パスワード

解決したら質問者本人がここをチェックしてください。

エラー発生時、再送信すると二重送信になることがあります。
回答が得られたら、お礼書き込み時に[解決]チェックしてください。
SPAM防止のためURLから始まる文章は投稿できません。
SPAM防止のため英文字のみの本文を投稿することはできません。

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