Hello
I want the 3d camera for my rubics cube act like this:
-click and hold left mousebutten while cursor outside cube should activate and hold the camera orbit function
-moving the mouse moves the camera related to mouse movement
-camera orbits around the 3d world-origin (where the cube is centered on)
-camera always points exactly on the world-origin
-horizontal movement can go in unlimited circles and vertical should stop exactly vertical above and below the cube
-only the x and y axis values of the camera angles should be used for this to keep the camera upright oriented
How to make the camera orbit in a fixed distance around the 3d world origin
- Edited
now i found this my self:
new spatial on world origin
camera as child in the spatial
camera in zero rotation towards it´s backside to distance of choice
This code to control the rotation of the spatial, that holds the camera:
func _process(delta):
if Input.is_action_just_pressed("rotate camera"):
old_rotation = camera.rotation_degrees
click_position = get_viewport().get_mouse_position()
if Input.is_action_pressed("rotate camera"):
var rot_x = clamp(old_rotation.x - (get_viewport().get_mouse_position().y - click_position.y), -90, 90)
var rot_y = old_rotation.y - (get_viewport().get_mouse_position().x - click_position.x)
camera.rotation_degrees = Vector3(rot_x, rot_y, 0)
old_rotation and click_position are variables to store the said values of mouse and camera-spatial to prevent rotation-flips in the moment of clicking
"canera" is the variable for the camera-spatial, just because it controls the camera rotation
Here's a version I just made (before seeing you've solved most of it already).
The node setup is the same (child of scene with camera as a child of that).
extends Spatial
var dragging = false
var sensitivity = 0.01
func _input(event):
if event is InputEventMouseButton and event.button_index == BUTTON_LEFT:
dragging = event.pressed
if event is InputEventMouseMotion and dragging:
rotation.y -= event.relative.x*sensitivity
rotation.x -= event.relative.y*sensitivity
rotation.x = clamp(rotation.x,-PI/2.0,PI/2.0)
The limit part is the last line. PI/2.0 radians is 90 degrees. So it clamps the x axis rotation (pitch) to between -90 and 90.
It should work with rotation_degrees too, I'm just used to radians.
- Edited
mine works as expected with a clamp() for limiting, too
The result is an almost perfect reproduction of the rotation-style in the editor.
Now i want to have a small color preview cube in a screen corner, that rotates together with the big one.
I added the cube as child of the camera-spatial too to keep it´s position fixed with the camera.
Than i tried to add this code-line:
small_cube.rotation_degrees = - camera.rotation_degrees
the second half is the rotation of the camera-spatial.
I taught, if i apply the negative of the spatial rotation to the small cube, it will reverse the spatial-rotation to stay aligned to the world axis
But it rotates weird
on the y axis it stays aligned with the scene, but the x axis acts weird
how must i calculate the rotation of the small cube to stay aligned to world axis while taken on the orbit as a child of the camera-spatial
- Edited
If I understand what you want to achieve...
This is where angles get a little tricky.
rotation_degrees is an euler angle, made of pitch, yaw and roll. It's true that doing -camera.rotation_degrees would give the opposite rotation.
But that only works if small_cube and camera aren't in a hierarchy together (like one the child of the other). The reason is euler angles of nodes in Godot aren't added to their parent's euler angles. So a parent with (20,10,0) and a child of (-20,-10,0) don't cancel out. The euler angles are converted to basis vectors (effectively matrix maths) and multiplied together.
What this means is not only do you need to do the opposite rotation (like (-20,-10,0)) but the order of combining pitch, yaw and roll must be reversed as well.
The best way to not have to worry about euler orders and stuff is to use Quaternions (a whole other bag of worms, but useful in this situation). You can read the orientation of the parent into a Quaternion, do the true inverse rotation and apply it to the child node. That will cancel out the parents rotation.
I made a child spatial node of the orbit camera spatial node and put a mesh child on it. On the child I added this function:
func _process(delta):
var q = Quat(get_parent().transform.basis)
transform.basis = Basis(q.inverse())
That reads the parent's rotation from transform.basis into a quaternion, inverts it and puts it into the child's transform.basis.
So I've got a little cube in the upper right that works like the Godot XYZ gizmo thing.
In your code, it should work if you replaced this line:
small_cube.rotation_degrees = - camera.rotation_degrees
with this:
var q = Quat(camera.transform.basis)
small_cube.transform.basis = Basis(q.inverse())
Edit: oh, forgot to mention that transform.basis isn't just the rotation, it's the scale too. Turning it into a quaternion and back will reset the scale to 1,1,1. So if you want the cube scaled, scale a child of the small_cube node instead, otherwise you'll need to manually scale it back each frame in the code.
The position is fine, that's separate in transform.origin.
- Edited
the small cube is resized by the size of it´s cube-mesh, not by scale.
Sp everything is fine now.
Thanks