チュートリアル - フローティング コントロールによるモーファー モディファイヤの拡張

チュートリアル > フローティング コントロールによるモーファー モディファイヤの拡張

3ds Max のモーファー モディファイヤには、最大 100 個のモーフ チャネルが用意されていますが、一度に表示できるのはそのうちの 10 個にすぎず、値の編集ボックスでのみコントロールできます。MAXScript を使用して、基本的なフローティング UI エクステンションをモーファー モディファイヤに追加します。 モーファー モディファイヤは、進行状況バーを使用してモーファー チャネルを表し、コントロールします。

また、スクリプトによる UI 要素のダイナミックな作成と時間の用途も示し、コールバックを変更して時間とプロパティの変化に反応するようにします。

関連トピック:

Macro Script の定義

Morpher : モディファイヤ

Morpher_Channel_Access

時間変更コールバック機能

変更ハンドラおよび When 構文

全体の流れ:

ボタン、メニュー項目またはショートカットとして使用できる macroScript としてコードをパッケージ化します。

モーファー モディファイヤ付きのオブジェクトが選択されていることを確認します。

モーファー モディファイヤを取得し、使用されているチャネルを収集します。

使用されているチャネルごとに、コントロール付きのダイアログ ボックスを記述する文字列を作成します。

すべてのコントロールの値を更新する関数を作成します。

シーンのタイムが変化したときに更新の関数を呼び出すコールバックを登録します。

モディファイヤのパラメータが変更されたときに更新の関数を呼び出すコールバックを登録します。

MAXScript

