前: テクスチャ形状 次: Object3D と ObjectInfo

5. スクリプト形状 上級編

ここまでで、簡単なスクリプト形状の例をいろいろと見てきました。ここでは、もっと複雑な例を見てみましょう。私の両親が暖炉に上に飾っている、エチオピアの馬毛のハエたたきをモデリングしました。

把っ手の部分は単純な幾何形状で手作りでモデリングしました。毛の部分は、以下のスクリプトで作成しました。


waviness = 0.1;     // Controls how straight the hairs are
length = 3.0;       // Length of each hair
thickness = 0.02;   // Thickness of each hair
hairs = 300;        // Number of hairs
coneAngle = 25.0;   // Sets the width of the "cone" of hairs at the base
gravity = new Vec3(0.0, -0.5, 0.0);  // Sets the strength and direction of gravity

if (script.isPreview())
  hairs = 20;
script.getCoordinates().toLocal().transformDirection(gravity);
random = new Random(0);
segmentLength = length/3.0;

// Main loop to create the hairs

for (i = 0; i < hairs; i++)
{
  v = new Vec3 [4];
  
  // Set the base at the origin.
  
  v[0] = new Vec3();
  
  // Determine the direction of the hair when it leaves the base.
  
  theta = coneAngle*random.nextDouble()*Math.PI/180.0;
  phi = random.nextDouble()*2.0*Math.PI;
  dir = new Vec3(Math.cos(theta), Math.cos(phi)*Math.sin(theta), Math.sin(phi)*Math.sin(theta));
  
  // Place the remaining vertices.
  
  for (j = 1; j < v.length; j++)
  {   
    // Place the next vertex.
    
    dir.normalize();
    v[j] = v[j-1].plus(dir.times(segmentLength));

    // Add a random displacement to the direction.
    
    dir.x += waviness*(random.nextDouble()-0.5);
    dir.y += waviness*(random.nextDouble()-0.5);
    dir.z += waviness*(random.nextDouble()-0.5);
    
    // Add a displacement due to gravity.
    
    dir.add(gravity);
  }
  
  // Create the hair.
  
  hair = new Tube(v, new float [] {1.0f, 1.0f, 1.0f, 1.0f}, new double []
      {thickness, thickness, thickness, 0.0}, Tube.APPROXIMATING, Tube.OPEN_ENDS);
  script.addObject(hair, new CoordinateSystem());
}

このスクリプトは今までのものより長く、より複雑ですが、まだ本当に複雑だとは言えません。どう機能するかを以下でじっくり見てみましょう。

スクリプトの振る舞いに影響する、さまざまな定数の定義から始めます。作成する毛の本数、それぞれの毛の長さと太さなどです。これは一般的に良い方法です。設定できるオブションすべてをスクリプトの一番上に配置して、簡単に変更できるようにします。

次に、以下の行を考えます。


if (script.isPreview())
  hairs = 20;

複雑なスクリプトは実行時間をかなり必要とし、作り出す幾何要素が複雑な場合、レンダー速度も遅くなります。高画質のレンダーは綺麗ですが、インタラクティブな編集作業が遅くなり、苦痛にもなります。script.isPreview() を呼び出すと、インタラクティブプレビューを作成するスクリプトをいつ実行するかの設定ができます。今回の例では、最終レンダー画像での毛の本数 (hairs) は300本ですが、インタラクティブプレビューでは20本のみ表示します。

次の行の記述です。

script.getCoordinates().toLocal().transformDirection(gravity);

その前に、下向き (0.0, -0.5, 0.0) の重力 (gravity) ベクトルを定義しました。定義したすべての幾何要素が、スクリプト形状の個別の座標系に変換されることを思い出しましょう。下向きの重力は実際は 全体 (global) 座標系にすべきです。このため、全体の座標系で「下向き」に対応する、個別 (local) 座標でのベクトルを探す必要があります。

script.getCoordinates() はスクリプト形状の座標系を返します。そして toLocal() または fromLocal() を呼び出し、その変換マトリクス (artofillusion.math.Mat4) を使います。このマトリクスで、個別の座標系に変換したり、その逆を行ったりします。

その次は、毛を作成するメインのループです。毛の1本ずつは、4つの頂点で構成された管オブジェクトで表現します。最初の頂点は常に基点に置きます。2番目は、指定した幅の円錐の中にランダムに配置します。この次に続く頂点については、(毛に波打ちを追加して)方向をランダムに変化させます。最後に管を作成して、スクリプト形状に追加します。

最初に書いたように、スクリプト形状の最も重要な特徴の1つは、見映えと同じように振る舞いも定義して「知的」にできることです。スクリプトが振る舞いを定義できる2つの方法を、先にお見せしました(オブジェクトは時間とともに明示的に変えられる、また、変更可能なパラメータでも変えられる)。このスクリプトでは、別なタイプの振る舞い(オブジェクトはシーン内の位置によって変えられる)をお見せします。このハエたたきを回転させると、現実と同じく、毛は常に下に垂れ下がります。

このスクリプトはとても柔軟です。小さな変更で、ほかの多くのものを表現できます。人の頭の髪の毛、草むら、噴水などです。同じスクリプトをほかのシーンでも使いたくなるときがよくあるでしょう。スクリプト形状編集ウインドウの "Load..." ボタンと "Save..." ボタンで、ハードディスクにスクリプトを簡単に保存できます。

ここまでの例ではすべて「新規スクリプト」を選択してきましたが、新規のスクリプト形状を作るときはいつでも、どのスクリプトを使うかを選択できます。ArtOfIllusion/Scripts/Objects フォルダにスクリプトを保存すると、リストの選択肢に追加できます。これで便利なオブジェクト形状を簡単に保存でき、多くのシーンで再利用できます。

前: テクスチャ形状 次: Object3D と ObjectInfo