inosyanのブログ

プログラム関連の話題を中心に掲載します

UnityのTimelineを使ったムービー制作 #2

f:id:inosyan:20180126081931j:plain

先日の記事で、アセットストア向けにアセットパッケージの制作をした際に、紹介ムービーをUnityで作成した際のことを書きましたが、今回はその続きです。

このムービーの冒頭の10秒間の部分がUnityで制作した部分です。


WWW Script Generator

ムービー開始後3~4秒付近の光る部分は点光源の光量をスクリプトで制御しています。 f:id:inosyan:20180126082039g:plain

シーンには点光源が置いてありますが、はじめは非アクティブで、タイムライン上で時間が来たらアクティブにしています。それと同時に点光源の光量を制御するスクリプトを開始しています。 はじめは光量0でだんだん明るくなり、一番明るくなったところからすこし暗くなって終わります。 f:id:inosyan:20180126082104p:plain

PointLightOnAsset.cs

[System.Serializable]
public class PointLightOnAsset : PlayableAsset
{
    public ExposedReference<Light> PointLight;

    public override Playable CreatePlayable(PlayableGraph graph, GameObject go)
    {
        var handle = ScriptPlayable<PointLightOn>.Create(graph);
        var beh = handle.GetBehaviour();
        beh.PointLight = PointLight.Resolve(graph.GetResolver());
        return handle;
    }
}

PointLightOn.cs

using UnityEngine;
using UnityEngine.Playables;

public class PointLightOn : PlayableBehaviour
{
    public Light PointLight;

    public override void OnGraphStart(Playable playable) {
    }

    public override void OnGraphStop(Playable playable) {
    }

    public override void OnBehaviourPlay(Playable playable, FrameData info) {
    }

    public override void OnBehaviourPause(Playable playable, FrameData info) {
        AdjustIntensity(1);
    }

    public override void PrepareFrame(Playable playable, FrameData info) {
        float rate = (float)(playable.GetTime() / playable.GetDuration());
        float d = 120 * rate / 180 * Mathf.PI;
        d = Mathf.Sin(d) / Mathf.Sin(120.0f / 180.0f * Mathf.PI);
        AdjustIntensity(d);
    }

    void AdjustIntensity(float intensity)
    {
        if (!PointLight) return;
        PointLight.intensity = intensity;
    }
}

PlayableAssetを継承したスクリプトをタイムラインに配置し、点光源のインスタンスを紐付けます。具体的な挙動はPlayableBehaviourを継承したスクリプトに記述します。

タイムラインのポジションが動くときに呼ばれるPrepareFrameの中で、

float rate = (float)(playable.GetTime() / playable.GetDuration());

タイムライン上のこのスクリプトの範囲を0~1で表したときのどの位置にいるのかを調べ、 それを0~120°の角度に換算し、

float d = 120 * rate / 180 * Mathf.PI;

後半明るくなってから少し暗くなるように、sin(120°)が最終的な光量になるように調整しています。

d = Mathf.Sin(d) / Mathf.Sin(120.0f / 180.0f * Mathf.PI);

sinの値は

sin(0°) = 0
sin(90°) = 1
sin(120°) = 0.87

なので、それぞれsin(120°)で割ると

sin(0°) / sin(120°) = 0
sin(90°) / sin(120°) = 1.15
sin(120°) / sin(120°) = 1

となり、一番明るいときの光量は1.15なので最後の1と較べてすこし明るいため、一瞬スパークしたように見えるのです。

ところで、このムービーで紹介しているアセットパッケージは申請してから2週間経とうとしますが、まだ審査中です。以前別のアセットパッケージを公開した際も2週間ほどかかったのでそろそろではないかとは思いますが、公開されたらあらためてご紹介したいと思います。