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


HSPTV!掲示板


未解決 解決 停止 削除要請

2023
0502
buhioひらめいた、、!子ノードのgetpos問題12解決


buhio

リンク

2023/5/2(Tue) 15:05:32|NO.99368

/*
gpnodeinfoで取得できる子ノードに対するgetposは、カメラの位置姿勢が考慮されない座標を返すという問題があり、
そのままでは扱えない問題がありました。
 GENKIさんのホームページ(https://mclab.uunyan.com/lab/hgimg4/hgimg4_011.htm)を見ていて、
gpcnvaxis命令のモード2が使えるのではと思い、試してみました。
 下記コードはサンプル「tamane_tree」に、1行追加☆し、変数名を合わせて修正した☆だけです。
これで子ノードのワールド座標取得は、イケてんじゃね??🐽
*/

#include "hgimg4.as"
#include "mod_gputil.as"

; gpnodeinfo sample
; 珠音(たまね)3D modelのモデル階層を表示
; (mod_gputilモジュールのgptree_getを使用することで全階層を取得できます)
; 階層の一部(asi_L_)を取り出し座標を取得
;

title "HGIMG4 Test"

gpreset

setcls CLSMODE_SOLID, $404040
gpload id_model,"res/tamane2" ; モデル読み込み
sc = 0.01 ; モデルのスケール
setscale id_model, sc, sc, sc

gpfloor id_floor, 8,8, $00ffff ; 床ノードを追加

gpbox id_box, 0.2

setpos GPOBJ_CAMERA, 0,1,5 ; カメラ位置を設定

gpact id_model

button "TREE",*view_tree
nodename = "asi_L_"
infonode = 0
x=0.0:y=0.0:z=0.0
*main
stick key,15
if key&128 : end

redraw 0 ; 描画開始

; カーソルキーでカメラ位置を動かす
if key&1 : addpos GPOBJ_CAMERA, -0.2, 0
if key&4 : addpos GPOBJ_CAMERA, 0.2, 0
if key&8 : addpos GPOBJ_CAMERA, 0, 0 , 0.2
if key&2 : addpos GPOBJ_CAMERA, 0, 0 , -0.2

gplookat GPOBJ_CAMERA, 0,1.2,0 ; カメラから指定した座標を見る

;addang id_model,0,0.02 ; ノード回転
gpdraw ; シーンの描画

; 特定の階層をノードとして取り出す
gpnodeinfo infonode,id_model, GPNODEINFO_NODE, nodename
if infonode>0 {
getpos infonode,x,y,z
gpcnvaxis dx,dy,dz, x,y,z, 2     //←この行を追加☆モード2
setpos id_box,dx*sc,dy*sc,dz*sc   //x,y,zをdx,dy,dzに変更☆
color 255,255,255
pos 80,0:mes nodename+"("+x+","+y+","+z+")"
}

redraw 1 ; 描画終了
await 1000/60 ; 待ち時間

goto *main

*view_tree
sdim s1,256
gptree_get s1,id_model
dialog s1
goto *main



この記事に返信する


buhio

リンク

2023/5/2(Tue) 15:21:24|NO.99369

あ、回転させたらダメだな、、、ゴメンご



buhio

リンク

2023/5/2(Tue) 15:34:37|NO.99370

//修正版 これでどうじゃ
//結局、ユーザー関数が必要かな。。でもだいぶ簡略になったかな。
//お騒がせしました。。仕事しよ

#include "hgimg4.as"
#include "mod_gputil.as"

; gpnodeinfo sample
; 珠音(たまね)3D modelのモデル階層を表示
; (mod_gputilモジュールのgptree_getを使用することで全階層を取得できます)
; 階層の一部(asi_L_)を取り出し座標を取得
;

title "HGIMG4 Test"

gpreset

setcls CLSMODE_SOLID, $404040
gpload id_model,"res/tamane2" ; モデル読み込み
sc = 0.01 ; モデルのスケール
setscale id_model, sc, sc, sc

gpfloor id_floor, 8,8, $00ffff ; 床ノードを追加

gpbox id_box, 0.2

setpos GPOBJ_CAMERA, 0,1,5 ; カメラ位置を設定

gpact id_model

