I am making a demo where you walk on a planet instead of a plane, it’s first person and you can just wander around this planet, but… Everything works fine until you go to the south pole, like the exact opposite side of the planet, on this spot the camera spins around because the way i rotate the player according to where they are located is i find the angle between the players position vector and the vector3.UP vector and then i find the orthogonal vector to the players position vector and rotating the player along this orthogonal vector by the angle from before, but this has a problem, everything rotates from the north pole and when you rotate a sphere it matters which direction you rotate it in because at values close to 180 degrees things still point outwards to the planet, but they are rotated perpendicular the the planets plane.
var positionVector = ($".".position-$"../Planet".position).normalized()
var v
var orthogonalVector = Vector3(-positionVector.z, 0, positionVector.x).normalized()
if orthogonalVector == Vector3.ZERO:
orthogonalVector = Vector3(1, 0, 0)
v = acos(positionVector.x * Vector3.UP.x + positionVector.y * Vector3.UP.y + positionVector.z * Vector3.UP.z)
$".".quaternion = Quaternion(positionVector, lookDegrees)*Quaternion(-orthogonalVector, v)
All i want is a way to find out how much it ends up rotating perpendicular to the planets plane as the player moves around it so i can offset it by that much.
i have found a semi fix where it finds the angle from the Vector3.DOWN vector and the players position vector when the player is in the southern hemisphere, this is a semi fix because it no longer freaks out at the south pole but it turns you 90 degrees when you cross the equator, all though kind of funny, this is not what i wanted.
Here is an example for a character walking around a planet, maybe it helps. The important bit is that you shouldn’t rotate the character according to Vector3.UP, but by their last individual up vector.
I am very new to godot so i don’t really understand this, it works btw, but can you please explain to me why, what is the difference between up_direction and Vector3.UP, what does all the global stuff mean, and can you use slerp with this lol.
up_direction actually is a member variable of CharacterBody3D, and it defines the “personal” up direction of the character. (Docs) By default it’s the same as Vector3.UP, and so the character will know the floor (for collision checks) is everything below it. So if you change the up_direction, collision checks still work even if you rotated the character. In my code I also use it to find out the angle between the last up_direction and the new normal (because the player moved on the sphere).
Everything with a global_ prefix just handles stuff in global space instead of local space. So global_position is the world position of a 3D node, while just position gives me the position relative to the 3D node’s parent.
And yes, you can add slerp to make it smoother I guess.
okay so basically what the code does is it changes the up_direction constantly for the Character controller and you rotate it around the cross product of this up and and the new up which is the new player position normalized, damn it is really close to what i was doing but here you just rotate from last frame where i was trying to rotate from the north pole every frame.
you just rotate from last frame where i was trying to rotate from the north pole every frame.
Yes, and that’s the important difference. Because if you rotate from Vector3.UP only, and you rotate towards Vector3.DOWN, you get gimbal lock, because it can’t know from which direction it came.
global_rotate() rotates the character around an axis in world space. It might be that the line
global_rotate(up_direction, PI * -0.5 * delta * input_rot)
is the same as
rotate(Vector3.UP, PI * -0.5 * delta * input_rot)
You can try to change it. In any case it makes sure the player correctly rotates when using the Left or Right keys.
global_basis = global_basis.rotated() basically does the same as global_rotate(). Another line of code you can experiment with!
they are all the same, well that’s because right now the planet is at (0, 0), and has no parents. But up_direction != Vector3.UP
and many many thanks, i should probably look at some godot tutorials before just jumping in and making crazy shit by only looking at the docs and godot forum answers
i have tried to implement slerp, and it works most of the time but sometimes it just decides to do a few barrel rolls and stuff
var new_up = ((position + velocity * delta) - $"../Planet".position).normalized()
var angle = basis.y.angle_to(new_up)
if angle > 0.0 && (position-$"../Planet".position).length() < $"../Planet".scale.x/2+scale.y*2:
var axis = basis.y.cross(new_up).normalized()
basis = basis.slerp(basis.rotated(axis, angle), 0.6)
up_direction = basis.y
i have no idea why this happens, also i have decided to use basis.y instead of up_direction since now it’s rotating in increments and basis.y updates with the increments.