Constant speed on Dolly Track

Hey guys,

I’m trying to move the camera with constant speed on a dolly track.
I managed to calculate the length of the segments between two waypoints and animate the “Path Position” value based on that.
What I noticed is that when the camera is approaching the next waypoint, it slows down a bit.
All the damping values are set to 0. Am I missing something? Is there a way to bypass the easing?

Thanks for your help. :slight_smile:

If your damping is off and you are correctly calculating the required path positions, then there should be no slowing down at the waypoints. Can you attach your code that calculates the path positions? There is some interest in the Unity community for this feature. See for instance Taking fixed distance steps down dolly path - Unity Engine - Unity Discussions
Thanks

Hi Gregoryl,

Thanks for your quick reply!
See my test script below.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Cinemachine;
using UnityEditor;

public class MoveCameraTest : MonoBehaviour {

    public CinemachineVirtualCamera virtualCamera;
    public CinemachinePath path;
    public AnimationCurve curve;
    public float runningTime;
    public float totalDuration;
    public float currentPercentage;

    private CinemachineTrackedDolly dolly;
    private float pathLength;

    private float[] pointPercentages;

    void Start(){
        dolly = virtualCamera.GetCinemachineComponent<CinemachineTrackedDolly> ();

        pointPercentages = new float[path.m_Waypoints.Length + 1];
        pointPercentages [0] = 0;
        Keyframe keyframe = new Keyframe (0, 0);
        curve.AddKey (keyframe);

        float length = 0;
        float step = 1f / path.m_Appearance.steps;

        //Calculate total length of path
        for (float t = path.MinPos + step; t <= path.MaxPos + step / 2; t += step) {
            Vector3 prev = path.EvaluatePosition(t-step);
            Vector3 p = path.EvaluatePosition(t);
            length += Vector3.Distance (prev, p);
        }

        pathLength = length;

        float partialLength = 0;
        int counter = 0;
        int currentStep = 0;
        float currentPercentage = 0;

        //Build speed curve
        for (float t = path.MinPos + step; t <= path.MaxPos + step / 2; t += step) {
            Vector3 prev = path.EvaluatePosition(t-step);
            Vector3 p = path.EvaluatePosition(t);
            partialLength += Vector3.Distance (prev, p);
            counter++;
            if (path.m_Appearance.steps == counter) {
                currentStep = Mathf.RoundToInt (t);
                currentPercentage = (partialLength / pathLength);
                pointPercentages [currentStep] = currentPercentage;
                counter = 0;
                keyframe = new Keyframe (currentPercentage, currentStep);
                curve.AddKey (keyframe);
            }
        }

        for (int i = 0; i < curve.keys.Length; i++){
            AnimationUtility.SetKeyLeftTangentMode (curve, i, AnimationUtility.TangentMode.Linear);
            AnimationUtility.SetKeyRightTangentMode (curve, i, AnimationUtility.TangentMode.Linear);
        }
    }

    void Update(){
        runningTime += Time.deltaTime;
        currentPercentage = runningTime / totalDuration;

        if (runningTime >= totalDuration) {
            runningTime -= totalDuration;
        }
        dolly.m_PathPosition = getPathPositionFromPercentage (currentPercentage);
    }

    float getPathPositionFromPercentage(float perc){
        return curve.Evaluate(perc);
    }
}

Your script was not sampling the path correctly. Try this instead:

using UnityEngine;
using Cinemachine;
using UnityEditor;

public class MoveCameraTest : MonoBehaviour
{
    public CinemachineVirtualCamera virtualCamera;
    public CinemachinePath path;
    public AnimationCurve curve;
    public float velocity;
    public float currentDistance;

    private float pathLength;
    private CinemachineTrackedDolly dolly;

    void SamplePath(int stepsPerSegment)
    {
        curve = new AnimationCurve();
        float minPos = path.MinPos;
        float maxPos = path.MaxPos;
        float stepSize = 1f / Mathf.Max(1, stepsPerSegment);

        pathLength = 0;
        Vector3 p0 = path.EvaluatePosition(0);
        curve.AddKey(new Keyframe(0, 0));
        for (float pos = minPos + stepSize; pos <( maxPos + stepSize/2); pos += stepSize)
        {
            Vector3 p = path.EvaluatePosition(pos);
            pathLength += Vector3.Distance(p0, p);
            curve.AddKey(new Keyframe(pathLength, pos));
            p0 = p;
        }

        for (int i = 0; i < curve.keys.Length; i++)
        {
            // TODO: replace this with something that does not depend on editor
            AnimationUtility.SetKeyLeftTangentMode(curve, i, AnimationUtility.TangentMode.Linear);
            AnimationUtility.SetKeyRightTangentMode(curve, i, AnimationUtility.TangentMode.Linear);
        }
    }
       
