How to shake camera with cinemachine?

Hello,Can anyone help me with this?
I used to shake camera with script when the charactor was hit by attack,
After using cinemachine the script doesn’t work,How can I shake the camera with cinemachine?

1 Like

Use the Noise module.

hey @Tak2017 , got the same issue, this is what I’ve done:

  • In the freeCamera, go and add a noise pattern, put AmplitudeGain and FrequencyGain to 0.
  • Add the following code in your camera function
  • launch the code with a “StartCoroutine(_ProcessShake (5, 0.5f) );”
        private IEnumerator _ProcessShake(float shakeIntensity = 5f, float shakeTiming = 0.5f)
        {
                Noise(1, shakeIntensity);
                yield return new WaitForSeconds(shakeTiming);
                Noise(0, 0);
        }

        public void Noise(float amplitudeGain, float frequencyGain)
        {
            cmFreeCam.topRig.Noise.m_AmplitudeGain = amplitudeGain;
            cmFreeCam.middleRig.Noise.m_AmplitudeGain = amplitudeGain;
            cmFreeCam.bottomRig.Noise.m_AmplitudeGain = amplitudeGain;
              
            cmFreeCam.topRig.Noise.m_FrequencyGain = frequencyGain;
            cmFreeCam.middleRig.Noise.m_FrequencyGain = frequencyGain;
            cmFreeCam.bottomRig.Noise.m_FrequencyGain = frequencyGain;       

        }
1 Like

Thanks very much! I’ll try this!

@Tak2017 Don’t take the syntax in the example too literally. Have a look at Cinemachine/Examples/Scenes/Scripting/ScriptingExample.cs for the correct syntax for accessing CM camera component members.

3 Likes

I want to shake strongly in very short time like 6 to 10 frames,not the handheld style.Thank you all the same~

@Tak2017 : @JakubSmaga and @sebsmax are right: use the noise module. Pulse the amplitude to get the shake. Alternatively, you can make a custom noise module that listens to a channel and adds an extra pulse to the background noise. You can make this quite easily by copying CinemachineBasicMultiChannelPerlin.cs and modifying the copy to create a custom noise module with your extra stuff.
See this post: How to config Cinemachine on a FPS - Unity Engine - Unity Discussions

Thanks for your reply!I’ll Try this,and post my progess later,thank you!

@sebsmax @Tak2017 @Gregoryl Thank you!

CinemachineVirtualCamera vcam;
CinemachineBasicMultiChannelPerlin noise;

void Start() {
        vcam = GameObject.Find("CM vcam1").GetComponent<CinemachineVirtualCamera> ();
        noise = vcam.GetCinemachineComponent<CinemachineBasicMultiChannelPerlin> ();
}

public void Noise(float amplitudeGain, float frequencyGain) {
        noise.m_AmplitudeGain = amplitudeGain;
        noise.m_FrequencyGain = frequencyGain;     
}
5 Likes

Duplicating my post here from How to enable Camera Noise via script? - Unity Engine - Unity Discussions

@Gregoryl You suggest to use the BasicMultiChannelPerlinNoise extension component, which is fine in this kind of setup where you have a Scene with one VirtualCamera that is always shaking.

I’m looking for more of game-event driven camera shake to make short-duration events during play more impactful, like player getting damage, things breaking, final hits when defeating enemies, explosions happening.

The thing is that there is a vast amount of Scenes, each with similarly large number of VirtualCameras, and some VirtualCameras are actually already using the noise component for something else that they need to emphasize.

I’d like to setup a system where I can pretty much call CameraShake.Shake(someShakeTemplateParameter) where someShakeTemplateParameter is probably a ScriptableObject with various intensity and duration variables set up so I can call “CameraShake.Shake(playerHitShake);” or “CameraShake.Shake(hugeExplosion);” and such in code where enemies hit or bombs go off.

I already threw together a class that tries to do a lot of things, like:

  • look for a CameraBrain to get the active VirtualCamera from

  • tracks Scene changes to re-look for a new CameraBrain and check for all other current references

  • tracks current CameraBrains VirtualCameraActivation event to check if it needs to Add or Get a new BasicMultiChannelPerlinNoise component for the current VirtualCamera

  • Hijacks the BasicMultiChannelPerlinNoise component and forces a new noise profile, new amplitude and new frequency values, storing the old values

  • restores the old values after a duration

  • etc.

The system is not perfect by a long shot. It’s easy to lose track of a VirtualCamera before restoring something and my quickly implemented system already managed to fail a couple of tests for tracking the VirtualCamera changes, so there’s somewhere a on-standby VirtualCamera shaking wildly, while the active one no longer shakes when expected to.