button "TREE",*view_tree
nodename = "asi_L_"
infonode = 0
x=0.0:y=0.0:z=0.0
*main
stick key,15
if key&128 : end

redraw 0 ; 描画開始

; カーソルキーでカメラ位置を動かす
if key&1 : addpos GPOBJ_CAMERA, -0.2, 0
if key&4 : addpos GPOBJ_CAMERA, 0.2, 0
if key&8 : addpos GPOBJ_CAMERA, 0, 0 , 0.2
if key&2 : addpos GPOBJ_CAMERA, 0, 0 , -0.2

gplookat GPOBJ_CAMERA, 0,1.2,0 ; カメラから指定した座標を見る

addang id_model,0,0.02 ; ノード回転
gpdraw ; シーンの描画

; 特定の階層をノードとして取り出す
gpnodeinfo infonode,id_model, GPNODEINFO_NODE, nodename
if infonode>0 {
getpos infonode,x,y,z
gpcnvaxis dx,dy,dz, x,y,z, 2//←この行を追加★
quatlocal id_model,id_box,dx*sc,dy*sc,dz*sc//←このユーザー関数を追加★
//親オブジェクトの回転を適用してやる必要があった
;setpos id_box,dx*sc,dy*sc,dz*sc//コメントアウト★
getquat infonode,qx,qy,qz,qw
color 255,255,255
pos 80,0:mes nodename+"("+x+","+y+","+z+")"
mes "("+qx+","+qy+","+qz+","+qw+")"
}

redraw 1 ; 描画終了
await 1000/60 ; 待ち時間

goto *main

*view_tree
sdim s1,256
gptree_get s1,id_model
dialog s1
goto *main

;=====================クオータニオン関係関数==================
#deffunc QuatLocal int _id_parent,int _id_son,double _localx,double _localy,double _localz
//親モデルの姿勢に子モデルのローカル位置を適用するメソッド
getquat _id_parent,px,py,pz,pw
sx=_localx
sy=_localy
sz=_localz
sw=0
;ローカル位置の適用
QuatMul result_q,px,py,pz,pw,sx,sy,sz,sw
QuatMul result_q_2,result_q(0),result_q(1),result_q(2),result_q(3),-px,-py,-pz,pw;結果q×-親q(共役クオータニオン)
getpos _id_parent,px1,py1,pz1
setpos _id_son,result_q_2(0)+px1,result_q_2(1)+py1,result_q_2(2)+pz1;子の位置=結果q+親のワールド位置
setquat _id_son,px,py,pz,pw
return

#deffunc QuatMul array _q3,double _x,double _y,double _z,double _w,double _x2,double _y2,double _z2,double _w2
//クオータニオンの乗算
ddim q1,4
ddim q2,4
q1(0)=_x
q1(1)=_y
q1(2)=_z
q1(3)=_w
q2(0)=_x2
q2(1)=_y2
q2(2)=_z2
q2(3)=_w2
_q3(0)=0.0f
_q3(1)=0.0f
_q3(2)=0.0f
_q3(3)=0.0f

_q3(3)= q1(3) * q2(3) - q1(0) * q2(0) - q1(1) * q2(1) - q1(2) * q2(2)
_q3(0)= q1(1) * q2(2) - q1(2) * q2(1) + q1(3) * q2(0) + q1(0) * q2(3)
_q3(1)= q1(2) * q2(0) - q1(0) * q2(2) + q1(3) * q2(1) + q1(1) * q2(3)
_q3(2)= q1(0) * q2(1) - q1(1) * q2(0) + q1(3) * q2(2) + q1(2) * q2(3)
return



buhio

リンク

2023/5/2(Tue) 16:00:04|NO.99371

ワールドクオータニオンは、順番に親から計算しないと取得できないよねぇ?



buhio

リンク

2023/5/2(Tue) 22:28:08|NO.99373

/*
過去ログより
https://hsp.tv/play/pforum.php?mode=all&num=95343
...位置(pos)はビュー座標系かつモデルの位置と姿勢が0、スケールが1の時の位置として、
姿勢(quat)は各ボーンの親ボーンに対するローカル姿勢として、
それぞれ取得されてしまうため、座標変換が必要になります。
...
(引用ここまで)

上記のハシケムさんの回答で解決しているのですが、違ったアプローチで挑んでみました。
長くなってしまいすいません。せっかくできたので堪忍してください。
*/
#include "hgimg4.as"
;#include "mod_gputil.as";→改造版を使うので、コメントアウト

