>   >  スクリプト兵法書 〜MAX Script編〜:Vol.4:スクリプトの具体的な作り方(後編)
Vol.4:スクリプトの具体的な作り方(後編)

Vol.4:スクリプトの具体的な作り方(後編)

PF を使い、ジオメトリの影を Cube 状に表現する

では、実際に PF でジオメトリの影を Cube 状にしてみましょう。以下のような手順で処理していきます。

<1>パーティクルを発生させる

<2>パーティクルを格子状に配置する

<3>配置したパーティクルのうち、影になっていない部分を削除する

<4>表示

<5>全パーティクルを削除

この、<1>〜<5>を毎フレーム繰り返せば、前回のサンプルムービー(下)のような映像表現が行えるようになります。実際にはもっと効率的だったり、賢いアルゴリズムはたくさんあるのですが、毎回作って消すというのが最もシンプルだったので、今回はこの手法を採用しました。それでは、その手順を具体的に解説していきましょう。
 

これより解説していく、MAXScript で PF を制御したサンプルムービー

前半:パーティクルを格子状に配置

まず最初に、インテグレーションステップを 1 フレームに設定します。今回の方法では、1 フレームに一度だけ計算を行えば良いためです。準備ができたらパーティクルを格子状に配置します。今回は<1>と<2>をまとめて Birth スクリプトオペレータで行いました。



----Birth Script----

  on ChannelsUsed pCont do(
    pCont.useAge = true
    pCont.usePosition = true
  )

  on Init pCont do (
  )

  on Proceed pCont do (
    cubeSize=5
    mapSize = 200
    for i in -mapSize/2 to mapSize/2 by cubeSize do (
      for j in -mapSize/2 to mapSize/2 by cubeSize do (
        pCont.AddParticle()
        pCont.particleIndex = pCont.NumParticles()
        pCont.particleAge = 0
        pCont.particlePosition = [i, j, 0]
      )
    )
  )

  on Release pCont do (
  )

----

ChannelsUsed Processed Release 「ハンドラ」と呼ばれ、中身は関数と同じように定義します。関数と違うのは、それぞれのハンドラは PF のイベントの中で呼ばれるという事です。ChannelsUsed ハンドラは、オペレータ内でどのようなパラメータが使用されるかを PF に知らせます。



  on ChannelsUsed pCont do(
    pCont.useAge = true		← エージ チャンネルを有効にします
    pCont.usePosition = true	← 位置チャンネルを有効にします
  )

これはほとんど、"おまじない"と同じで「こんなものなんだ」程度に軽く覚えてもらえば十分です。そして、次の Processed ハンドラがこのスクリプトオペレータの本体になります。



  on Proceed pCont do (
    distance=5
    mapSize = 200
    for i in -mapSize/2 to mapSize/2 by distance do (
      for j in -mapSize/2 to mapSize/2 by distance do (
        pCont.AddParticle()
        pCont.particleIndex = pCont.NumParticles()
        pCont.particleAge = 0
        pCont.particlePosition = [i, j, 0]
      )
    )
  )

Processed の引数の pCont は PF から渡される、パーティクル情報を管理しているコンテナです。pCont という名前の籠の中に、パーティクルが入っている状態をイメージしてください。

distance や mapSize という変数を決めた後、i と j の二重ループが回ります。ここはもう、慣れた形ですね。このループの中では、i 、j 共に -mapSize/2〜mapSize/2 までの値を順に取って、 pCont.particlePosition = [i, j, 0] でパーティクルの位置として使用しています。つまり、縦横 mapSize の範囲に、間隔 distance 置きにパーティクルを配置しています。それでは、j のループの中をより詳しく見てみましょう。



  pCont.AddParticle()

AddParticle() で、コンテナ pCont にパーティクルを追加します。これが、ステップ 1 のパーティクルの発生です。



  pCont.particleIndex = pCont.NumParticles()

これから操作するパーティクルを指定します。パーティクルは追加された順番に 1、2、3......と、番号が振られていくので直前に追加されたパーティクルを指定する場合は pCont に含まれているパーティクルの数を指定します。



  pCont.particleAge = 0

パーティクルエージを 0 に指定します。この値は、タイムラインが進むにつれて自動的に加算されていきます。



  pCont.particlePosition = [i, j, 0]

その上で、パーティクルの位置を指定します。 i,j は、先ほど説明した通りです。全ループが終わると、200×200 ユニット(デフォルトの単位はインチ)範囲のグリッド状に配置されることになります。この時の状態を表示してみましょう。Send Out をオフにして、Display を Event 001 に追加すると、Birth Script の結果を確認することができます。

Particle Flow:Birst Script の結果を確認

Display(赤マル)を Event 001 に追加すると、Birst Script の結果が確認できる

その他の連載