void RotateCubeTowardsCamera()
{
// Calculate the direction from the cube to the camera
Vector3 directionToCamera = mainCamera.transform.position - transform.position;
// Create a rotation that looks in the direction of the camera
Quaternion lookRotation = Quaternion.LookRotation(-directionToCamera, Vector3.up);
// Set the cube's rotation to the calculated rotation
transform.rotation = lookRotation;
}
My issue is that it’s very jittery, I think it might be conflicting with something but I have no idea what is could be conflicting with. Or maybe this is a poor implementation. This is currently running in the update loop. The object this script is attached to has no parents. Everything else movement related is operating in fixed update or update.
I did try to make the cube a child of the camera actually, it became an issue because of it’s position since I am using a cinemachine freelook camera (guess I didn’t specify that in OP, oops). The cube would just move in a circle by a specifiied offset, here is a video of what I mean:
maybe I just don’t know how to stop transforms like that but I assume that any further transform modifications would just conflict with the hierarchy and cause more jittering. Maybe I’m wrong though. Also I intend for have mild transforms of this cube when moving like the video below and like I said before I assume it would just jitter due to transform conflicts, but again maybe I’m wrong:
also just tried setting the function in after the cube position function here:
void UpdateCubePosition()
{
if (anchorObject == null) return; // Exit if no anchor object is assigned
// Convert the screen position to a world position relative to the camera
Vector3 targetWorldPosition = mainCamera.ViewportToWorldPoint(screenPosition);
// Calculate the offset from the anchorObject to the target position
Vector3 offset = targetWorldPosition - mainCamera.transform.position;
// Move the cube to maintain its position relative to the anchorObject
transform.position = anchorObject.position + offset;
}
Place the script below onto a default cube and it will place itself ahead of the camera. Be sure to set the mainCamera reference.
using UnityEngine;
public class HUD : MonoBehaviour
{
public Transform mainCamera;
void LateUpdate()
{
transform.position=mainCamera.position+mainCamera.forward*3;
transform.rotation=mainCamera.rotation;
}
}
nah that didn’t work either, my OP implied this but I didn’t specify that camera operates in fixedUpdate, if it was in late update it would be less severe but still wouldn’t fix the issue unfortunately. also no I will not move the brain to lateUpdate I like the camera damping that comes with the freelook camera and if I changed it to late update then simply moving around would look terrible since my character also moves in fixedUpdate. here’s another video of what I mean
yea putting the function you gave me in fixed update does decrease some of the lagging, but it’s not completely smooth yet. it does look better now though
FixedUpdate won’t be smooth unless it’s set to update at the same rate as your monitor which isn’t advisable if you’re using a high refresh rate monitor.
It seems your issue is more with CinemaMachine than anything. I’ve never used it myself and so I can’t really help you there.
Sorry for the late reply, I’ve been having some issues getting notifications.
The problem is that whether you use LateUpdate or FixedUpdate, you are using a stale camera position from the previous frame.
You must position your cube after Cinemachine has updated the camera transform. This happens very late in the frame, in CinemachineBrain.LateUpdate, and CinemachineBrain has a late execution order. The simplest way is to hook into CinemachineCore.CameraUpdatedEvent, which is fired immediately after the camera has been positioned. At that point your code can use the camera position to place the cube.
Thank you for the reply, it’s very much appreciated. I should probably update how this has went so far. For the position I just made it a child of the player since I don’t plan for it’s position to be different from how it already is. The main goal here is essentially an “aiming reticle” (or in this case an aiming polyhedron) where an enemy inside is targeted for an auto aim gun. So the this case the Object (Fire Control System or FCS) should always be infront of the player an should copy the position transforms of the player and the rotation transfroms of the camera. The position and left and right rotation is simply handled by making the FCS a child of the player. The left and right (or I guess horizontal relative to the camera) rotation is based on a function that matches the player’s rotation to the camera so that the player is always facing where the camera is horizontally (for whatever reason this does not give me an issue). I did that to make a new script to get the vertical rotation working but like before it is lagging for the reason you explained. Here is the script I’m working on that still has this issue.
using Cinemachine;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CamTargetRotate : MonoBehaviour
{
// Reference to the camera whose X rotation you want to match
[SerializeField] private CinemachineFreeLook targetCamera;
[SerializeField] private float TestValue;
[SerializeField] private float cameraXRotation;
public float rotateRange = 180f;
public float rotateMax = 67f;
public float rotateMin = -54f;
private float newRotateRange;
private float newRotateMax;
private float newRotateMin;
public float againRotateMax;
public float againRotateMin;
private float previousValue;
private void Start()
{
newRotateMax = 2f * rotateMax;
newRotateMin = -2f * rotateMin;
//againRotateMax = (rotateMax / 90f);
//againRotateMin = (rotateMin / -90f);
}
// Update is called once per frame
void Update()
{
// Get the current Y-axis value
float TestValue = targetCamera.m_YAxis.Value;
MatchCameraRotation();
}
void MatchCameraRotation()
{
if (targetCamera == null)
{
Debug.LogError("Target camera is not assigned.");
return;
}
//Changes the rotation max/min depending on whether the camera is above or below the middle camera value
if(targetCamera.m_YAxis.Value >= 0.5)
{
cameraXRotation = getThingRotation(newRotateMax);
}
else
{
cameraXRotation = getThingRotation(newRotateMin);
}
// Get the camera's current X rotation (pitch) value
//cameraXRotation = ((targetCamera.m_YAxis.Value - 0.5f) * rotateRange);
//these two stop the weird reflection each frame
if (cameraXRotation < -90)
{
cameraXRotation += 180;
cameraXRotation = -cameraXRotation;
}
if (cameraXRotation > 90)
{
cameraXRotation -= 180;
cameraXRotation = -cameraXRotation;
}
//experimental thing here
/*
if (cameraXRotation >= 0 && cameraXRotation < 90)
{
cameraXRotation *= againRotateMax;
}
if ( cameraXRotation < 0 && cameraXRotation > -90)
{
cameraXRotation *= againRotateMin;
}
*/
//these two set a max/min rotate value
if(cameraXRotation < rotateMin)
{
cameraXRotation = rotateMin;
}
if(cameraXRotation > rotateMax)
{
cameraXRotation = rotateMax;
}
// Apply the camera's X rotation to the object, keeping other axis the same
transform.localEulerAngles = new Vector3(cameraXRotation, transform.localEulerAngles.y, transform.localEulerAngles.z);
}
public float getThingRotation(float MaxMin)
{
return ((targetCamera.m_YAxis.Value - 0.5f) * MaxMin);
}
}
Now I tried for a bit to use the implementation you recommended but I’m having trouble understanding what you mean I guess. Here’s my attempt at achieving what you recommended:
private void Start()
{
newRotateMax = 2f * rotateMax;
newRotateMin = -2f * rotateMin;
// Subscribe to the Cinemachine camera update event to update the cube's rotation after the camera has been updated
CinemachineCore.CameraUpdatedEvent.AddListener(OnCameraUpdated);
//againRotateMax = (rotateMax / 90f);
//againRotateMin = (rotateMin / -90f);
}
// Unsubscribe from the event when the object is destroyed to avoid memory leaks
private void OnDestroy()
{
CinemachineCore.CameraUpdatedEvent.RemoveListener(OnCameraUpdated);
}
// Called after the Cinemachine camera has been updated
private void OnCameraUpdated(CinemachineBrain brain)
{
// Ensure the update is only applied when the correct camera is the active camera in the brain
// Casting to ICinemachineCamera to avoid the warning and ensure proper reference comparison
if (brain == null || brain.ActiveVirtualCamera != (ICinemachineCamera)targetCamera)
{
return;
}
// Get the current Y-axis value
float TestValue = targetCamera.m_YAxis.Value;
// The rotation update is now handled in OnCameraUpdated, so no need to call MatchCameraRotation here
// Update the cube's rotation
MatchCameraRotation();
}
I’m sure I’m just doing something wrong somewhere because this is giving the same kind of laggy response as before. I can send a video of what it looks like if you need it. Anyways thanks again for responding even if it was pretty long after the original post. And thanks if you have read this far as well.
Your code to extract the vertical rotation from the FreeLook appears sketchy to me. Why not take a different approach? I suggest this: in OnCameraUpdated, set your cube’s rotation to brain.OutputCamera.transform.rotation. That will exactly match what the camera is doing, and even if you later replace the FreeLook with a different style of camera, it will continue to work.
Have you considered upgrading to CM3? The samples there include some nice code for positioning aiming reticles.
Ah, didn’t know you could make a reference to the brain like that. When creating that script I was assuming that I could only access values from the objects components, hence the jury-rigged nature of it. Anyways it works perfectly now. Thanks a lot!!
I assume this requires me to upgrade my version of unity to a later version? I started working in this current version because I never bothered to update it in 2 years since I installed it and I’m not sure if Unity 6 is worth updating to. Does CM3 (and the engine in general) have any notable features/improvements compared to the one I’m currently using aside from the samples?
CM3 comes with some nice samples and is generally easier to work with. Event handling is better. If you’re happy with CM2 you can stick with it, we’ll be supporting it for a while.