    void Start()
    {
        dolly = virtualCamera.GetCinemachineComponent<CinemachineTrackedDolly>();
        if (path != null)
            SamplePath(path.m_Appearance.steps); // TODO: decouple numSteps from appearance setting
    }

    void Update()
    {
        int numKeys = (curve != null && curve.keys != null) ? curve.keys.Length : 0;
        if (dolly != null && numKeys > 0 && pathLength > Vector3.kEpsilon)
        {
            currentDistance += velocity * Time.deltaTime;
            currentDistance = currentDistance % pathLength;
            dolly.m_PathPosition = curve.Evaluate(currentDistance);
        }
    }
}

Hi Gregoryl,
Great, your solution works fine. I can now move the camera with constant speed! :smile:
Thanks a lot!

Is there an updated version of this code for Unity version 2018.3.12f1? I’m looking for some way to have the camera move with constant speed on the dolly track. I’m just learning to include custom code in my projects but when I used the script above, it had problems with:

SamplePath(path.m_Appearance.steps); // TODO: decouple numSteps from appearance setting

This is very old, and is now outdated. Cinemachine now comes with a script called CinemachineDollyCart. You add it to a gameObject, connect it to a path, and it will move with constant speed along the path.

You can have your vcam track the cart with a transposer or LockToTarget behaviour, or you can add a DoNothing vcam as a child of the cart.

2 Likes

Thank you. I will try it out.

1 Like

Thanks Gregory, your suggestion worked like a charm. Previously, I had created the Cinemachine Dolly Camera with Track, and it didn’t have the option for the constant speed. It was like being on a roller coaster; fast on turns and going down. This motion was disorienting for VR-type apps and recordings. Using your suggestion, I created the Dolly Track with Cart, I deleted the new Dolly Track (I already had a Dolly Track created), and kept just the Dolly Cart. The script for the Dolly Cart had the Speed variable that I adjusted to get the speed just right. I set the Path to the previously created Dolly Track and Added the Component for The Cinemachine Virtual Camera (DoNothing vcam). Viola! Does what I wanted it to do. Glad to have found this thread from a few years back how Unity has evolved the product to include this functionality out of the box.

I’d like to enhance my project with a small drone flying directly in front of the DollyCart and was trying to figure out whether there’s a way for an asset to be pathed to the DollyCart, but it seems like DollyCarts and DollyTracks are just for the vcams.

The point of the dolly cart is to have something that can follow a path. It’s just an ordinary object, not tied to vcams. You can attach anything to it. Also, you can have as many carts as you like on the same path.

Very cool. Added this script (component) to the DollyCart and added my Drone GameObject as the Font Object. Working great. I’m going to have a lot of fun creating Dolly Tracks and Dolly Carts. Thanks again Gregory for the quick response.

using UnityEngine;
using System.Collections;

public class MovewithCamera : MonoBehaviour
{

public GameObject frontObject;
public float distance;

void LateUpdate()
{
    frontObject.transform.position =  this.gameObject.transform.position  + this.gameObject.transform.forward * distance;
    frontObject.transform.rotation =    new Quaternion(0.0f, this.gameObject.transform.rotation.y, 0.0f, this.gameObject.transform.rotation.w);
    }
}
1 Like

Why don’t you just parent it in the hierarchy at the offset you like? That way you won’t need the script.

OMG. I disabled the script, threw the gameobject below the DollyCart…held my breath, and pressed Play. It worked! I’m just blown away by what Unity can do.

4540303--421021--upload_2019-5-14_12-59-55.png

Thank you very much.

1 Like

How do I change speed to slower on the dolly track? (Not cart) @Gregoryl

@mattis89 Track itself does not have a speed. What object are you talking about? Can you show the inspector?

How fast the camera travels on the track… how to change speed sir?

There is no speed limit on the vcam if it’s following a target. You can only control the damping. To do a speed limit you would have to put a vcam in a cart and implement your own movement - or have an intermediate invisible target that moves toward your real target at a fixed speed - and have the vcam track that instead

Yes! I used a cart instead, works good… But the virtual camera noise profiles, I cant create new because create is greyed out, and I cant duplicate a preset nothing happends, and I when I mark a noise profile, I can click “gearwheel” or edit…? why have you guys locked it ?

It’s not locked for me. What version of CM are you using?

5151437--510389--upload_2019-11-7_16-23-50.png

Latest from package manager… really weird… Also I build with no errors, still as soon as I run it, it crash (in build)