As per the title, when using virtual cameras my “Camera.main” is null.
So how do i get the correct camera reference ?
As per the title, when using virtual cameras my “Camera.main” is null.
So how do i get the correct camera reference ?
Cinemachine does not affect Camera.main, it should still work if you tag your camera as the main camera.
So this will point to the active virtual camera at any given time? What about when two virtual cameras have the same priority such as if you wanted split screen? Or does main camera not connect to virtual cameras but rather the gameobject that has the tag?
I’m looking to obtain the active cameras specifically, so was not sure if I can still use camera.main or not for virtual cameras.
A virtual camera is not a camera. It controls a camera. In a single-screen game, there is only one camera (the one with the CM brain on it). In a split screen game, there are two cameras, each with a CM Brain, and each being controlled by its respective virtual cameras.
See here: Using Cinemachine | Cinemachine | 2.6.17
Camera.main applies to the Unity camera, not to the virtual cameras. To get a current active virtual camera, get the CM Brain from the Unity camera, then query the CM Brain for the active virtual camera.
Ah okay, thank you
If you have code that depends on the Camera position, you have to make sure to execute that code after CMBrain has positioned the camera. This happens in CinemachineBrain.LateUpdate. Note that CinemachineBrain has a late execution order, so you need to do this in LateUpdate in a script that has an execution order set greater than CinemachineBrain’s. Alternatively, you can use CinemachineCore.CameraUpdatedEvent, which fires after the camera has been positioned.
@Gregoryl I’ve removed my previous post because I thought I’ve resolved it but I’ve not.
Ok, I’ve tried to use the CameraUpdatedEvent to set the new position for my object but it’s still flickering (only when the camera moves).
Here’s my code.
private Vector3 offset = Vector3.forward * 2f;
private readonly float duration = 2f;
private float time = 0f;
private void ShowToCamera (CinemachineBrain brain)
{
transform.position = Vector3.Lerp(transform.position, brain.OutputCamera.transform.TransformPoint(offset), time / duration);
time += Time.deltaTime;
if (time > duration)
{
CinemachineCore.CameraUpdatedEvent.RemoveListener(ShowToCamera);
GetComponent<Animator>().SetTrigger("ScaleDown");
Destroy(gameObject, 1f);
}
}
It’s hard to tell what’s going on without a little context.
Can you explain how this script is being used? A video of the issue would also help.
Here’s a video. It’s the gem I want to hook on the camera.
When the player enters the trigger attached to the gem then I add the above code as a listener to the UpdatedCameraEvent.
Attached here you can find the inspector for that gem and its child (a FBX model).
Here is what I understand:
Is that correct?
Not exactly.
Here’s how I set up Cinemachine.
This code says that the transition to the point in front of the camera will take “duration”:
transform.position = Vector3.Lerp(transform.position, brain.OutputCamera.transform.TransformPoint(offset), time / duration);
However, I’m guessing that the problem is related to aliasing between render frames and FixedUpdate frames.
What happens when you remove the RigidBody from the gem?
Yes, right. However, the result feels like it’s moving fast in front of the camera and stays there for a moment, because the starting point of the Vector3.Lerp() is the transform.position itself and it gets nearer and nearer. Not a very precise code but I like the result… unless it’s the cause of the flickering
I’ve tried to destroy the rigidbody component as soon as it’s triggered the gem collection. Same behaviour.
@Gregoryl Ah. It only flickers if the frame rate is consistently lower than 1 / fixedTimeStep (50 cps). I’ve first noticed this behaviour on mobile, then reproduced this on Mac by setting the Application.targetFrameRate to 30 fps.
I’ve then tried to debug it via Debug.Logs but I couldn’t understand why it happens. There’s more or less one Update cycle every two FixedUpdates. The target position hooked to the camera is changing every update and remains the same for FixedUpdate cycles. But now I’m using your CinemachineCore.updatedCameraEvent system.
I don’t understand why you need the RigidBody on the gem. You have a trigger SphereCollider on the child, right? And when the player enters that it launches your thing? What’s the gem’s RigidBody for?
I ask about it because I’m trying to simplify the problem. You manipulating the transforms in LateUpdate on a RigidBody spooks me.
Because if it is not for the Rigidbody I would not be able to have my OnTriggerEnter function called, since the Trigger Collider is on the child and I’m receiving the call OnTriggerEnter with a script attached to the parent.
The reason why the trigger collider is on the child (with the mesh renderer) is because it was once a MeshCollider, which I then changed for a SphereCollider without really thinking about simplifying the object.
Now I’ve tried to move the SphereCollider from the child to the parent, and I’ve also removed the Rigidbody from the parent. Just a SphereCollider on the parent, which has also the script attached. Same behaviour.
What happens when you change the brain’s BlendUpdateMode to FixedUpdate? That will cause your event handler to get called during FixedUpdate.
That simply and beautifully works.
@Gregoryl Why was that? Isn’t that setting for blending between two different virtual cameras? I’m not changing camera here.
I remember there was a reason why I didn’t want to mess up with those settings. But I don’t remember why I needed them that way. Well, let’s see what comes up.
Big thanks.
Hello. I tried
cinemachineBrain.ActiveVirtualCamera
But this is not returning the active virtual camera. Instead it returns the parent of the virtual cameras which holds the CinemachineStateDrivenCamera.
What is the correct way to get the active virtual camera?
Thanks
Hey,
StateDrivenCamera is an exception. In the code it is a Camera driven by other cameras.
You could do something like that to find your camera.
var currentCamera = CinemachineBrain.ActiveVirtualCamera().VirtualCameraGameObject;
if(currentCamera != null) {
var nestedCamera =. currentCamera.GetComponent<CinemachineStateDrivenCamera>();
if(nestedCamera != null) {
currentCamera = nestedCamera.LiveChild
}
}
Let us know if this works for you.