日本でハリウッドVFXを制作! 「経産省アイディアボックス」 結果:  
●まとめエントリはこちら ●FAQ ●お問い合わせは左のメールフォームから

2009年12月17日木曜日

「グローバル・プロシージャ」と「ローカルプロシージャ」の違い

前回のエントリ「ウインドウの作成(2): ボタン」で、ボタンで実行できるものに、コマンドとプロシージャーがあると書いた。

コマンドを使えるようにするのは簡単だったが、やはりMelスクリプトでGUIを使って自分のスクリプトを使えるようにするには、プロシージャが不可欠となってくる。

プロシージャーを使うことで、スクリプティングが格段にやりやすくなる。
特定の機能をブロック単位でわけて考えることが出来、必要に応じてそれを部品として利用することができるようになる。

今まで、このブログでは、学習過程をシンプルにするために、プロシージャーについてはほとんど触れなかったが、それについて、一歩踏み込む必要がでてきたようだ。

そこで、おさらいを兼ねて「プロシージャ」について復習してみた。
そこででてきた疑問が、プロシージャーには大別してグローバル・プロシージャとローカルプロシージャの2種類があるが、その違いは何か?ということだ。

他者の作ったスクリプトを解析していて、よく見るのは「global proc」とかかれたグローバル・プロシージャである。
ローカル・プロシージャを使っているのはあまりお目にかかったことがないか、出会ってもあまり注意を払っていなかったせいか記憶にない。


このふたつの違いは、なんとなくはわかったつもりだったが、より明確にするために少し実験をしてみた。


以下の物は、DigitalMatrixの「プロシージャの作り方 」にあった例をよりシンプルにしたグローバル・プロシージャーの例である。
これを仮に「プロシージャA」と呼ぶことにする。
global proc makeSphere1()
{
polySphere;
}


これをスクリプトエディターに入力して実行しただけでは、見た目には何も起きない。
しかし、メモリ内にはこのプロシージャーが保存されている。

そのため、実行後には、
makeSphere1
と入力して実行するだけでプロシージャーが実行される。
結果は、ポリゴン・スフィアが作成される。

このようにプロシージャーは「makeSphere1」という自前のコマンドとして使えるようになる。


次に同じプロシージャー名で、中のスクリプトが異なるグローバル・プロシージャーを作ってみた。
これを仮に「プロシージャB」と呼ぶ。

global proc makeSphere1()
{
sphere;
}

入力して実行。
そしてさきほどと同じコマンド
makeSphere1
を入力して実行してみる。(プロシージャー名が同じであることに注意)

すると今度はNurbsスフィアが作成される。


何が起きたかというとメモリ上にあるプロシージャーが上書きされて内容が後者の物に変わってしまったのだ。

このことはMayaのヘルプ「グローバル プロシージャを回避する 」に書かれている。
「グローバル プロシージャの潜在的な問題として、メモリ要件も挙げることができます。Maya は、宣言されたグローバルプロシージャをすべてメモリに保存します。多くのグローバル プロシージャをロードすると、グローバルプロシージャの保存に、それだけ多くのメモリが使用されます。」


簡単におさらいすると
1)グローバル・プロシージャはいつでもそのプロシージャ名をコマンドとして利用できる。
2)同じ名前のプロシージャは上書きされる。


----------------------------------------
では次にローカルプロシージャについて実験してみた。
ローカルプロシージャは「global proc」から「global 」を取り除けば良いだけである。
(参照:DigitalMatrix プロシージャの形式

proc makeSphere1()
{
polySphere;
}

これをスクリプトエディターから実行しmakeSphere1を実行すると同じ結果がでる。


次にNurbsスフィアを作るローカル・プロシージャを作ってみた。

proc makeSphere1()
{
sphere;
}

これもスクリプトエディターから実行しmakeSphere1を実行すると同じ結果がでる。

.....。
これではグローバル・プロシージャで実験したのと同じで、上書きされている。


----------------------------------------
次に、先に実行する物をグローバル・プロシージャにして後の物をローカルにしてみた。
global proc makeSphere1()
{
polySphere;
}


次に下記を実行。

proc makeSphere1()
{
sphere;
}

実はこれでもmakeSphere1内容は上書きされてしまう
どうも違いがよくわからない。


----------------------------------------
Digital Matrixのページで、プロシージャの形式の項目で、「global」の箇所をよく見直してみる。
「ローカル プロシージャは記述してあるファイルの内部からしか実行できません。 また、ローカル プロシージャは、スクリプト エディタ のインプットウインドウで実行することはできません。 」

この説明では、ローカル・プロシージャは「記述してあるファイルの内部からしか実行できない」と書かれている。
言い換えればスコープされている状況で内部でしか実行できないということ。
(スコーピングについてはエントリ:「構文 (1)」を参照)


この部分を明確にするには、
1)グローバル・プロシージャを宣言(実行)
2)スコーピングされた内部で同じ名前のプロシージャをローカルとして宣言(実行)
3)スコーピングされた内部でプロシージャを実行
4)後ほど同じプロシージャを実行