; gpnodeinfo sample
; 珠音(たまね)3D modelのモデル階層を表示
; (mod_gputilモジュールのgptree_getを使用することで全階層を取得できます)→今回は改造版を使用
; 階層の一部(asi_R_)を取り出し座標を取得
;

title "HGIMG4 Test"

gpreset

setcls CLSMODE_SOLID, $404040
gpload id_model,"res/tamane" ; モデル読み込み
sc = 0.01 ; モデルのスケール
setscale id_model, sc, sc, sc

gpfloor id_floor, 8,8, $00ffff ; 床ノードを追加

gpbox id_box, 0.2,$ff0000 ;★赤い色でボックス作成
setscale id_box,1.0,1.0,2.0 ;★分かりやすいようにBOXをZ軸に拡大

setpos GPOBJ_CAMERA, 0,1,5 ; カメラ位置を設定

gpact id_model
gpsetanim id_model,0,GPANIM_OPT_SPEED,30 ;★分かりやすいようにアニメスピードを30%に減速

button "TREE",*view_tree
nodename = "asi_R_"
infonode = 0
x=0.0:y=0.0:z=0.0

; モデル構造の取得
sdim s1
gptree_get s1,id_model ;★(改造版)階層構造文字列取得(行番号,階層深度,ノード名,親の行番号\n...)
QuatTree list,s1 ;★(ユーザー関数)階層全体の配列(一つの2次元配列に変換)
QuatList qlist,nodename,list;★(ユーザー関数)指定ノードの親クオータニオン計算順序リスト(指定したノードのルートノードからの計算順序)

*main
stick key,15
if key&128 : end

redraw 0 ; 描画開始

; カーソルキーでカメラ位置を動かす
if key&1 : addpos GPOBJ_CAMERA, -0.2, 0
if key&4 : addpos GPOBJ_CAMERA, 0.2, 0
if key&8 : addpos GPOBJ_CAMERA, 0, 0 , 0.2
if key&2 : addpos GPOBJ_CAMERA, 0, 0 , -0.2

gplookat GPOBJ_CAMERA, 0,1.2,0 ; カメラから指定した座標を見る

addang id_model,0.0,0.02,0.0 ; ★親モデルを回転しても大丈夫なのを確認
addpos id_model,0.0,0.00,-0.001 ; ★親モデルを移動しても大丈夫なのを確認

gpdraw GPDRAW_OPT_OBJUPDATE ; ★シーンの描画(アニメーションを実行)
; まず自動移動やアニメーションを実行させないと、getposやsetposが、表示上1フレーム遅れることになる
; カメラで追従したらよくわかる(今回のサンプルでは気にしなくてもOK)

; 特定の階層をノードとして取り出す
gpnodeinfo infonode,id_model, GPNODEINFO_NODE, nodename
if infonode>0 {


;子ノードの位置を取得=========
getpos infonode,x,y,z //★getposでは、ビュー座標系の座標が返る(スケール1,親の位置0)
gpcnvaxis dx,dy,dz, x,y,z, 2 //★この行を追加→ここでビュー変換→親モデルから見たローカル座標が計算できたといえる
QuatLocalPos id_model,id_box,dx*sc,dy*sc,dz*sc //★このユーザー関数を追加
//★親オブジェクトの回転を適用してやる必要がある
//setpos id_box,dx*sc,dy*sc,dz*sc //★コメントアウト
;=============================

;子ノードの姿勢を取得=========
QuatMulX q,id_model,qlist //★先に作っておいた指定ノード計算順序配列qlistからワールドクオータニオンを計算
setquat id_box,q(0),q(1),q(2),q(3)
;==============================

}
gpdraw GPDRAW_OPT_DRAWSCENE ; ★全シーンの描画(3Dシーン)
redraw 1 ; 描画終了
await 1000/60 ; 待ち時間

goto *main

*view_tree
sdim s1,256
gptree_get s1,id_model
dialog s1
goto *main

