Making Camera Shake using Impulse Listener Extensions
Yesterday we looked at the Noise settings within Cinemachine Virtual Cameras, but we can also introduce Noise by looking at the first of many Virtual Camera extensions, namely, the Impulse Listener Extension.
Setting an Impulse Listener Extension on a virtual camera, and subsequently adding Impulse Sources in the scene, we can dynamically use game logic to apply various levels of Noise to our cameras!
Our Impulse Listener, as stated in the image, receives Impulse signals throughout the scene via an Impulse Source. If our game is 2D, we should select 2D Distance, to eliminate the Z axis being calculated.
Our Channel Mask and Gain features, are predominantly for larger scale applications, in which we may want different cameras affected by different sources, and at different levels per camera. Channel Mask Layers work similarly to other layers, in that we can transmit and receive information only from other game objects within that layer.
An example of this, may be in a third person shooter, we want explosions or gunfire to add noise, but want this to be enhanced when aiming down the sights, or perhaps not triggered at all when focused on an object via another camera.
To show how we can use Impulse Sources, let’s create a simple gun, that when ‘shot’ will trigger an Impulse.
With a basic cube set up in our First Person camera, we can add a Cinemachine Impulse Source component to the ‘gun’.
Here, we first have the ability to set the transmission channel. Next, we need to create a Noise setting for our Raw Signal input. Before we continue on with parameters, we should first set this up.
Our Noise Setting contains 6 graphs, 3 for Position, and 3 for Rotation, across each 3 of the axes. Adjusting their individual frequencies and amplitudes, we can create up to a 6 dimensional impulse. For my gun shot, I have only opted for rotation noise, as positional changes can effect gameplay too much when trying to aim.
Now we can continue looking at our Impulse Source settings. Similarly to the Impulse Listener we have a master Amplitude and Frequency gain to alter all 6 dimensions as a whole, as well as opting to randomize the starting position across the graph each time.
Next we can create our Time Envelope, similar to an audio source — altering how quick the impulse starts, holds at full force, then dies out.
Lastly, we have Spatial Range, which doesn’t actually apply to this instance as this gun will always be at camera position. But when having external Impulse Sources in our game world, we can have these dynamically adjust based on distance.
It’s important to note, that so far, we haven’t been able to actually preview the impulse, as we have no triggering code. Instead we can speculate and get a rough idea of parameters, but they will probably require tweaking later. Additionally, we could set up the game logic first. Either or!
To trigger the Impulse Source, I have created a simple PlayerWeapon script that gets a reference to the Impulse Source, then whenever we left click, a FireGun method is called. This would be where we instantiate bullets and carry out any impact logic, but for now, we are simply using the GenerateImpulse function.
Now to test and tweak! Already, this adds a great amount of player feedback for such a core element in video games.
Rather than using an Impulse Source, we can alternatively set up a Collision Impulse Source. This allows for the Generate method to occur internally based on physics collisions, rather than having other game logic such as our firing of a gun.
To achieve this, we follow a similar set up to that of the Impulse Source, this time, I’ve opted for a default Noise Setting. At the bottom of the component, we have two additional groups of parameters. The first being the Trigger Object Filter, which allows us to set a Layer Mask, as well as any Tags that the collisions should ignore.
How To Generate The Impulse allows us to make use of any Rigidbody collisions that may occur in our scene, using direction to alter rotation, as well as mass and speed to alter amplitude.
Now when the object this component is attached to, collides with anything in the Collision Layer, an Impulse will be generated that any nearby Impulse Listeners will pickup. For our case, we have attached the Impulse Collision Source to the player, and created an obstacle in the scene that is on the Collision layer. We could alternatively have our obstacles generate the Impulse, but if we start to have multiple game objects casting the same Impulse it would get much more intensive than it would to have one source and many colliders!
This obstacle has been set to Is Trigger for ease of demonstration, so our player capsule can simply pass through.
Remember, for Unity to detect collisions, one of the colliding objects requires a rigidbody!
One neat last little trick, is that Impulse Listeners don’t necessarily need to be on a virtual camera. We can use the exact same methods to apply impulses to any game objects in our scene!