Version: 2019.1
Размер усечённой пирамиды на данном расстоянии от камеры
Лучи из камеры

Dolly Zoom (эффект “Trombone”)

Dolly Zoom - это очень известный прием, подобный эффект получают путем движения камеры вперед или назад одновременно с изменением фокусного расстояния. В результате создается ощущение, что объект съемки остается неизменным, а все остальные объекты вокруг видны с другого ракурса. Если не переусердствовать, создается впечатление выделения объекта съемки, в следствие того, что это единственный объект на сцене который не меняет своего положения на экране. Или же этот прием, если исполнить быстро, можно использовать, чтобы добиться эффекта головокружения.

Объект, который точно помещается в пирамиду видимости (frustum ) вертикально, будет занимать всю высоту экрана на сцене. Это верно для любого расстояния от объекта до камеры и для любого угла обзора, главное, чтобы объект точно помещается в пирамиду видимости вертикально. Только этот объект будет казаться неизменным, хотя все остальное поменяет как размер и расстояние, так и угол обзора. На этом базируется эффект dolly zoom.

Чтобы воссоздать эффект, нужно измерить высоту основания пирамиды видимости (frustum) (основание совпадает с позицией объекта съемки) в начале изменения фокусного расстояния (zoom). После, когда камера начинает двигаться, нужно подобрать угол обзора, так чтобы высота оставалась неизменной. Этого можно добиться следующим кодом:-

using UnityEngine;
using System.Collections;

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

    // Calculate the frustum height at a given distance from the camera.
    void FrustumHeightAtDistance(float distance) {
        return 2.0f * distance * Mathf.Tan(camera.fieldOfView * 0.5f * Mathf.Deg2Rad);
    }

    // Calculate the FOV needed to get a given frustum height at a given distance.
    void FOVForHeightAndDistance(float height, float distance) {
        return 2.0f * Mathf.Atan(height * 0.5f / distance) * Mathf.Rad2Deg;
    }

    // Start the dolly zoom effect.
    void StartDZ() {
        var distance = Vector3.Distance(transform.position, target.position);
        initHeightAtDist = FrustumHeightAtDistance(distance);
        dzEnabled = true;
    }
    
    // Turn dolly zoom off.
    void StopDZ() {
        dzEnabled = false;
    }
    
    void Start() {
        StartDZ();
    }

    void Update () {
        if (dzEnabled) {
            // Measure the new distance and readjust the FOV accordingly.
            var currDistance = Vector3.Distance(transform.position, target.position);
            camera.fieldOfView = FOVForHeightAndDistance(initHeightAtDist, currDistance);
        }
        
        // Simple control to allow the camera to be moved in and out using the up/down arrows.
        transform.Translate(Input.GetAxis("Vertical") * Vector3.forward * Time.deltaTime * 5f);
    }
}

C# script example

var target: Transform;

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


// Calculate the frustum height at a given distance from the camera.
function FrustumHeightAtDistance(distance: float) {
    return 2.0 * distance * Mathf.Tan(camera.fieldOfView * 0.5 * Mathf.Deg2Rad);
}


// Calculate the FOV needed to get a given frustum height at a given distance.
function FOVForHeightAndDistance(height: float, distance: float) {
    return 2 * Mathf.Atan(height * 0.5 / distance) * Mathf.Rad2Deg;
}


// Start the dolly zoom effect.
function StartDZ() {
    var distance = Vector3.Distance(transform.position, target.position);
    initHeightAtDist = FrustumHeightAtDistance(distance);
    dzEnabled = true;
}


// Turn dolly zoom off.
function StopDZ() {
    dzEnabled = false;
}


function Start() {
    StartDZ();
}


function Update () {
    if (dzEnabled) {
        // Measure the new distance and readjust the FOV accordingly.
        var currDistance = Vector3.Distance(transform.position, target.position);
        camera.fieldOfView = FOVForHeightAndDistance(initHeightAtDist, currDistance);
    }
    
    // Simple control to allow the camera to be moved in and out using the up/down arrows.
    transform.Translate(Input.GetAxis("Vertical") * Vector3.forward * Time.deltaTime * 5);
}

JS script example

Размер усечённой пирамиды на данном расстоянии от камеры
Лучи из камеры
Copyright © 2023 Unity Technologies
优美缔软件(上海)有限公司 版权所有
"Unity"、Unity 徽标及其他 Unity 商标是 Unity Technologies 或其附属机构在美国及其他地区的商标或注册商标。其他名称或品牌是其各自所有者的商标。
公安部备案号:
31010902002961