カメラからの距離で求める錐台のサイズ
Rays from the Camera

ドリーズーム (別名「トロンボーン」エフェクト)

ドリーズームは良く知られた視覚エフェクトで、カメラがターゲットオブジェクトに向かうと同時にズームアウトするものです。その結果、ターゲットオブジェクトはほとんど同じ大きさで表示されたまま、シーンの他のすべてのオブジェクトのパースペクティブが変化します。ドリーズームでは、イメージの中で唯一ターゲットオブジェクトの位置だけが移動しないため、さりげなく行うと、ターゲットオブジェクトをハイライトする効果があります。別の効果としては、ズームを意図的に素早く行う事で、方向感覚を失った印象を作り出すことができます。

錐台の中に縦方向にちょうど収まるオブジェクトは画面で見たとおりに視野の高さ全体を占めます。これはオブジェクトのカメラからの距離がいくつであっても、視野角 (FOV, field of view) が何度であっても変わりません。例えば、カメラをオブジェクトに近づけて、視野角を広げてオブジェクトが錐台の高さにちょうどおさまるようにすることができます。その特定のオブジェクトは画面上で同じ大きさで表示されますが、その他のすべては、距離および視野角の変さらに伴ってサイズが変更されます。これはドリーズーム効果の最重要点です。

コードでこのエフェクトを作成するには、ズーム開始時のオブジェクトの位置における錐台の高さを保存することになります。次に、カメラが移動するにつれ、新しい距離が見つかり、そしてオブジェクトの位置と同じ高さであるように視野角は保持されます。これは次のようなコードにより実現できます。

using UnityEngine;
using System.Collections;

public class ExampleScript : MonoBehaviour {
    public Transform target;
    public Camera camera;
    
    private float initHeightAtDist;
    private bool dzEnabled;

    // カメラから指定の距離にある錐台の高さを計算します
    void FrustumHeightAtDistance(float distance) {
        return 2.0f * distance * Mathf.Tan(camera.fieldOfView * 0.5f * Mathf.Deg2Rad);
    }

    // 指定した距離で指定の錐台の高さを得るために必要な FOV を計算します
    void FOVForHeightAndDistance(float height, float distance) {
        return 2.0f * Mathf.Atan(height * 0.5f / distance) * Mathf.Rad2Deg;
    }

    // ドリーズーム効果を開始
    void StartDZ() {
        var distance = Vector3.Distance(transform.position, target.position);
        initHeightAtDist = FrustumHeightAtDistance(distance);
        dzEnabled = true;
    }
    
    // ドリーズームをオフにします
    void StopDZ() {
        dzEnabled = false;
    }
    
    void Start() {
        StartDZ();
    }

    void Update () {
        if (dzEnabled) {
            // 新しい距離を測り、FOV をそれに合わせて再調整します
            var currDistance = Vector3.Distance(transform.position, target.position);
            camera.fieldOfView = FOVForHeightAndDistance(initHeightAtDist, currDistance);
        }
        
        // up/down の矢印でカメラを内側/外側に動かせる簡単な制御
        transform.Translate(Input.GetAxis("Vertical") * Vector3.forward * Time.deltaTime * 5f);
    }
}

C# スクリプトの例

var target: Transform;

private var initHeightAtDist: float;
private var dzEnabled: boolean;


//  カメラから指定の距離にある錐台の高さを計算します
function FrustumHeightAtDistance(distance: float) {
    return 2.0 * distance * Mathf.Tan(camera.fieldOfView * 0.5 * Mathf.Deg2Rad);
}


// 指定した距離で指定の錐台の高さを得るために必要な FOV を計算します
function FOVForHeightAndDistance(height: float, distance: float) {
    return 2 * Mathf.Atan(height * 0.5 / distance) * Mathf.Rad2Deg;
}


// ドリーズーム効果を開始
function StartDZ() {
    var distance = Vector3.Distance(transform.position, target.position);
    initHeightAtDist = FrustumHeightAtDistance(distance);
    dzEnabled = true;
}


// ドリーズームをオフにします
function StopDZ() {
    dzEnabled = false;
}


function Start() {
    StartDZ();
}


function Update () {
    if (dzEnabled) {
        // 新しい距離を測り、FOV をそれに合わせて再調整します
        var currDistance = Vector3.Distance(transform.position, target.position);
        camera.fieldOfView = FOVForHeightAndDistance(initHeightAtDist, currDistance);
    }
    
    // up/down の矢印でカメラを内側/外側に動かせる簡単な制御
    transform.Translate(Input.GetAxis("Vertical") * Vector3.forward * Time.deltaTime * 5);
}

JS スクリプトの例

カメラからの距離で求める錐台のサイズ
Rays from the Camera