;=====================クオータニオン関係関数====================
;===============================================================
;クオータニオンの乗算
#deffunc QuatMul array _q3,double _x,double _y,double _z,double _w,double _x2,double _y2,double _z2,double _w2

ddim q1,4
ddim q2,4
q1(0)=_x
q1(1)=_y
q1(2)=_z
q1(3)=_w
q2(0)=_x2
q2(1)=_y2
q2(2)=_z2
q2(3)=_w2
_q3(0)=0.0f
_q3(1)=0.0f
_q3(2)=0.0f
_q3(3)=0.0f

_q3(3)= q1(3) * q2(3) - q1(0) * q2(0) - q1(1) * q2(1) - q1(2) * q2(2)
_q3(0)= q1(1) * q2(2) - q1(2) * q2(1) + q1(3) * q2(0) + q1(0) * q2(3)
_q3(1)= q1(2) * q2(0) - q1(0) * q2(2) + q1(3) * q2(1) + q1(1) * q2(3)
_q3(2)= q1(0) * q2(1) - q1(1) * q2(0) + q1(3) * q2(2) + q1(2) * q2(3)
return
;===============================================================
;親モデルの姿勢に子モデルのローカル位置を適用する
#deffunc QuatLocalPos int _id_parent,int _id_son,double _localx,double _localy,double _localz

getquat _id_parent,px,py,pz,pw
sx=_localx
sy=_localy
sz=_localz
sw=0

//ローカル位置の適用計算
QuatMul result_q,px,py,pz,pw,sx,sy,sz,sw
QuatMul result_q_2,result_q(0),result_q(1),result_q(2),result_q(3),-px,-py,-pz,pw ;結果q×-親q(共役クオータニオン)
getpos _id_parent,px1,py1,pz1
setpos _id_son,result_q_2(0)+px1,result_q_2(1)+py1,result_q_2(2)+pz1 ;子の位置=結果q+親のワールド位置

return
;===============================================================
;文字列から階層構造の配列を作成
#deffunc QuatTree array _objlist,array _s1

sdim result1
sdim result2,1,4

split _s1,"\n",result1
sdim _objlist,50,stat,3

n=length(result1)-1
repeat n
i=cnt
split result1(cnt),",",result2
_objlist(i,0)=result2(1);階層深度
_objlist(i,1)=result2(2);ノード名称
_objlist(i,2)=result2(3);親番号

loop

return
;===============================================================
;階層構造の配列から親ノードから指定子ノードへの計算順序配列を作成
#deffunc QuatList array _qlist,str _name,array _list

foreach _list
if _list(cnt,1)=_name:id_son=cnt:break
loop

_lv=int(_list(id_son,0))
sdim _qlist,50,_lv
repeat _lv+1;深度+1

_qlist(_lv-cnt)=str(_list(int(id_son),1));ノード名を保存
id_son=_list(int(id_son),2);親ノードに切替

loop

return
;===============================================================
;計算順序リストに従ってクオータニオンを乗算してワールド姿勢を計算
#deffunc QuatMulX array _q,int _id_parent,array _bone_list
getquat _id_parent,px,py,pz,pw
_q_(0)=0.0f
_q_(1)=0.0f
_q_(2)=0.0f
_q_(3)=-1.0f

foreach _bone_list

;cnt(0)→親ボーンから順番にクオータニオンを乗算
gpnodeinfo _infonode,_id_parent, GPNODEINFO_NODE,_bone_list(cnt)
getquat _infonode,x,y,z,w
quatmul _q_,_q_(0),_q_(1),_q_(2),_q_(3),x,y,z,w

loop

quatmul _q_,px,py,pz,pw,_q_(0),_q_(1),_q_(2),_q_(3);最後に親のクオータニオンを乗算

_q(0)=_q_(0)
_q(1)=_q_(1)
_q(2)=_q_(2)
_q(3)=_q_(3)
return

;===================================================
; utility header for HGIMG4(改造版)R5.5.2
;改造の理由
;元の階層取得関数gptree_getは、ボーンのツリーが、関連付いたメッシュの子ボーンとして複数回表示されてしまうので、
;ボーンツリーは、1回しか取得されないように改変
;各ボーンの親ノードを取得保存すると同時に階層深度を記録する様に改変。あとで再利用しやすいように。
;===================================================
#ifndef __posthsp3gp__
#define __posthsp3gp__