このステップを踏めばプロシージャ名は同じでも
「3」ではローカルプロシージャが実行された結果、
「4」でグローバル・プロシージャが実行された結果が得られるはずである。

そして「ローカル・プロシージャはスクリプト・エディタのインプットウインドウで実行することができない」という意味がわかるはずだ。


まず「ステップ1」。グローバル・プロシージャのスクリプトを実行。
global proc makeSphere1()
{
sphere;
}


この段階では
makeSphere1
を実行すればNurbsスフィアが作成される。


次に「ステップ2」と「ステップ3」
ブロック({ })で区切られた内部でプロシージャを宣言し、makeSphere1を実行。

{
proc makeSphere1()
{
polySphere;
}
makeSphere1;
}

これによりポリゴン・スフィアが作成された。

では、最後に「ステップ4」である。
makeSphere1
あれっ?
ポリゴン・スフィアが作成された???


どうもプロシージャーをスクリプトエディター内で実行しただけではちゃんとした区別はされないらしい。
どちらもグローバル・プロシージャとして判断されているようだ。
「{ }」を使ってブロック内でプロシージャを宣言してもスコーピングされてはいないのか。


もう一度DigitalMatrixのページを見直してみる。
「ローカル プロシージャは記述してあるファイルの内部からしか実行できません。」

「ファイル」と書いてある。


オンラインヘルプの「ローカル プロシージャ 」にも明確に書いてあった。
「スクリプト エディタ(Script Editor)でローカル プロシージャを定義することはできません。これらは、外部スクリプト ファイルのみで使用可能です。 」

なるほど、スクリプトエディターでは
proc makeSpehre1()
と書いてもローカルプロシージャの定義はできないので、これはグローバル・プロシージャとして判断されているということだろうか?


----------------------------------------
そこでこんどはスクリプトファイルを作成して試してみた。

まずグローバル・プロシージャ用のスクリプトファイル
ファイル名は「globaltest.mel」で保存した。
global proc makeSphere1()
{
sphere;
}

これをスクリプトエディターからソース・スクリプトにて読み込んだ後、
makeSpehre1
を実行するとNurbsスフィアが作成される。


つぎに、ローカルプロシージャ用のスクリプト・ファイルを作成。
ファイル名は「localtest.mel」で保存。
proc makeSphere1()
{
polySphere;
}

これをスクリプトエディターからソース・スクリプトにて読み込んだ後、
makeSpehre1
を実行するとNurbsスフィアが作成された。

ポリゴン・スフィアが作成されないということはグローバル・プロシージャのみがコマンドとして実行されていると言うことだ。


----------------------------------------
これでローカルプロシージャというのがなんとなくわかってきた。

ヘルプにも「他の言語では、プロシージャをサブルーチンと呼ぶことがあります。 」と書かれているようにローカルプロシージャはまさにサブルーチン的だ

グローバル・プロシージャは一つのスクリプト・ファイル内に収まっている必要はない(別のスクリプト・ファイルに記述されていても利用できる。)のだが、ローカルは一つのスクリプト・ファイル内に含まれていなくてはならない(同一のスクリプトファイル内からだけ利用可能。)。

サブルーチンの定義をWikiで見ると
「繰り返し利用されるルーチン作業をモジュールとしてまとめたもので、呼び出す側の「主」となるもの(メインルーチン)と対比して「サブルーチン」と呼ばれる。」

と書かれている。


現時点で、今ひとつローカル・プロシージャの使い道がわからないが、思いつくのは、サブルーチンの定義から推測すると、「ローカル・プロシージャは、メインのフローを持ったスクリプトの中で使われるもの」だということなのだろう。


「プロシージャ」、「サブルーチン」、「関数」という言葉は似たような概念を表しているが、プログラミング言語によって、その言葉があらわしている定義が若干異なることがあるようで、今回の考え方はMelにのみ当てはまる。

 

0 件のコメント:

コメントを投稿