Some resources:

The general thing I am seeing is that is is easiest to just have a node and use Godot's built in transform system handle it for you. So, if you have a mesh instance you want to rotate around a point, a scene tree like this is what you might want:

  • root (has script)
    • point
    • MeshInstance

And then you can move the point around using $point.global_transform.origin = Vector3(1, 1, 1) or similar and then use the normal Spatial functions for rotating, like #point.rotate_y(PI * delta) for example.

2 years later
2 years later

Ok so i need helps with this.

Still cant find where you can rotate camera around object like you can in blender.



The code below does simple thing:
If mouse3 button is pressed - sets is_rotating = true
and while true run rotate_camera() function

This dont work..

extends Node3D
@onready var camera_3d: Camera3D = $Camera3D
@onready var mouse_status: Label = $CanvasLayer/Control/PanelContainer/VBoxContainer/HBoxContainer/MouseStatus
@onready var mesh_instance_3d: MeshInstance3D = $MeshInstance3D

var is_rotating = false

func _unhandled_input(event: InputEvent) -> void:
	if event is InputEventMouseButton:
		#var lol = InputMap.get_actions()
		if event.is_action_pressed("action_mouse_middle"):
			# Rotate
			mouse_status.text = "Rotate"
			is_rotating = true
		if event.is_action_released("action_mouse_middle"):
			# Rotate
			mouse_status.text = "None"
			is_rotating = false
			pass
		if event.is_action_pressed("action_mouse_left"):
			# Rotate
			mouse_status.text = "Left"
		if event.is_action_released("action_mouse_left"):
			mouse_status.text = "None"
			pass
	if event is InputEventMouseMotion:
		if is_rotating:
			rotate_camera(event)
		
# Called when the node enters the scene tree for the first time.
func _ready() -> void:
	pass # Replace with function body.


# Called every frame. 'delta' is the elapsed time since the previous frame.
func _process(delta: float) -> void:
	
	pass

func rotate_camera(event:InputEventMouseMotion):

	camera_3d.rotate_y(deg_to_rad(-event.relative.x * 0.2))
	camera_3d.rotate_x(deg_to_rad(-event.relative.y * 0.2))
	camera_3d.rotation.x = clampf(camera_3d.rotation.x, deg_to_rad(-90), deg_to_rad(90))

	camera_3d.rotate_y(event.relative.y * 0.0010)
	camera_3d.rotate_x(event.relative.x * 0.0010)
	
	
	pass

I know how to do the rotation if you put camera inside 2 nodes:

func _input(event):
	if not is_multiplayer_authority(): return
	if event is InputEventMouseMotion and Input.mouse_mode == Input.MOUSE_MODE_CAPTURED:
		$h.rotate_y(deg_to_rad(-event.relative.x * h_sensitivity))
		$h/v.rotate_x(deg_to_rad(-event.relative.y * h_sensitivity))
		$h/v.rotation.x = clampf($h/v.rotation.x, deg_to_rad(cam_v_min), deg_to_rad(cam_v_max))

But i want to be able to do the same with just the camera.. im sure its possible? If not then ill just use the player char setup to do this 🙁...

  • Toxe replied to this.

    Toxe like i said earlier, the springarm code - working code. I want to solve this problem without additional nodes.

    Is it possible or not?

      kuligs2 Possible? Sure. Sensible? Not really. After all, that's exactly what the spring arm is for.

      But if you really want to do it on your own: How's your trigonometry (the math stuff with sine and cosine)? You need to know your current angle of rotation around your center point and your new angle after the rotation, your distance from the center, calculate your new camera position and then change the x/y position of the camera accordingly. After that rotate the camera so that it faces the center point.

      BTW, what are you trying to achieve? I feel like you are overcomplicating things.

      kuligs2 I want to solve this problem without additional nodes.

      "scientists were so preoccupied with whether they could, they didn't stop and ask themselves if they should've"

      Can't you look into Godots source code and translate it to gdscript?

      kuligs2
      This is trivial, not sure why it's causing so much confusion.
      Construct the rotation matrix and transform object's relative (to rotation origin) position by it. In the case of camera orbiting, the matrix you want is probably composed of delta rotations around up and local right axes. For camera, you'd also want to aim it at the rotation origin after each rotation.

      extends Camera3D
      
      @onready var target = $"../target"
      const SENSITIVITY = .02
      
      func orbit_point(origin: Vector3, point: Vector3, orbit_angle: Vector2) -> Vector3:
      	var d = point - origin
      	var t = Transform3D().rotated(Vector3.UP, orbit_angle.x).rotated(-d.cross(Vector3.UP).normalized(), orbit_angle.y)
      	return origin + t * d
      
      func _input(e):
      	if e is InputEventMouseMotion:
      		global_position = orbit_point(target.global_position, global_position, e.relative*SENSITIVITY)
      		look_at(target.global_position)

        xyz Thank you, dear Sir!. Will try to understand what happens, the oiler physics is too much for my brain.. also using transforms also not intuitive for me, not yet. Need to practice more to have a better understanding..

        One thing to note, to make it feel like blender, you need to pass inverted event.relative value

        func _input(e):
        	if e is InputEventMouseMotion:
        		global_position = orbit_point(target.global_position, global_position, -e.relative*SENSITIVITY) # < ---- Minus sign
        		look_at(target.global_position)

        Here is a demo.

        xyz

        Is there a way to have vertical rotation to be infinite, just like horizontal is?

        • xyz replied to this.

          kuligs2 Is there a way to have vertical rotation to be infinite, just like horizontal is?

          Of course there is.

          i guess ill sweat a bit over this

          • xyz replied to this.

            kuligs2

            extends Camera3D
            
            @onready var target = $"../target"
            const SENSITIVITY = .02
            
            func orbit_transform(origin: Vector3, t: Transform3D, orbit_angle: Vector2) -> Transform3D:
            	var dt = Transform3D().rotated(t.basis.x, orbit_angle.y).rotated(Vector3.UP, orbit_angle.x)
            	t.basis = dt.basis * t.basis;
            	t.origin = origin + t.basis.z * (t.origin - origin).length()
            	return t
            
            func _input(e):
            	if e is InputEventMouseMotion:
            		global_transform = orbit_transform(target.global_position, global_transform, e.relative*SENSITIVITY)

              xyz you just couldn't let me cook 😃, for atleast one day, thanks man!!!!!

              xyz is the king of the matrix and transforms 🙏