#module "utilhsp3gp"
#deffunc gptree_init int _p1

sdim buf,$1000
objid = _p1

sdim bone_list,$1000//追加
pname="" //追加
count=0 //追加
rename="" //追加

return
#deffunc gptree_get var _p1, int _p2

gptree_init _p2

//メッシュリストのツリー作成
gptree_getsub "",0

//ボーンのツリー作成
split bone_list,"\n",results
repeat stat-1
gptree_getsub results(cnt),0,count
loop

_p1=buf

return

#deffunc gptree_getsub str _p1, int _p2,int _p3,local child ,local child_id

buf+=""+count+"," //追加
count++ //追加
child_id=_p3

buf+=""+_p2+"," //追加

buf+=_p1+","+pname+"\n" //追加

child=""
gpnodeinfo child,objid,GPNODEINFO_CHILD, _p1

repeat
pname=""+_p3 //追加
pid=child_id
if child="" : break

gptree_getsub child,_p2+1,count
gpnodeinfo child,objid,GPNODEINFO_SIBLING, child

loop

child=""
gpnodeinfo child,objid,GPNODEINFO_SKINROOT, _p1

if child!="" { //追加
if str(rename)!=child{ //追加

bone_list+=child+"\n"
;gptree_getsub child,_p2+1//ボーンのツリーは別で作成
rename=child //追加
} //追加

}

return

#global

#endif



usagi

リンク

2023/5/4(Thu) 13:50:26|NO.99385

おぉ、これ面白いですね。buhioさんのを参考に私もやってみました。
確かにgpconvaxisでかなり制御が楽になるのではないでしょうか。

#include "hgimg4.as" chdir dir_exe+"\\sample\\hgimg4" ; 初期化 gpreset : setcls CLSMODE_SOLID, $404040 gpload id_model, "res/tamane2" : gpact id_model nodes = "chest","head","hip","kata_L_","ude_L_","momo_L_","asi_L_","kata_R_","ude_R_","momo_R_","asi_R_" ; 床ノードを追加 gpfloor id_floor, 300,300, $00ffff ; ノード座標表示用 gpcolormat mat, $FF0000, 8 foreach nodes: gpbox id_nodes(cnt),10,,mat: loop ;-------------------- *main ; カメラ setpos GPOBJ_CAMERA, (ginfo_winx/2-mousex)/4, 100, 400 ; モデル 移動と回転、スケール setpos id_model,sin(delta)*100,,cos(delta)*100 : setang id_model,,delta+1.57 sc = (cos(delta)+1)/2+0.5 : setscale id_model, sc, sc, sc ; ノード達 foreach nodes ; ★ココから gpnodeinfo infonode, id_model, GPNODEINFO_NODE, nodes(cnt) : if infonode<=0 : continue ; 親の座標,角度,スケール取得 getpos id_model, p_px,p_py,p_pz : getang id_model, p_ax, p_ay, p_az : getscale id_model, p_sx, p_sy, p_sz ; ノード(ボーン)の座標,角度取得。▲そしてビューの逆行列をノード座標に反映(getposが影響を受けるので、という事?) getpos infonode, px, py, pz : getang infonode, ax, ay, az gpcnvaxis px,py,pz, px,py,pz, 2 : px*=p_sx: py*=p_sy: pz*=p_sy fvset fv, -p_ax,-p_ay,-p_az : fvdir fv, px,py,pz ; 親の座標,角度を反映 setpos id_nodes(cnt), p_px,p_py,p_pz : addpos id_nodes(cnt), fv.0,fv.1,fv.2 setang id_nodes(cnt), p_ax,p_ay,p_az : addang id_nodes(cnt), ax,ay,az ; ★ココまで loop ; 描画 gpdraw : color 255,255,255 foreach nodes: getpos id_nodes(cnt), x,y,z: gpcnvaxis x,y,z,x,y,z: pos x-strlen(nodes(cnt))*4,y-32: mes nodes(cnt),4: loop redraw 1: await 16: redraw 0: delta = 0.01+delta goto *main
ただ、getposの結果がモデルと特殊なノードで座標が変わるというのは、
もしかしたら不具合なのか、gpnodeinfoでの特殊なノードの時のgetposのオプションなどあるともっと使いやすくなるのかもしれませんね。