macroscript MorpherFloater category: "HowTo"
(
global mf_float, mf_morpher_mod
on isEnabled return
 selection.count == 1 and (try($.morpher)catch(undefined)) != undefined
on execute do
(
 mf_morpher_mod = $.modifiers[#morpher]
 used_channels = #()
 txt ="rollout mf_main \"Morpher Floater\" (\n"
 for i = 1 to 100 do
 (
  if WM3_MC_HasData mf_morpher_mod i then
  (
   append used_channels i
   txt +="progressbar mf_slider_"+ i as string
   txt +=" value:"+ (WM3_MC_GetValue mf_morpher_mod i) as string
   txt +=" width:150 height:18 across:2 align:#left\n"
   txt +="edittext mf_label_"+i as string
   txt +=" align:#right text:\""+i as string+": "
   txt +=(WM3_MC_GetName mf_morpher_mod i) +"\"\n"
   txt +="on mf_slider_"+i as string+" clicked val do (\n"
   txt +="WM3_MC_SetValue mf_morpher_mod "
   txt += i as string+" (val as float) \n"
   txt +="SliderTime +=0)\n"
  )
 )--end i loop
txt +=")\n"
 
createDialog (execute txt) 340 (used_channels.count*24)
txt ="fn mf_update_slider = (\n"
for i in used_channels do
(
 txt +="mf_main.mf_slider_"+i as string
 txt +=".value = WM3_MC_GetValue mf_morpher_mod "+i as string+" \n"
)--end i loop
txt +=")\n"
 
global mf_update_slider = execute txt
registertimecallback mf_update_slider
deleteAllChangeHandlers id:#morpher_floater
 
when parameters mf_morpher_mod changes \
 HandleAt:#RedrawViews \
 id:#morpher_floater do mf_update_slider()
)--end execute
)--end script

ステップごとの解説

macroscript MorpherFloater category:"HowTo"
(

macroScript は MorpherFloater と呼ばれます。スクリプトを使用する場合は、[カスタマイズ...](Customize...)に移動してスクリプトを[HowTo]カテゴリからツールバー、メニュー、またはクアッド メニューにドラッグするか、キーボード ショートカットを割り当てることができます。

マクロ スクリプトの定義

global mf_float, mf_morpher_mod

モーファー コントロールを表示するために使用するロールアウトと、現在選択されている制御対象のモーファー モディファイヤを格納するために、一組のグローバル変数が必要です。

変数のスコープ

on isEnabled return
selection.count == 1 and (try($.morpher)catch(undefined)) != undefined

このスクリプトは、シーン内で単独のオブジェクトが選択され、そのオブジェクトがスタック上にモーファー モディファイヤを持っている場合にのみアクティブになります。

isEnabled ハンドラは、ステートメントを返した後に式を評価して、その式が true の場合にスクリプトのボタン、メニュー項目またはショートカットを有効にします。そうでない場合、スクリプトは無効になります。

最初のステートメントでは、シーン内で選択されたオブジェクトの数を 1 と比較します。 ただ 1 つのオブジェクトのみが選択されている場合、この式は true を返します。

次に、選択されたオブジェクトに適用されるモーファー モディファイヤがあるかどうかも尋ねます。これは、 try()catch() コンテキスト内で行われます。モーファー モディファイヤがある場合は、そのモーファー モディファイヤがこの式の結果として返されます。モーファーがない場合、通常はエラーになります。このエラーを捕捉して、代わりに undefined を返します。したがって、結果が undefined で「ない」かどうかがチェックされます。これで、モーファーが検出された場合は true の、そうでない場合は false の結果が返されます。

テストの最初の部分と 2 番目の部分が両方とも true を返したときにのみ、isEnabled ハンドラも true を返し、スクリプトがアクティブになります。

Macroscript_Body_Event_Handlers

on execute do
(

execute ハンドラにはスクリプトの本体が含まれ、このスクリプトが割り当てられているボタンをユーザがクリックするか、メニュー項目を選択するか、キーボード ショートカットを押したときには常に実行されます。これは、 isEnabed が true を返したときにのみ発生します。

Macroscript_Body_Event_Handlers

mf_morpher_mod = $.morpher

最初に、スクリプトの先頭で定義したグローバル変数にモーファー モディファイヤを格納します。選択されているオブジェクトがただ 1 つであることを確認済みなので、 $ selection[1] の代わりに使います。 また、 isEnabled のチェックによって、選択されたオブジェクト内にモーファー モディファイヤがあることが既にわかっているので、これ以上エラーの捕捉の必要はありません。

used_channels = #()

モーファー内のチャネルで使用されるインデックスを確認するための、ユーザ定義の配列が必要です。

配列の値

txt ="rollout mf_main \"Morpher Floater\" (\n"

ここで、かなり変わった操作を始めます。 最初に文字列変数内に必要なすべての定義を配置し、それが通常のスクリプト ファイルであるかのように実行することによって、新規のロールアウト全体をダイナミックに作成していきます。文字列内に引用符がある箇所には、必ず円記号「¥」 が必要であることに注意してください。また、「¥n」シーケンスを使用して改行を示す必要があります。

文字列値

ロールアウト句

for i = 1 to 100 do
(

モーファー モディファイヤは、最大 100 個のチャネルを持つことができます。 for ループを使用して、それらのチャネルを巡回します。変数の i で、現在のモーフ ターゲット チャネルを表わす 1 から 100 までをカウントします。

for ループ

if WM3_MC_HasData mf_morpher_mod i then
(

3ds Max 5 では、モーファー チャネルにアクセスする新しい関数が実装されました。 WM3_MC_HasData 関数を呼び出してモーファーとチャネル インデックスを渡すことによって、チャネルにモーファー データがあるかどうかをチェックすることができます。データがある場合は if ステートメントのコンテキスト内部に進み、ない場合はこのチャネルをスキップします。

If 式

Morpher_Channel_Access

append used_channels i

for ループの変数 i に格納されているチャネル インデックスを、使用されているチャネルの配列に追加します。 for ループの準備ができたら、使用されているすべてのチャネルが配列に含まれます。

配列の値

txt +="progressbar mf_slider_"+ i as string
txt +=" value:"+ (WM3_MC_GetValue mf_morpher_mod i) as string
txt +=" width:150 height:18 across:2 align:#left\n"

ここで、ロールアウト文字列内部の新しい進行状況バーの UI 要素の作成について説明します。「+=」を使用して現在の文字列に新しい部分文字列を追加することに注意してください。すべての UI 要素にそれぞれ固有の名前を付けるために、チャネル番号を文字列として付加します。progressbar の現在の値をモーファー モディファイヤのチャネルの現在の値に設定します。 across:2 キーワードを使用して、2 つの UI 要素を同じ行に配置するようにします(後で、モーフ ターゲットの名前のテキスト ラベルを追加します)。

ProgressBar

txt +="on mf_slider_"+i as string+" clicked val do (\n"
txt +="WM3_MC_SetValue mf_morpher_mod "
txt += i as string+" (val as float) \n"
txt +="SliderTime +=0)\n"

progressbar UI 要素は通常はプロセスの進行状況を表示するために使用されますが、マウスで変更された値を返す変更ハンドラが提供されているため、スライダの代わりとしても使用することができます。 on ... clicked val do... ハンドラは、ユーザが進行状況バー上でマウスをクリックするごとに呼び出されます。変数 var には、0 から 100 の範囲の現在値が格納されます。これを 0.0 から 100.0 までの浮動小数点数として、インデックス i を使用してそれぞれのチャネルに代入します。

SliderTime += 0 は、後で定義する時間コールバックを欺くためのトリックです。ゼロを追加するのでスライダの時間は実際には変化しませんが、システムに変化を評価させ、時間コールバックを実行させます。

時間コントロール

txt +="edittext mf_label_"+i as string
txt +=" align:#right text:\""+i as string+": "
txt +=(WM3_MC_GetName mf_morpher_mod i) +"\"\n"

さらに、編集テキストの UI 要素の作成について説明します。このテキストには、文字列としてのチャネル インデックスと i 番目のモーファー チャネルの名前が含まれます。ラベルは進行状況バーと同じ行に表示され、右寄せされます。

Edittext

)--end if
)--end i loop
txt +=")\n"

この時点で、i ループは終了します。このループで、空でないすべてのチャネルのためのコントロールが UI を記述する文字列に追加されました。あとは、ロールアウトの終了ブラケットを追加するだけです。

createDialog (execute txt) 340 (used_channels.count*24)

ここで、新しいロールアウトのソースとして配置した文字列を使用して、ダイアログ ボックスを作成します。外部のソース コード ファイルと同じようにして、実行関数で文字列を評価します。評価の結果は、スクリプト エディタを使用して入力したのと同じロールアウトになります。ダイアログ ボックスは、幅が 340 ピクセル、収集された総チャネル数を 24 倍してロールアウト内のコントロール数で割ったものになります。つまり、スクリプトが開始されるごとに、モディファイヤ内のモーファー チャネルの数によって UI の高さが変化します。

CreateDialog

文字列値

txt ="fn mf_update_slider = (\n"

ここで再び、モーファーが変更されるごとに呼び出される新しい文字列定義の関数を開始します。

カスタム関数の定義

for i in used_channels do
(

使用されている各モーファー チャネルに対応するスライダを更新する必要があります。変数 i には、ループの反復ごとに対応するチャネルのインデックスが含まれます。

for ループ

txt +="mf_main.mf_slider_"+i as string
txt +=".value = WM3_MC_GetValue mf_morpher_mod "+i as string+" \n"

ここで、グローバルに定義されたロールアウト mf_main のチャネル i の進行状況バーに、その値をグローバル変数 mf_morpher_mod 内に格納されたモーファー モディファイヤ内の i チャネルの値に変更するように指示します。

Morpher_Channel_Access

)--end i loop
txt +=")\n"

最後に、関数のブラケットを閉じます。

global mf_update_slider = execute txt

次に、コールバック内で使用できる評価された関数を指定する関数の定義テキストを実行します。それをグローバル変数に格納して、定義しようとしているすべてのコールバックでアクセスできるようにします。

変数のスコープ

文字列値

registertimecallback mf_update_slider

最初のコールバックは、時間の変化に反応します。マウスでタイム スライダを動かしたり、アニメーションを再生したりなどしてシーン内の時間が変化するたびに、時間コールバックが指定された関数を呼び出します。 この例では、直前に定義した UI 更新の関数を呼び出します。前に説明した、この関数の SliderTime += 0 の部分を思い出してください。これで、このコールバックも呼び出されることになります。

このコールバックの結果、モーファー チャネルの値をアニメートしてからアニメーションを再生した場合、アニメーションが再生されている間にリアルタイムで進行状況バーが更新されます。

時間変更コールバック機能

deleteAllChangeHandlers id:#morpher_floater

他のコールバックを登録する前に、まず、同じスクリプトによって登録された古いコールバックがメモリから削除されていることを確認します。この例のコールバックの固有の ID は、 #morpher_floater です(この名前はユーザ定義であり、固有であるかぎりどのような名前でもかまいません)。それで、その ID を持つ既存のコールバックがあればそれを削除するように MAXScript に指示します。

変更ハンドラおよびコールバック

when parameters mf_morpher_mod changes \
HandleAt:#RedrawViews \
id:#morpher_floater do mf_update_slider()

最後に、パラメータ変更のコールバックを登録します。when コンストラクタで、指定されたオブジェクトの監視対象のプロパティ (この例ではモーファー モディファイヤのパラメータ) の値が変更されたときに常に実行されるコールバックを定義します。

ビューポートが再描画されているときにのみ更新するようにコールバックに指示します。これで、ユーザが気付くような障害なしに、内部的な呼び出しの実際の回数が減り、スクリプトの実行速度が上がります。

後でこのコールバックを削除できるように、固有の ID を与えます。

このコールバックが実行するのは、更新の関数を呼び出すことだけです。その結果、モーファー チャネルの値を変更したときに、ここで作成したフローティング UI が自動的にその変更を反映するようになります。

変更ハンドラおよびコールバック

)--end execute
)--end script

スクリプトの使い方

スクリプトを評価します。スクリプトを使用する場合は、[カスタマイズ...](Customize...)を使用して、スクリプトを[HowTo]カテゴリからツールバー、メニュー、またはクアッド メニューにドラッグするか、キーボード ショートカットを割り当てることができます。

モーファー モディファイヤ付きの単独オブジェクトとシーン内でアクティブなチャネルをいくつか選択し、このスクリプトを実行します。新しいフローティング ダイアログ ボックスが、進行状況バーとチャネル番号およびターゲット名を表示するテキスト フィールド付きで表示されます。

関連項目

これは、非常に単純化された例です。シーン内の単独のターゲット オブジェクトを選択するためのスピナーやボタンなどを追加して、このフロータを拡張することができます。 また、進行状況バー要素を変更して、代わりに通常のスライダを使うこともできます。

上記のスクリプトは、使用されているモーファー チャネルの変更 (モーフ ターゲットの追加/削除) を検出しません。現時点では、スクリプトを再起動して変更を反映する必要があります。このような場合の処理を追加することもできます。

戻る

「チュートリアル」のインデックス ページ