Is there any alternatives to the Node3D's look_at function so that I do not have to rely on creating a node, in order to get what would be the rotation value of a node 'looking at' a specific position.

In code, it might look like this

func get_look_at_rotation(from, to) -> Vector3:
    var node = Node3D.new()
    node.global_position = from
    node.look_at(Vector3(20, 50, 40), Vector3.UP)
    return node.rotation
#

# Something like this
get_look_at_rotation(Vector3(50, 50, 50), Vector3(20, 30, 40))

xyz

I am trying to set the camera_rig's position so that it positioned away from the object it is following at vector distance away from the item it is following.

I might be better to position a node inside the camera rig and use that to set a relative position. I might also need to brush up on my maths knowledge. I am currently watching a video series on youtube on how to do 3d maths for game development.

	# Get direction from follow_this position to camera ( as normalized direction )
	var follow_this_rotation = follow_this.rotation
	follow_this.look_at(target_vector_distance)
	var forward_dir = follow_this.basis.z
	follow_this.rotation = follow_this_rotation
	
# Prints Vector3(nan, nan, nan)  ????
	print(forward_dir)
	var magnitude = follow_this.global_position.distance_squared_to(camera.global_position)
	
	camera_rig.global_position = follow_this_pos + Vector3(0, target_height, 0) - (forward_dir * magnitude)

Not sure I fully understand it. You want to position the camera at a certain offset from the target and orient it so that it looks at the target?

    xyz Yes, it sounds like you do understand. I think using a camera rig node would make sense in this case. I just wouldn't know the maths (for setting the global_position of the camera rig directly instead of using Godot's node system to correctly position and offset the camera rig).

    I was just trying to write in a code a way to set the position of a camera rig so that it has a rotatable offset. The camera seems to already be rotated to look towards the target.

    • xyz replied to this.

      zerohootsoliver No, I don't think I fully get it. If you want to position the camera with some offset simply take the position of the target, add that offset and assign the result to the camera/rig position property. But I suspect you perhaps want the offset to be taken in target's local space/basis so that camera is always "behind" the target (with the offset). In other words it's not just offset in the world or parent space but the target orientation also matters. I'm not sure this is what you want though. It's not completely clear from your description. Perhaps post a video from an existing game that has the exact camera follow behavior you want to implement.

      You can, but writing a look at math function is way more complicated than using a node. What I usually do is create a node in the scene (could be in the editor), just one node I call "Target". Then I use this whenever I need to function that takes nodes. I just first move the "Target" where I want, then send it to whatever function like look at. This is the easiest thing.

      Yeah you can do pretty much anything with math 🙂 Lookat is actually not that hard to implement, but when dealing with orientations in 3d you'd probably want to use quaternions because using euler xyz rotations for that is cumbersome and riddled with gotchas. I could write you the function but I'm not sure you actually need it. Also the result of lookat cannot be xyz rotation only. That's not enough information to fully describe orientation in 3d space. You'd typically output an orthonormal 3d basis (which is defined by at least 2 perpendicular normal vectors) or indeed a quaternion (which is 4 float values).

      Ok just for the sake of discussion here's a homemade lookat() without quaternions:

      func lookat(from: Vector3, to: Vector3, up: Vector3 = Vector3.UP) -> Basis :
      	var basis: Basis
      	basis.z = (from-to).normalized()
      	basis.x = up.cross(basis.z).normalized()
      	basis.y = basis.z.cross(basis.x).normalized()
      	return basis

      We can test it by comparing its output with what Node3D::look_at() does:

      # some random from and target
      randomize()
      var from = Vector3(rand_range(-100.0, 100.0), rand_range(-100.0, 100.0), rand_range(-100.0, 100.0))
      var target =  Vector3(rand_range(-100.0, 100.0), rand_range(-100.0, 100.0), rand_range(-100.0, 100.0))
      			
      # test node's look_at()
      var node = Spatial.new() # or Node3D.new() for Godot 4
      get_tree().get_root().add_child(node)
      node.translation = from
      node.look_at(target, Vector3.UP)
      print(node.transform.basis)
      
      # test our lookat()
      print(lookat(from, target, Vector3.UP))

      Results are the same:

      ((-0.575881, 0.566949, 0.589007), (0, 0.720469, -0.693488), (-0.817534, -0.399366, -0.414904))
      ((-0.575881, 0.566949, 0.589007), (0, 0.720469, -0.693487), (-0.817534, -0.399366, -0.414904))
      
      ((-0.531516, -0.637291, 0.557988), (0, 0.658744, 0.752367), (-0.847048, 0.399895, -0.350133))
      ((-0.531516, -0.637291, 0.557988), (0, 0.658744, 0.752367), (-0.847048, 0.399895, -0.350133))
      
      ((-0.892539, 0.08448, 0.442987), (0, 0.982297, -0.187329), (-0.45097, -0.167198, -0.876739))
      ((-0.892539, 0.08448, 0.442987), (0, 0.982297, -0.187329), (-0.45097, -0.167198, -0.876739))