Godot Version
4.5.1
Question
I have a 3D object (a 3D vector): VisVec in the image below. I want its tip to always face the camera.
I have attempted to do this by ensuring the tip is facing along the -Z axis in its scene, and placing it as such in the game scene, and then every frame calling look_at in the process function, passing in the camera position. Link to the look_at documentation.
extends Node3D
func _process(_delta: float) -> void:
var camera = get_viewport().get_camera_3d()
if (camera):
self.look_at(camera.position)
This video shows that the tip of the cone is not always facing the camera. Why is this?
Try
get_camera_3d().global_position
instead of
get_camera_3d().position
The global position is the actual position in world coordinates, the position variable is the position in the local reference frame, so probably zero.
I did try that before posting, assuming you mean this:
extends Node3D
func _process(_delta: float) -> void:
var camera = get_viewport().get_camera_3d()
if (camera):
self.look_at(camera.global_position)
Here’s a video of me orbiting it again, using global_position instead (I added more to the scene to give a more obvious visual reference frame for how it is rotating).
1 Like
If you had to rotate your VisVec for it to point -Z then it’s rotation will be reset by look_at, you could add a Node3D in between to keep the child’s rotation at -Z while the parent node can use look_at
1 Like
This fixed it! Yes, you are right, I did a -90 degree rotation about the x-axis in the scene to get it facing the -Z axis. I’ve instead moved them to a container node and applied that rotation to the container.
Just to add to @gertkeno’s answer, I believe this is the implementation in the source code. No attempt to preserve any rotations is made (which seems very obvious in hindsight, thank you again!)
Basis Basis::looking_at(const Vector3 &p_target, const Vector3 &p_up, bool p_use_model_front) {
#ifdef MATH_CHECKS
ERR_FAIL_COND_V_MSG(p_target.is_zero_approx(), Basis(), "The target vector can't be zero.");
ERR_FAIL_COND_V_MSG(p_up.is_zero_approx(), Basis(), "The up vector can't be zero.");
#endif
Vector3 v_z = p_target.normalized();
if (!p_use_model_front) {
v_z = -v_z;
}
Vector3 v_x = p_up.cross(v_z);
if (v_x.is_zero_approx()) {
WARN_PRINT("Target and up vectors are colinear. This is not advised as it may cause unwanted rotation around local Z axis.");
v_x = p_up.get_any_perpendicular(); // Vectors are almost parallel.
}
v_x.normalize();
Vector3 v_y = v_z.cross(v_x);
Basis basis;
basis.set_columns(v_x, v_y, v_z);
return basis;
}