SceneObjectController とアニメーション

要約:
SceneObjectController により SceneObject のアニメーションが可能になります。Curl® 言語ではサブクラス TransformController を提供し、リニア補間でキーフレーム アニメーション システムを実装します。
キーフレーム アニメーションの概念は、初期のフィルム アニメーションに由来します。マスター アニメ制作者が主要なイメージであるキーフレームを描き、ジュニア アニメ制作者がフレーム間のギャップを埋めるイメージを描くというものです。
TransformController によるアニメーションでは、キーフレームで空間や時間における SceneObject の配置を指定し、コントローラで中間の位置を生成します。
各キーフレームでは次を指定します。
各キーフレームの平行移動、回転、スケールでは、キーフレームに与えられた時間におけるオブジェクトの方向を指定します。
コントローラでは SceneObject の変形を設定しますが、オブジェクトが親の SceneObject を持つ場合、親の変形に基づいて配置が決まります。
使用するキーフレームの数が非常に多い場合、サイズの大きなデータ セットを速く処理できる TransformController.from-arrays の使用を推奨します。
SceneObjectController のサブクラスを作成して、TransformController ではサポートされていない方法で SceneObject のアニメーションを実装することができます。SceneObject にアタッチされた SceneObjectController によりオブジェクトが更新されます。サブクラスを作成するときにオブジェクトの更新方法を定義します。
次の例では、TransformController を使って、小さな少女の画像を表示する Quad の動きをアニメーションにします。Quad は、最初は右に移動しながら時計の針と反対方向に回転し、続いて上に、さらに左に移動しながら時計回りに回転します。そしてこのシーケンスを始めから繰り返します。

例: TransformController の使用
{import * from CURL.GRAPHICS.SCENE, using-name="SCENE"}
{import * from CURL.PGUIDE.SCENEUTILS,
    location =  "../../default/support/SceneUtils.scurl"}
{let quat-quad:Quad = {Quad -10in, -10in, 20in, 20in}}
{let quat-group:SceneGroup = {SceneGroup}}
{do
    set quat-quad.fill-pattern = {url "curl://install/docs/default/images/adria.jpg"}
    {quat-group.transformation.local-translate 10in, 0in, 0in}
    {quat-group.add-object quat-quad}
}
{let controller:TransformController =
    {TransformController
        "the controller",
        null, || translation
        null, || rotation
        null, || scale
        0s,

        {Distance3d 20in, 0in, 0in},
        {Quaternion.from-axis-rotation 80deg, {Direction3d 0, 0, 1}},
        null,
        5s,

        {Distance3d 0in, 0in, 40in},
        {Quaternion.from-axis-rotation -80deg, {Direction3d 0, 0, 1}},
        {Fraction3d 3, 3, 3},
        10s
    }
}
{define-proc {toggle obj:SceneObject}:void
    {if obj.controller != null then
        set obj.controller.enabled? = not obj.controller.enabled?
    }
    {if obj isa SceneGroup then
        {for each-obj in (obj asa SceneGroup).objects do {toggle each-obj}}
    }
}
{value
    let scene:ExampleScene = {ExampleScene}
    {scene.camera-setup}
    {let scene-graphic:SceneGraphic =
        {SceneGraphic
            scene,
            width=4in,
            height=4in,
            background = {FillPattern.get-black}
        }
    }
    set quat-quad.controller = controller
    set controller.loop? = true
    set controller.enabled? = false
    {scene.add-object quat-group}
    {scene.add-object {make-axis-object 1m}}
    let tmr:Timer =
        {scene-graphic.animate
            frequency = 30fps,
            {on TimerEvent do
                {scene-graphic.update-drawable}
            }
        }
    {VBox
        scene-graphic,
        {CommandButton
            label = "Run/Stop",
            {on Action do
                {toggle scene}
            }
        }
    }
}