2008年08月

2008年08月29日

スキン・モディファイヤのウェイト値を書き出したり読み込んだり 3ds max 2008

雨ヤバス・・・((((;゚д゚)))ガクガクブルブル

太平洋側から吹き上がってくる水分をたっぷり含んだ果てしない空気の流れが、関東地方全体に凄まじい集中豪雨を発生させているな。台風も日本近海の海で発生するようになって来たし、もう気候は亜熱帯なのかも・・・。浸水に備えてポンプくらい買っとこうかなぁ・・・。このサイトを見ると雨の様子がわかるよ。これにかからないくらいのゲリラ集中豪雨も多発してるけどね。

東京アメッシュ
http://tokyo-ame.jwa.or.jp/index.html

以前に紹介した地震のコピペの茨城の群発地震は未だに頻発しているし、地震が先か、洪水が先かって感じだなぁ。地震はかなり迫っている感があるので地震保険に加入する事にしたよ。火災保険に入っていても、地震の後の火事なんかは地震保険に入ってないとダメらしいな。

さて、まだmaxの作法が今ひとつ分らないせいか、ちょっとウェイトマップの調節をするのにも、四苦八苦している。エンベロープの調整まではいいんだけどね。そこで思い切ってウェイトマップを外部に書き出して、慣れ親しんだmodoに持ち込んで、modo側で変更してはmax側でデータを更新するような方法を採ってみようかと思う。面白い事にこういう方式でウェイトマップの調整をすると、maxとmodoでやり取りするのは単にウェイトマップの情報のみなので、modo側の方でウェイトマップが塗りやすいように自由に変形しちゃってもmax側のモデルには一切影響が出ない。新しいmodoでもこんなビューポートのモードを付けたら面白いかもね。そのビューポート内で行った変形はモデルの形状には一切影響を及ぼさないビューポートなんてね。現実の世界では耳の裏側とかを塗る時に絵筆を回り込ませるより耳を摘んでグニャってひっくり返すでしょ?あんな変形をするわけだ。そして終わったらワンタッチで元の形状に戻す。もちろんモーフマップを使えば似たような事が出来るけどね。でもマニュアルも読まないでそんなビューポートに出くわしたらびっくりするだろうね。せっかく変形しても元に戻っちゃうわけだしwww。

余談はさておき、まずは表題の通りスキンモディファイアにおける頂点のウェイト値をファイルとして書き出したり読み込んだり出来るようにしてみたよ。inport_weight.msとexport_weight.msがそれだ。

使い方はスキンモディファイアを設定してあるメッシュを選択してスクリプトを実行するだけ。例えば以下のようなモデルでやってみると、このメッシュを選択してexport_weight.msを実行すると、ファイル名を聞いて来るので、「test」とでも入力してOKを押せばデータファイルが作成される。

fig01

データのフォーマットは以下の通り。

スキンに登録されたボーンの数
ボーンの名前1
ボーンの名前2
    :
ポイントの数
ポイント番号,影響を与えるボーンの数,ボーンID,ウェイト値,ボーンID,ウェイト値、・・・
ポイント番号,影響を与えるボーンの数,ボーンID,ウェイト値,ボーンID,ウェイト値、・・・
       :

今のところimport_weight.msで読み込む時にボーンの名前は読み飛ばしちゃっているよ。書き出されたファイルはテキストファイルなのでエディタ等で直接書き換え可能だ。下の画像の37〜45の部分のウェイト値を変更してみよう。

注目ポイント

これがそのデータ。先頭がポイント番号だから37〜45の付近を書き換えてみる。

export

オリジナルのデータだと、このポイントに干渉するボーンは2本あって、そのボーンのIDは2と3。例えば37番のポイントのウェイトの状態は、ボーン2が0.501898のウェイト値を持ち、3が0.498102のウェイト値を持っている。これを以下のように書き換えてみた。

修正

ポイントは交互にボーン1か5の影響を100%受ける。データの意味を書くとこんな感じ。

ポイントID:37,影響ボーンの数:1、ボーンID:1、weight値:1.0
ポイントID:38,影響ボーンの数:1、ボーンID:5、weight値:1.0
                                    :

これを再び今度はimport_weight.msを使ってスキンにメッシュに読み戻す。下の画像はその結果。黄色い矢印で示した問題の部分は、import前にはBone01とBone05の干渉は受けていなかったのに、import後は隣どうし交互に1と5の影響が出ている。

インポート

リファレンスをあたっていたら、スキン関係はskinOpsという構造体にいろんなメソッドが入ったパッケージになっているようで、スキンのインスタンスに対して、

skinOPs.メソッド スキン パラメータ

という形式で操作が出来るようだ。そこでまず、

skinmod = $.modifiers[#Skin]

で現在選択しているオブジェクトのスキンモディファイアをskinmodに取得して、これに対していろいろな処理をする。以下は今回使ったメソッドのご紹介。

スキンに登録されているボーンの数を取得する

skinops.getnumberbones skinmod

n番目に登録されているボーンの名前を取得する

skinops.getbonename skinmod  n  1

スキンが適用されているポイントの数を取得する

skinops.getnumbervertices skinmod

そのポイントに影響を与えるボーンの数を取得する

skinops.getvertexweightcount skinmod ポイント番号

そのポイントにn番目に登録されているボーンの番号を取得する

skinops.getvertexweightboneid skinmod ポイント番号 n

そのポイントにn番目に登録されているボーンに対するweight値を取得する

skinops.getvertexweight skinmod ポイント番号 n

そのポイントのウェイト値を影響を与えるボーンの番号リストとそれに対応するウェイト値のリストを与えて一挙に変更する

skinOps.ReplaceVertexWeights skinmod ボーンの番号リスト ウェイト値のリスト

スクリプトはこんなメソッドを使って作ってあるよ。プログラムはアップしておいたよ。modoと連携して使う場合は出力するファイルは固定でいいかなぁ。更新のたびにファイル名指定してたら面倒だからね。modo側は次回ね。

それではまた来週。

maxまとめページ



take_z_ultima at 11:08|この記事のURLComments(0)TrackBack(0)3ds Max | CG

2008年08月28日

Ogreをmaxに渡して動かしてみたい(スカートのセットアップ) その11 modo 302 max2008

ようやくOrgeに戻ってきたよ。さて、多少のノウハウを吸収したので服のヒラヒラに適用してみる。

ヒラヒラの大きさに合わせてトップビューでボーンを1本描いて右クリックで止めてエンドボーン付きのボーンを1セット作る。

fig02

この時スナップfig01なんかを使うとポイントの位置あわせとかが早いかも。ボーンが出来たら根元にポイントを1つ追加して、名前を「root」にする。

fig03

そして大きい方のボーンを選択して、アニメーション→IKソルバ→HIソルバを選んでエンドボーンをクリックする。これでIKが設定されてゴールが表示される。ゴールのサイズを適当に調整しておく。

fig04

このゴールと大きい方のボーンは、さっき作った「root」ポイントにペアレントする。

fig05

次に膝関節の付近にポイントを1つ作り、名前を「target」にし、腿のボーンにペアレントする。

ターゲットを作成

ボーン全体のコントロール用に適当なオブジェクトを作る。ここでは作成パネルのシェイプから文字のボタンを押して下図のように「spring param」という文字オブジェクトを作ってみた。

fig08

これを選択して、アニメーション→パラメータ編集で、パラメータを追加する。パラメータタイプを選択して、UIタイプと名前、位置あわせを設定しては「追加」ボタンを押して追加していく。

fig06

結果は下の画像のようにモディファイアパネルに切り替えておけば表示される。

fig07

追加するパラメータは以下の通り。

パラメータタイプ UIタイプ 名前 既定値 位置合わせ
Float Spinner 12
Float Spinner 0.9
Float Spinner 0.03
Float Spinner offX 0.0
Float Spinner offY 0.0
Boolean CheckBox Enable - 中央

次にコントローラを設定する。IKのゴールを選択してアニメーション→位置コントローラ→スクリプトを選択。

fig09

次にモーションパネルのコントローラを割り当てロールアウトを開いて、「位置スクリプト」を探して右クリックでプロパティを選択する。

fig10

パネルが出たら「ロード」ボタンを押して「flare_motion.ms」を読み込む。

fig11

次に変数にコントローラとノードを割り当てる。

fig12

変数の割り当ては以下の通り。ノード割り当てとコントローラ割り当てがあるので注意してね。

fig13

出来たらrootポイントを選択して腰の辺りに配置する。この時操作するのはrootだけね。それからrootを回転する時は水平を保ったまま回転させてね。rootはBipedの腰のボーンにペアレントする。

fig17

次にIKのゴールを参照座標系を親にしておいて、ボーンの角度をヒラヒラにあわせるようにX−Z座標平面上で移動する。この時、モーションパネルの位置リストロールアウトのXYZ位置の方を選択してアクティブボタンを押すとゴールの移動が出来るようになるよ。

fig19

前にやった時にはこの方法では動かなくて、キーを打ってグラフエディタで動かしたんだけど、何故だか今回は移動ツールでちゃんと動く・・・。なんでだろう?

fig18

root、ボーンのチェーン、IKを選択してコピーし、ローカルのX軸が放射状に外を向くように配置する。

fig20

さらにこれらにターゲットを加えたものを選択して、一度にコピーすると、新たに作成されたターゲットを対象としたボーンのセットが生成される。

これで大雑把に配置が出来たので、スプリングのコントロール用のアートリビュートを仕込んだ文字のオブジェクトを選択して、モディファイアパネルを開くと、作成したアートリビュートが見える。EnableをONにすると、下の画像のようにボーンが反応するようになる。適当にアニメーションを付けて動かしながらパラメータをいじって挙動を調節する。

fig16

Orgeのデータは付けられないけど、Bipedのデータとロードするためのスクリプトファイルはアップしておいたよ。

それではまた次回。

maxまとめページ



take_z_ultima at 12:45|この記事のURLComments(0)TrackBack(0)3ds Max | modo

2008年08月27日

Bipedの足跡モードがアクティブに出来ない(´・ω・`) 3ds max 2008

暫くぶりにOrgeに戻ってヒラヒラに入れるボーンをセットアップしてみて、歩行アニメーションでテストしようとしたら、足跡モードのボタンが非アクティブになっていて押す事が出来ない。

fig07

この現象はBipedにフリーアニメーションを付けちゃうと発生するので、ワークフローとしては、足跡アニメを先に付けて、その中でフリーアニメーションの設定をする順番がオススメらしい。足跡アニメの中にはフリーアニメを入れられるけど、フリーアニメの中には歩行アニメは入れられないからだ。

そこで、Bipedに付けたキーをどんどん削除してみたんだけど、それでもボタンがアクティブにならない。何か残っちゃってるのかな?

途方に暮れて考えること数分。そう言えばスケマティックビューでFootstepsと書いてあるノードを見かけた事を思い出した。

fig01

さっそくスケマティックビューを開いてみると、やっぱりそこにあった。選択してみて気付いたのは、なんと非アクティブな状態の足跡ボタンが非アクティブな表示のままONになってる。

fig02

これはもしかして・・・と思って足跡を作成してみた。

fig04

残念ながら足跡は出てこなかった。でも諦めるのはまだ早い。よく見ると「非アクティブな足跡のキーを作成」ボタンがアクティブになっている。

fig05

ボタンを押してみると、Orgeが気を付けポーズになった。おーこれは・・・。

fig06

そして再生してみると、何も起こらない。あれ?

さらによーく調べてみたら、どうやら歩行アニメーションは現在シーンに設定されている時間範囲の外に作成されたみたいだ。さっそく再生範囲を広げて改めて再生してみると、今度はちゃんと歩いた。どうやらフリーアニメーションの範囲外のところに歩行アニメーションが出来上がったようだ。これは複数の足跡を作成パネルのタイミングの所の設定で、「最後の足跡から開始」が選択されていたからで、「現在のフレームから開始」を選べば、現在の所から歩行アニメーションを作成出来た。要するにこの方法を使えばフリーアニメーションのあるところに歩行アニメーションを上書き出来るって事だ。

fig03

そしてスケマティックビューで先に選択していたFootstepsの選択を解除して、スケマティックビューを閉じ、改めてビューポート上でBipedを選択してモーションパネルを開いてみたら、非アクティブ状態だった足跡ボタンがアクティブになってる。さっそく押してみたら足跡が表示された。これで通常の編集手順に復帰できたってわけだ。いいのかなぁ・・・。

その後スケマティックビューでBipedのノード全部を選択してみたところ、キーがまだ結構残っているのを発見したwww。あれ?

さっそく0フレームのキーまで全部消したら足跡モードのボタンがアクティブになった。うむむ。でも今回の方法を使えば(後でトラブルが発生して泣く事になるかも知れないけどwww)、フリーアニメーションを消さなくても足跡アニメーションをそのまま追加したり上書きしたり出来そうだ。とは言え、そんな無茶しなくても他に方法はあるだろうって話なのかな?

それではまた次回。

maxまとめページ



take_z_ultima at 12:01|この記事のURLComments(4)TrackBack(0)3ds Max | CG

2008年08月26日

スクリプトコントローラについて調べてみた その7 3ds max 2008

さて、長々やってきたけどボーンの動きにバネを仕込んでそろそろ切り上げよう。下の画像はrootポイントを基準とするローカル座標系のボーン、IKChain、Targetの様子だ。TargetだけはX−Z平面上に無く、X−Z平面に投影された像(rootのローカル座標で表わしてY座標を0としただけ)だ。

fig01

最初にこの構造を作った時は単にIKのゴールをTargetにペアレントしただけだった。その結果、Targetがボーンと直角の向きになってもIKのゴールがTargetに引っ張られて持ち上がってしまい、あまりいい結果にならなかった。そこでTargetの方向によってIKのゴールの移動ベクトルに重み付けをして、TargetがrootのX軸上にある時ゴールとTargetは重なり、それより角度が付いた時はその角度のコサインをとって図で行くとゴールの初期位置GとTargetTを結ぶ移動ベクトルGTにそのコサインをかけたベクトルGAの所までしかIKのゴールが移動しないようにした。コサインは90度で0なので、これでTargetが直角のところまで回転したらIKのゴールは全然移動しなくなるわけだ。

そして、このIKのゴールの位置を直接決めるのではなくて、運動方程式で制御してみようと言うのが今回のお題だ。バネと抵抗による運動方程式は以下のようになる。

fig02

一応ちょびっとだけ式を説明しておくと、Xが位置で、これが変化するとバネが伸び縮みすると捉えると、Xが増加してバネが伸びると、縮まろうとする力がバネの伸びに比例して発生する。これが−kxでkがバネの伸びに対する力の大きさを決めるバネ係数って奴だ。マイナスが付いているのはバネの端が移動して長さが変化する時、バネが発生させる力とバネの端の位置が進んだ方向は逆だからだ。そして物体が移動すればそれを押し留めようとする抵抗力が働く。空気抵抗や摩擦なんかなんだろうけど、これが速度に比例して発生すると考えれば、−αdx/dtの式になる。dx/dtは時間に対する位置の変化、すなわち速度の事だ。それに比例係数αをかけたのが抵抗力ってわけだ。これらの力によって質量mの物体が加速度を受けるわけで、力と加速と質量の運動方程式は、

fig03

でd^2x/dt^2はxを時間で2回微分で時間に対する位置の変化量の時間に対する変化量で、速度の変化量。すなわち加速度なわけだ。だからのこの方程式を使うとバネと空気などの抵抗を受ける物体の加速度を求める事が出来る。今回はやらなかったけど、さらに遠心力やバネの反対側にかかる張力、そして重力なんかも入れて行くとより現実に近付くんだろうね。まあそこまでやるならクロスシミュレータを使った方が手っ取り早いのかな?

さて、加速度が求められるならそこから質点の速度と位置が求められる。

fig04

ところでここで挙げた式に出てくる位置のX、速度のV、加速度のaは全部ベクトルとして扱えるのと、計算自体は要素ごとにこれらの式を当てはめて計算するだけなので、ここから先の話は全部これらの要素は全部XYZの3要素を持つベクトルであるのを前提に話を進めて行くよ。それから上の式は加速度aが定数なのが前提ね。だから今回のように加速度が変化する場合は微小時間の中で近似的に使っていくよ。

さて、そこで改めて最初の図に立ち戻ってIKのゴールはターゲットTに対してAの位置に引っ張られるわけだ。そしてこのGAベクトルが、前に作ったスクリプトコントローラの出力する値で、ベース位置であるGからの相対位置であるわけだ。

このAの位置へIKゴールを引っ張ると原点O(rootのローカル座標の原点ね)からAへの方向にも力が発生し、ボーンの点Oを中心とした回転を振動させる運動には何ら関係ない。そこでIKゴールを引っ張る方向をAからボーンの描く円の円周上の点Bに変更する事にした。こうすれば回転に対する遠心方向の力は殆ど抑えられる。

そこでBの位置なんだけど、OGの長さとOAの長さの比を使ってベクトルOAにその比をかけてやれば、ベクトルOBが得られる。これらのベクトルは全部原点Oに対する座標値そのものだから計算もとっても簡単だ。

fig05

求まった点Bと、直前のIKゴールの位置Pから2つのポイント間変位を求めてそれにバネ係数kを掛け合わせてゴールが目標に引っ張られる力とし、直前のIKゴールの位置Pのもう1個前の位置とPの位置の間の変位をその間の経過時間で割って速度を出し、それに抵抗係数αをかけてバネ振動を減衰させる抵抗力として足し合わせ、それを質量mで割ると、IKゴールの加速度が計算できる。

この加速度は時間によって変化するけれども、ごく微小な時間なら定数として捉えて直線運動すると考えても今回の目的の趣旨的に問題は無い。そこで、位置、速度、加速度の式を直前の点Pを原点として変位Xを求めて、それを点Pに毎回加算していく形で点Pの位置を更新していく。

これで足に添って動くだけだったボーンが足の勢いでちょっと跳ね上がったり、足が離れても、勢いでちょっとブラブラしたりするようになる。ただし、これでやってみると、このままではマズイ点がすぐに判明する。それは追従に遅れがあるので足の振り上げ時にボーンが足にめり込んでしまう事だ。そこでもう一工夫して、計算して求めたPの位置とBの位置を比較して、Pの位置が足にめり込む時はPの位置をBで置き換えるようにした。

再生結果

ここまでやってみてわかったのはプレビュー再生が全フレームを表示しない事だ。あれ?確かどこかに設定があったはず・・・と思ったけどすぐには見つからなくて、時間経過は直前の更新時に時刻を記録しておいて、現在時刻から引き算して作る事にした。これで更新の間隔がまばらでも、1フレームずつ送ったのと近い感じの動きになるはずだ。プログラムについてはいじっているうちにだいぶ怪しげな場合分けや補正が付いてしまってちょっと見苦しいんだけど、Bipedごとアップしてあるので、ゴールオブジェクトを選択してモーションパネルからコントローラを割り当てロールアウトを開けて、IKゴール、位置と展開して行けば、位置スクリプトが見えてくるので、それを右クリックしてプロパティを出せば、見られるよ。

やっぱりこういう離散的な方法じゃなくてちゃんと角速度とかを使った式にしとけば良かったかな・・・。

ただ、バネ係数とか質量とかの調整にいちいちこれを開くのも面倒なので、ゴールオブジェクトのユーザー定義プロパティとしてプログラムの外側で設定するようにしてみた。ゴールオブジェクトを右クリックして、下の画像のようにメニューからオブジェクトプロパティを開けばアクセスできる。

fig06

下の画像がそれだ。ユーザー定義のタブをクリックすれば出てくる。

fig07

それぞれのパラメータは以下の通り。

m:質量、k:バネ係数、alph:減衰係数、offX・offZ:ターゲットからのオフセット

使ってみて気付いたんだけど、まだ初期位置の設定の方法には詰めなきゃならない問題があって、フレーム0から動かすぶんにはいいんだけど、途中から動かした時や止めたり戻ったりすると、速度の計算や時間の計算がおかしくなる。どこのフレームで止めてもちゃんとなるためには、直前の位置を記録する方法はあんまり良くないのかなぁ。今回はこれもやらなかったけど、記録する位置をワールド座標系で処理すると、身体を動かした時の揺れなんかにも対応出来るようになるよ。ものは試しで色々やってみてるけど、IKゴールの先にもう一個ポイントを作ってIKゴールとそのポイントをスプリングのコントローラで結んで、その反対側のコントローラをターゲットにコンストレイントする方法も良さそうだな。

これは半分作ったものをターゲットを含んで選択してコピーして残り半分も作って歩かせてカメラで追ったもの。

fig08

とりあえずこんなモンでOrgeに適用してみようかな。

それではまた次回。

maxまとめページ



take_z_ultima at 12:20|この記事のURLComments(5)TrackBack(0)

2008年08月25日

スクリプトコントローラについて調べてみた その6 3ds max 2008

前回作ったグローバル変数にスクリプトコントローラごとの変数を自動的に割り当てるプログラムだけど、配列に収める変数のセットを配列にする替わりに構造体を使って作り直してみた。単に配列の3番目はカウンターに使うとかって頭で記憶して使うよりも、position,direction,countの3つのメンバー変数を持つ構造体として定義して、「インスタンス変数名.メンバー変数名」という形でアクセスした方がプログラムが読みやすくなる。それに構造体にはファンクションも組み込めるので、これらのメンバー変数に対する処理はメンバー変数に書く事でデータとその処理をひとまとめに出来る。

struct motion (
  position=[0,0,0],
  direction = random 0 5,
  count = random 1 50,
  fn changeDirection = (direction=random 0 5;count=random 1 50),
  fn reset = (position=[0,0,0];changeDirection()),
  fn move = (case of
    (
      (direction==0):position.x+=1
      (direction==1):position.x-=1
      (direction==2):position.y+=1
      (direction==3):position.y-=1
      (direction==4):position.z+=1
      (direction==5):position.z-=1
    );
    count -=1;
    if count==0 then changeDirection()
  )
)

これでメインのプログラムは短くなって読みやすくなる。基本的にはmyvalues=motion()でデータを生成し、myvalues.reset()で初期化、myvalues.move()で動く処理をして、myvalues.positionで位置を読み出して位置スクリプトに出力しているだけだ。リセットはsフレームが0(組み込み変数のFの値が0)の時に実行してみた。残りの部分はグローバル変数の割り当てと読み込みの部分ね。

global gMyArray
local myvalues
if gMyArray==undefined then
(
  myvalues=motion()
  gMyArray=#(#(thisnode.name,myvalues))
)
for i = 1 to gMyArray.count do
  if gMyArray[i][1]==thisnode.name then myvalues=gMyArray[i][2]
if myvalues==undefind then
(
  myvalues=motion()
  append gMyArray #(thisnode.name,myvalues)
)
if F==0 then myvalues.reset()
myvalues.move()
myvalues.position

ここまでやったらグローバル変数を扱う方も何とかならないかと思ってるところだけど、今の所中途半端な感じだ。

global gMyArray
struct motion (
  position=[0,0,0],
  direction = random 0 5,
  count = random 1 50,
  fn changeDirection = (direction=random 0 5;count=random 1 50),
  fn reset = (position=[0,0,0];changeDirection()),
  fn move = (case of
    (
      (direction==0):position.x+=1
      (direction==1):position.x-=1
      (direction==2):position.y+=1
      (direction==3):position.y-=1
      (direction==4):position.z+=1
      (direction==5):position.z-=1
    );
    count-=1;
    if count==0 then changeDirection();
  )
)

struct globalvar (
  values=undefined,
  ptr = 0,
  fn initialize name = (
    if gMyArray==undefined then (
      gMyArray=#(#(name,values))
      ptr=1
      print name
    )
    else
      for i = 1 to gMyArray.count do
        if gMyArray[i][1]==name then (
          values=gMyArray[i][2]
          ptr=i
        )
  ),
  fn setValues name myvalues = (
    if ptr==0 then (
      append gMyArray #(name,myvalues)
      ptr = gMyArray.count
    )
    else gMyArray[ptr][2]=myvalues;
    values = myvalues
  )
)

local gv = globalvar()
gv.initialize thisnode.name
if gv.values==undefined then (
  local vars=motion()
  gv.setValues thisnode.name vars
  [0,0,0]
)
else (
  if F==0 then gv.values.reset()
  gv.values.move()
  gv.values.position
)

メインルーチンを見てもらえばわかる通り、構造体globalvarの初期化の一部が外に漏れ出している。「if gv.values==undefined then」の部分はinitialize( )ファンクションの中に隠したいんだけど、クラスを渡して構造体の中でクラスのインスタンスを生成する方法がまだわかっていない。それとグローバル変数も構造体の外にあるのでまとまりが悪いよね。使う部分より上で宣言しとかなきゃならないので冒頭にglobal gMyArrayと宣言している。まあそれでも少しはまとまって来たかな。
構造体globalvarのメンバー変数はvaluesとptr。valuesはグローバル変数に設置された配列の中のこのスクリプトコントローラのために用意した領域を指し示す変数で、ptrはその領域が配列の何番目にあるのかを表わしている。グローバル変数が宣言された直後はundefinedが入っているので、その場合はグローバル変数に新規に作成した配列を代入し、その配列の1番目の要素として(name,values)という2つのデータが入った配列を入れ、ptrを1に設定する。この時点ではvaluesはundefinedの状態なのが困ったところだ。初期化の時に構造体の定義を受け取ってここで新規に構造体のインスタンスが作れると、スッキリするんだけど、先にも書いたように今の所その方法がわからない。もちろんこのルーチンの汎用性を失くすなら、そのまま今回のプログラムで配列に収める構造体motionのインスタンスを生成するようにコード内にじかに書いちゃえばいいわけだ。その代わりこのルーチンはmotion専用って事になっちゃうけどね。どっちにしろ汚いコードになっちゃうならその方がスッキリしていていいのかな?

そうしなかった場合、後からvaluesがundefinedであるかどうか調べて、undefinedなら、ptrの数値を調べて、0なら該当する名前のセクションが見つからなかったので、配列に新規に作った(名前,構造体)という形のデータを追加して、ptrの数値を更新し、0以外なら既に配列内に(名前,undefined)という部分が確保されているのでundefiedの部分に生成した構造体を代入する。どちらの場合も配列に設置した構造体はメンバー変数valuesからもアクセスできるようにvaluesにもその位置を代入しておく。

これでこの構造体のメンバー変数valuesにアクセスすればいつでも自分に割り当てられたメモリー領域にアクセスできるようになるし、それはコントローラごとに重ならないし、アクセスの方法は全く同じに出来る。コントローラをノードごとバンバンコピーしても重ならないグローバル変数が使えるってわけだ。

変数がグローバルになると、スクリプトコントローラのプログラムを抜けても値が保持されるので、下の画像のように直前の速度や位置を使って、減衰振動のアニメーションを簡単にプログラムしたり出来る(あれっ?at timeを使えばそんな事しなくても出来るかな・・・)。

fig01

時間が無くなって来たのでその話はまた次回。

maxまとめページ



take_z_ultima at 12:20|この記事のURLComments(2)TrackBack(0)3ds Max | CG
Archives