I removed all damping on the Cinemachine and set the camera update to manual. the rotation is working fine however, it seems the rotation starts after the camera rotates and seems to be behind by a few frames. Any ideas on how I remove this “start delay”?
Rotation Code if it helps (Using ECS…please ignore the poor structure, I’m still debugging)
Entities
.WithName("CinemachineECSJob")
.WithoutBurst()
.WithAll<CinemachineECSData>()
// .WithReadOnly(world)
// .WithReadOnly(timeAhead)
// .WithReadOnly(systemData)
.ForEach((Entity entity, CinemachineECSConverterComponent monoBehaviour, ref CinemachineECSData cinemachineECSData) =>
{
// update the GameObjest's position (this is the gameobject the cinemachine camera is following)
monoBehaviour.transform.position = systemData.Position;
// update the rotation of the Target Entity base on cinemachine's rotation
// NOTE: this is coded with the CinemachineFreeLook Component in mind
CinemachineFreeLook freeLook = monoBehaviour.CinemachineGO.GetComponent<CinemachineFreeLook>();
CinemachineBrain brain = monoBehaviour.MainCamera.GetComponent<CinemachineBrain>();
if (freeLook != null)
{
Debug.Log(math.degrees(systemData.internalData.CurrentRotationAngle) + "::" + freeLook.m_XAxis.Value);
float3 up = Core.GameSettings.DetermineUpUsingGravity(Core.GameSettings.GameSettingsPhysicsStep.Gravity,systemData.controllerComponentData.Gravity);
systemData.internalData.CalculateRotation = false;
systemData.internalData.CurrentRotationAngle = math.radians(freeLook.m_XAxis.Value);
Rotation r = GetComponent<Rotation>(systemData.TargetEntity);
SetComponent(systemData.TargetEntity, new Rotation { Value = math.normalize(math.mul(r.Value,quaternion.AxisAngle(up,systemData.internalData.CurrentRotationAngle-systemData.internalData.LastRotationAngle))) });
systemData.internalData.LastRotationAngle = systemData.internalData.CurrentRotationAngle;
}
else Debug.LogWarning("CinemachineECSJob: Failed to get CinemachineFreeLook Component!");
SetComponent(systemData.TargetEntity, systemData.internalData);
brain.ManualUpdate();
}).Run();
Are you trying to update the rotation of the follow target based on the rotation of the camera? If so, then you’re creating a feedback loop because the FreeLook’s Binding Mode is Lock To Target - which means that it takes its rotation from the follow target. Try setting the binding mode to World Space.
My bad i forgot to add that the CameraParent target that the Cinemachine camera is set to follow and rotate around is not being rotated through code. it is a child (using ECS’s PreviousParent) of the GameObject I am applying the rotate code to.
But now that you mention it, since it is a child of the thing I’m rotating the it’s LocalToWorld is being affected by the parent according to this
so trying to negate the rotation but all that achieved was glitchiness every 10-20 frames so I changed some code and did some tests and think it might be a timing issue. I think the ECS Job that sets the rotation may be faster or slower than the CinematicCamera GameObect.
I just realized this is not true and I’m manually updating the position of the CameraParent transform in the Job as well so the Parent issue doesn’t apply
[Edit]: forgot to dropdown CameraParent in the image
Anything that says has “Manager” in it is an empty game object i use to organize.
The CameraParent is what Cinemachine Follows and looks at.
In the Job, the transform position of CameraParent is being set. The Rotation of ElectrodeDummy is being set based on the CinemachineFreeLook current rotation value.
Entities
.WithName("CinemachineECSJob")
.WithoutBurst()
.WithAll<CinemachineECSData>()
// .WithReadOnly(world)
// .WithReadOnly(timeAhead)
.WithReadOnly(systemData)
.ForEach((Entity entity, CinemachineECSConverterComponent monoBehaviour, ref CinemachineECSData cinemachineECSData) =>
{
CinemachineBrain brain = monoBehaviour.MainCamera.GetComponent<CinemachineBrain>();
brain.ManualUpdate();
// update the CameraParent's position (this is the gameobject the cinemachine camera is following)
monoBehaviour.transform.position = systemData.Position;
// update the rotation of the Target Entity base on cinemachine's rotation
// NOTE: this is coded with the CinemachineFreeLook Component in mind
CinemachineFreeLook freeLook = monoBehaviour.CinemachineGO.GetComponent<CinemachineFreeLook>();
if (freeLook != null)
{
// Debug.Log(math.degrees(systemData.internalData.CurrentRotationAngle) + "::" + freeLook.m_XAxis.Value);
float3 up = Core.GameSettings.DetermineUpUsingGravity(Core.GameSettings.GameSettingsPhysicsStep.Gravity, systemData.controllerComponentData.Gravity);
systemData.internalData.CalculateRotation = false;
// quanternion is in radians so we have to convert
systemData.internalData.CurrentRotationAngle = math.radians(freeLook.m_XAxis.Value);
// difference of (current - previous) rotation (in radians)
float difference = systemData.internalData.CurrentRotationAngle - systemData.internalData.LastRotationAngle;
// get rotation of ElectrodeDummy
Rotation r = GetComponent<Rotation>(systemData.TargetEntity);
// add rotation difference to ElectrodeDummy Rotation
SetComponent(systemData.TargetEntity, new Rotation { Value = math.normalize(math.mul(r.Value, quaternion.AxisAngle(up, difference))) });
// set last rotation to current rotation for later calculation
systemData.internalData.LastRotationAngle = systemData.internalData.CurrentRotationAngle;
}
else Debug.LogWarning("CinemachineECSJob: Failed to get CinemachineFreeLook Component!");
SetComponent(systemData.TargetEntity, systemData.internalData);
}).Run();
Your image isn’t coming through, but the hierarchy is visible in a previous post (duh) so it’s ok. I’m having a little trouble understanding what you’re trying to do with the camera. Can you describe in words how you want the camera to behave and its relationship with the target?
I want the Cinemachine Camera to rotate around and look at the CameraParent object. This is working fine. However, when I move my mouse i notice there is a very slight rotation delay (a few frames, barely noticable) on the ElectrodeDummy GameObject (the rotation is set in code and the GameObject not attached to Cinemachine Camera or targeted by it).
Now that i think about this could be an ECS issue rather than a Cinemachine issue.
If you want i can make a short video on it and post it.
So ElectrodeDummy (which I understand is a child of the non-rotating CameraParent object) is supposed to rotate to match the main camera’s Y rotation? Is that correct?
ElectrodeDummy and CameraParent do not have a parent/child relationship. In the ECS Job i set the position of CameraParent to ElectrodeDummy manually.
// update the CameraParent's position (this is the gameobject the cinemachine camera is following)
// systemData.Position is a float3 representing the position of ElectrodeDummy
CameraParent.transform.position = systemData.Position;
and yes, ElectrodeDummy is supposed to match the main camera’s Y rotation.
The ECS job moves the CameraParent to the ElectrodeDummy’s (Electrode Dummy is a general Entity that i plan to have many of so i have a different system handle them)
But It’s Fixed
I moved the brain.ManualUpdate() around to other functions and found that all i needed was the the ManualUpdate() to be called before the applied rotation and after the call to set the CameraParent’s Position.
Entities
.WithName("CinemachineECSJob")
.WithoutBurst()
.WithAll<CinemachineECSData>()
.WithReadOnly(systemData)
.ForEach((Entity entity, CinemachineECSConverterComponent monoBehaviour, ref CinemachineECSData cinemachineECSData) =>
{
// update the CameraParent's position (this is the gameobject the cinemachine camera is following)
// systemData.Position is a float3 representing the position of ElectrodeDummy
monoBehaviour.transform.position = systemData.Position;
// update HERE!
CinemachineBrain brain = monoBehaviour.MainCamera.GetComponent<CinemachineBrain>();
brain.ManualUpdate();
// update the rotation of the Target Entity base on cinemachine's rotation
// NOTE: this is coded with the CinemachineFreeLook Component in mind
CinemachineFreeLook freeLook = monoBehaviour.CinemachineGO.GetComponent<CinemachineFreeLook>();
if (freeLook != null)
{
// Debug.Log(math.degrees(systemData.internalData.CurrentRotationAngle) + "::" + freeLook.m_XAxis.Value);
float3 up = Core.GameSettings.DetermineUpUsingGravity(Core.GameSettings.GameSettingsPhysicsStep.Gravity, systemData.controllerComponentData.Gravity);
systemData.internalData.CalculateRotation = false;
// quanternion is in radians so we have to convert
systemData.internalData.CurrentRotationAngle = math.radians(freeLook.m_XAxis.Value);
// difference of (current - previous) rotation (in radians)
float difference = systemData.internalData.CurrentRotationAngle - systemData.internalData.LastRotationAngle;
// get rotation of ElectrodeDummy
Rotation r = GetComponent<Rotation>(systemData.TargetEntity);
// add rotation difference to ElectrodeDummy Rotation
SetComponent(systemData.TargetEntity, new Rotation { Value = math.normalize(math.mul(r.Value, quaternion.AxisAngle(up, difference))) });
// set last rotation to current rotation for later calculation
systemData.internalData.LastRotationAngle = systemData.internalData.CurrentRotationAngle;
}
else Debug.LogWarning("CinemachineECSJob: Failed to get CinemachineFreeLook Component!");
SetComponent(systemData.TargetEntity, systemData.internalData);
}).Run();
Thank you for your help everything looks perfect now! I can’t wait to furture explore into Cinemachine