Yeah, I will probably try to improve my system to use your recommendation of VirtualCamera noise for camera shake, but it’s a lot of work, breaks using the noise for other purposes, requires constantly adding/getting a ton of component references and I feel there has to be a better way.

1 Like

There is very much a better way. Cinemachine has moved forward since the recommendation of using BasicMultiChannelPerlinNoise for camera shakes, and I would no longer recommend that approach.

Right now in development is the Cinemachine Impulse system, which does something very much like what you describe (i.e. scriptable-object Shake definitions, and the ability to broadcast shakes to all active cameras). It really is exactly what you need. However, it’s not quite ready for prime-time so I can’t let you give it a spin just yet. But it’s pretty close.

If you’re in a hurry to get something up and running now, I would suggest the following approach:

  • Forget about using the BasicMultiChannelPerlinNoise component, for all the reasons you outline. Throw that idea away.
  • Use the CinemachineExtension API to write a camera shaker. I’ll include a simple example below, that shakes the camera continuously. Use that as a starting point for your extension.
  • Instead of shaking the camera continuously, have the shaker extension query a singleton for current active “shakes”, and apply the signal to the vcam.
  • The "CameraShake(shakeDefinition) method could live on the singleton. Your game code would call it to initiate shakes.
  • The key is not to push the shakes to the vcams. Let them listen for shakes instead, via the CameraShake extension. Put that extension on all your vcams. It won’t interfere with any Perlin Noise that’s on the vcams.

That would be a baby version of the Impulse system. Of course you could just wait a few weeks for the real deal instead of home-brewing. Here is the sample extension I mentioned:

using UnityEngine;
using Cinemachine;

/// <summary>
/// An add-on module for Cinemachine to shake the camera
/// </summary>
[ExecuteInEditMode] [SaveDuringPlay] [AddComponentMenu("")] // Hide in menu
public class CameraShake : CinemachineExtension
{
    [Tooltip("Amplitude of the shake")]
    public float m_Range = 0.5f;

    protected override void PostPipelineStageCallback(
        CinemachineVirtualCameraBase vcam,
        CinemachineCore.Stage stage, ref CameraState state, float deltaTime)
    {
        if (stage == CinemachineCore.Stage.Body)
        {
            Vector3 shakeAmount = GetOffset();
            state.PositionCorrection += shakeAmount;
        }
    }

    Vector3 GetOffset()
    {
        // Note: change this to something more interesting!
        return new Vector3(
            Random.Range(-m_Range, m_Range),
            Random.Range(-m_Range, m_Range),
            Random.Range(-m_Range, m_Range));
    }
}
5 Likes

Wow, that’s a fantastic response! Thank you for staying civil in the face of my rant and providing such a prompt, informative and immediately helpful answer!

We’re running on a deadline, so I don’t quite have the time to roll my own at this point, nor can I simply wait for two weeks, but your example will tide my needs over as a nice compromise. I’ll use that to implement a quick temporary solution and hope that your Impulse system will be available in two weeks - if not, I’ll scramble to improve the slap-patch solution, but at least now I don’t have an immediate need to allocate much time for it. :slight_smile:

1 Like

@Gregoryl Any updates on the Cinemachine Impulse System that you can share? Any ETA? :stuck_out_tongue:

Yes, it will be there in the next CM release, to coincide with Unite Berlin.
It’s possible that there will be some preview releases prior to then.

2 Likes

Did this feature make it into 2.1.12?

No, but it’s on the verge.

Hey Greg, quick question on the code you posted:

Which object do I attach this script? Would it be one of the virtual cams? Would I call this class in another script and pass it the virtual cam? Also how would I control the time to shake? Would I Slerp the total shake over a set amount of time using a while loop in a coroutine?

Let me know and thanks!

@sandBucket2 You just drop the script in your project, and it will show up in the virtual camera “Extensions” menu. Add it to the vcam from there.

For making a pulse, you would need to set an amplitude and a duration. I would decay the amplitude over the course of the duration, not necessarily with a lerp, as that would look mechanical. Use some kind of exponential damping. You could do that animation in a coroutine, as you suggested. It will only shake the vcam it’s attached to.

Thanks! Also an offtopic question:

I’ve tried to import the latest post processing stack (v2) off github but I keep getting this error after import: Assets/PostProcessing/CinemachinePostFX.cs(45,28): error CS0234: The type or namespace name PostProcessing' does not exist in the namespace UnityEngine’. Are you missing an assembly reference?

I’m using Unity 2017 but I’ve heard that cinemachine works with the v2 stack on 2017. How would I go about fixing this?

If you’re using Post v2 then you can just delete the file that’s generating the errors. It’s for Post v1 and you don’t need it.