buhio

リンク

2023/5/4(Thu) 19:33:23|NO.99394

usagiさん
なんで、、こんなに短いコードになるんでしょうか!!!!??

 すごい〜。ありがとうございます(^^♪宿題が増えた気分です。。。
いつも参考になります🐖



usagi

リンク

2023/5/4(Thu) 23:02:43|NO.99397

>なんで、、こんなに短いコードになるんでしょうか!!!!??
いえいえgpcnvaxis使ったことなかったので、buhioさんのアイデアを見て触発されました。

もしあるとすれば、ループでまとめてしまったのと、
座標と角度は一度ノードの座標に親をセットして子を加算してるからでしょうか。
(また、今回はシンプルにクォータニオン使ってないので)
何か参考になったのであれば幸いです。

あと、余談でこの手のデバックは軸が分からないとやりにくくて、
hgimg4に直接3D描画命令が無いのですが、gpcnvaxisで簡易的に出来そうですね。
(Zバッファは考慮されませんが。。。)


#include "hgimg4.as" chdir dir_exe+"\\sample\\hgimg4" ; 軸描画モジュール(簡易) ;-------------------- #module #deffunc gbdline double a_x1, double a_y1, double a_z1, double a_x2, double a_y2, double a_z2 gpcnvaxis x1,y1,z1, a_x1,a_y1,a_z1 : gpcnvaxis x2,y2,z2, a_x2,a_y2,a_z2 line x1,y1, x2,y2 return #define global gpdaxis(%1,%2=10) _gpdaxis %1,%2 #deffunc _gpdaxis int a_id, int a_len getpos a_id, px, py, pz: getang a_id, ax, ay, az repeat 3 fvset fv, -ax,-ay,-az if cnt=2 : fvdir fv, a_len : goto *@forward if cnt=1 : fvdir fv, ,a_len : goto *@forward if cnt=0 : fvdir fv, ,,a_len *@ fvadd fv, px,py,pz rgbcolor $FF<<cnt*8 gbdline px, py, pz, fv.0,fv.1,fv.2 loop return #global gpreset : setcls CLSMODE_SOLID, $404040 gpload id_model, "res/tamane2" : gpact id_model nodes = "chest","head","hip","kata_L_","ude_L_","momo_L_","asi_L_","kata_R_","ude_R_","momo_R_","asi_R_" ; ノード座標表示用 foreach nodes: gpnull id_nodes(cnt): loop ;-------------------- *main setpos GPOBJ_CAMERA,,100, 400 setang id_model,,delta+1.57 ; ノード達 foreach nodes gpnodeinfo infonode, id_model, GPNODEINFO_NODE, nodes(cnt) : if infonode<=0 : continue getpos id_model, p_px,p_py,p_pz : getang id_model, p_ax, p_ay, p_az : getscale id_model, p_sx, p_sy, p_sz getpos infonode, px, py, pz : getang infonode, ax, ay, az gpcnvaxis px,py,pz, px,py,pz, 2 : px*=p_sx: py*=p_sy: pz*=p_sy fvset fv, -p_ax,-p_ay,-p_az : fvdir fv, px,py,pz setpos id_nodes(cnt), p_px,p_py,p_pz : addpos id_nodes(cnt), fv.0,fv.1,fv.2 setang id_nodes(cnt), p_ax,p_ay,p_az : addang id_nodes(cnt), ax,ay,az loop ; 描画 gpdraw : color 255,255,255 foreach nodes: getpos id_nodes(cnt), x,y,z: gpcnvaxis x,y,z,x,y,z: pos x-strlen(nodes(cnt))*4,y-32: mes nodes(cnt),4: loop gpdaxis id_model: foreach nodes: gpdaxis id_nodes(cnt): loop redraw 1: await 16: redraw 0: delta = 0.01+delta goto *main

位置とか角度の確認、皆さんはどうされてるんですかね。(もしかして機能あったりして)



buhio

リンク

2023/5/5(Fri) 00:20:39|NO.99398

ちょっと待った。。。
もしかして、、子ノードへのgetangは、ワールド回転が取得されるのか??
getquatはローカル回転で、getangはワールド回転なのか??
getang infonode, ax, ay, az

addang id_nodes(cnt), ax,ay,az

これはそういう事ですよね??
今までの苦労が、、、、気づかなかった。。。



usagi

リンク

2023/5/5(Fri) 03:20:28|NO.99400

おそらく、ローカル回転で合ってると思いますよ。
よくある親子関係の計算で、”親+子=子の最終結果”としました。
親が右90度で子が右90度回っていれば、子の最終結果は右180度(後ろ向き)という感じです。

setang id_nodes(cnt), p_ax,p_ay,p_az ; ここで親(モデル)の角度をノード表示用へセット
addang id_nodes(cnt), ax,ay,az ; ここで子(ノード)の角度をノード表示用へ加算

補完や軸に対しての回転、ある方向を向かせたい場合はクォータニオンは便利ですが、
今回はアニメーションされているノードの方向が知りたいだけだったのでオイラー角で指定してみました。

buhioさんも自前で実装してますが、クォータニオンが使えた方がやれる事が増えるのでhgimg4のに算術系の命令が増えるといいですねぇ。。。
(quatset, quatmulみたいな感じで。 あと内部的にはあると思うので、getmtxみたいな感じでいろいろ行列が取得できれば)



buhio

リンク

2023/5/5(Fri) 08:09:39|NO.99401

混乱してきましたが、こういう違いがあるような気がしています。

gpnpdeinfoによるオブジェクトidに対する

getpos ルートノードに対する相対位置(ビュー変換されたもの)→親モデル姿勢でワールド座標に変換できる
getquat 直接の親ノードに対するローカル姿勢→ルートから順番に計算してさらに親モデル姿勢でワールド姿勢
getang ルートノードに対する相対角度→親モデル姿勢を加えればワールド姿勢に
getscale ルートノードに対する各ノードのスケール


setpos 直接の親ノードに対するローカル座標を設定
setquat 直接の親ノードに対するローカル姿勢を設定
setang ルートノードに対する相対角度を設定
setscale ルートノードに対する各ノードのスケール

addpos 機能しない
adang 機能しない
addscale 機能しない



usagi

リンク

2023/5/5(Fri) 15:35:55|NO.99403

>getang ルートノードに対する相対角度→親モデル姿勢を加えればワールド姿勢に
混乱させてすみません。たぶん同じ意味合いだと思うのですが、
親から見た相対的な値としてローカルと書きました。(今回の場合はモデル)
私のはノード同士の親子関係無視してましたね。。。(tamaneサンプルでは座標を割り出すのに必要なかった為)

深く検証できてないですが、クォータニオンに置き換えても結果は同じだったので、
angでもquatでも取得できるものは同じで、オイラー角かクォータニオンかの違いだけだと思いました。※下記検証

ですから、正しい姿勢の角度を出すにはおっしゃられている
"直接の親ノードに対するローカル姿勢→ルート..."というのがどちらも正しいのかもしれません。※未検証

しつれいしました。

gpnpdeinfoによるオブジェクトidに対するゲッター、セッターのマニュアルが欲しいですねぇ。

#include "hgimg4.as" chdir dir_exe+"\\sample\\hgimg4" ; 初期化 gpreset : setcls CLSMODE_SOLID, $404040 gpload id_model, "res/tamane2" : gpact id_model nodes = "chest","head","hip","kata_L_","ude_L_","momo_L_","asi_L_","kata_R_","ude_R_","momo_R_","asi_R_" ; 床ノードを追加 gpfloor id_floor, 300,300, $00ffff ; ノード座標表示用 gpcolormat mat, $FF0000, 8 foreach nodes: gpbox id_nodes(cnt),10,,mat: loop ;-------------------- *main ; カメラ setpos GPOBJ_CAMERA, (ginfo_winx/2-mousex)/4, 100, 400 ; モデル 移動と回転、スケール setpos id_model,sin(delta)*100,,cos(delta)*100 : setang id_model,,delta+1.57 sc = (cos(delta)+1)/2+0.5 : setscale id_model, sc, sc, sc ; ノード達 foreach nodes gpnodeinfo infonode, id_model, GPNODEINFO_NODE, nodes(cnt) : if infonode<=0 : continue ; 親の座標,角度,スケール取得 getpos id_model, p_px,p_py,p_pz : getang id_model, p_ax, p_ay, p_az : getscale id_model, p_sx, p_sy, p_sz getquat id_model, p_qx,p_qy,p_qz,p_qw; ★クォータニオンで角度取得 ; ノード(ボーン)の座標,角度取得 getpos infonode, px, py, pz : getang infonode, ax, ay, az getquat infonode, qx,qy,qz,qw; ★クォータニオンで角度取得 gpcnvaxis px,py,pz, px,py,pz, 2 : px*=p_sx: py*=p_sy: pz*=p_sy ;fvset fv, -p_ax,-p_ay,-p_az : fvdir fv, px,py,pz ; 親の座標,角度を反映 q1 = p_qx,p_qy,p_qz,p_qw : q2 = px,py,pz,0.0 : qtmul q, q1, q2 q1 = q.0,q.1,q.2,q.3 : q2 = -p_qx,-p_qy,-p_qz,p_qw : qtmul q, q1, q2 q.0+=p_px: q.1+=p_py: q.2+=p_pz setpos id_nodes(cnt), q.0,q.1,q.2; ★クォータニオンで位置設定 q1 = p_qx,p_qy,p_qz,p_qw : q2 = qx,qy,qz,qw : qtmul q, q1, q2 setquat id_nodes(cnt), q.0,q.1,q.2,q.3; ★クォータニオンで角度設定 ;setpos id_nodes(cnt), p_px,p_py,p_pz : addpos id_nodes(cnt), fv.0,fv.1,fv.2 ;setang id_nodes(cnt), p_ax,p_ay,p_az : addang id_nodes(cnt), ax,ay,az loop ; 描画 gpdraw : color 255,255,255 foreach nodes: getpos id_nodes(cnt), x,y,z: gpcnvaxis x,y,z,x,y,z: pos x-strlen(nodes(cnt))*4,y-32: mes nodes(cnt),4: loop redraw 1: await 16: redraw 0: delta = 0.01+delta goto *main ; クォータニオンモジュール ;-------------------- #module #deffunc qtset array q, double x, double y, double z, double w _r = w / 2 : _s = sin(_r) : q.0 = x*_s : q.1 = y*_s : q.2 = z*_sin : q.3 = cos(_r) return #deffunc qtmul array q, array q1, array q2 q.0 = q1.3*q2.0 + q2.3*q1.0 + q1.1*q2.2 - q1.2*q2.1 q.1 = q1.3*q2.1 + q2.3*q1.1 - q1.0*q2.2 + q1.2*q2.0 q.2 = q1.3*q2.2 + q2.3*q1.2 + q1.0*q2.1 - q1.1*q2.0 q.3 = q1.3*q2.3 - q1.0*q2.0 - q1.1*q2.1 - q1.2*q2.2 return #global



buhio

リンク

2023/5/7(Sun) 09:13:49|NO.99410

検証ありがとうございました。
やはり姿勢は一発では取得できないんですね。
fvset、fvdir、座標の描画、ボーンのメッシュ描画(別スレ)等、大変参考になり、
自身のスクリプトへ組み込んでいきたいと思います。
ありがとうございます。

ノードのワールド座標を取得する命令(自分用のまとめメモ)


#deffunc getposW array _vec,_id_model,str _nodename ;ノードのgetposをビュー変換 gpnodeinfo infonode, _id_model, GPNODEINFO_NODE,_nodename getpos infonode, px, py, pz gpcnvaxis px,py,pz, px, py, pz, 2 ;親モデルのposとscaleを取得 getpos _id_model, p_px, p_py, p_pz getscale _id_model, p_sx, p_sy, p_sz ;親モデルのスケールと姿勢を反映した位置を計算 px*=p_sx: py*=p_sy: pz*=p_sy fvset fv, -p_ax,-p_ay,-p_az fvdir fv, px,py,pz _vec(0)=p_px+fv(0) _vec(1)=p_py+fv(1) _vec(2)=p_pz+fv(2) return

;親モデルのgetposとgetscaleは全ノードで共用できるので外に出すほうが良い場合もある。



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