I'm not sure I fully understand what you want to do, but I can give you something to work with.
I'll assume that you already have the input as a Vector3. If not, you want to see Input.get_action_strength, Input.get_axis and Input.get_vector.
I'm also assuming that the braking situations you encountered are a case of gimbal lock. But since you are asking about applying velocity not rotation, I'll not go into that topic.
Since you are using a KinematicBody, I suppose you would be using move_and_slide or similar method, which work in global space. But you want the input to have to be based on the current orientation. Thus, you would consider your Vector3 which represents the input to be in local space. And the issue is how to go from that local space to the global space that move_and_slide et.al. need.
Transform
You might be familiar with to_local and to_global. Which would interpret the Vector3 as a position:
var global_input_vector:Vector3 = to_global(input_vector)
And the opposite operation would be:
input_vector = to_local(global_input_vector)
The problem with these is that since these consider the Vector3 to be positions, they will translate the vector depending where the KinematicBody is. We can undo that translation:
var global_vec:Vector3 = to_global(local_vec) - global_transform.orign
And the opposite operation would be:
local_vec = to_local(global_vec + global_transform.orign)
By the way this is another way to write the same code:
var global_vec:Vector3 = (global_transform * local_vec) - global_transform.orign
And the opposite operation would be:
local_vec = global_transform.affine_inverse() * (global_vec + global_transform.orign)
Which I'm mentioning because I want you to see the similarity with the following approach.
Basis
I would rather not consider the Vector3 to be positions. Just free vectors. So, we would transform it with only the Basis, like this:
var global_vec:Vector3 = global_transform.basis * local_vec
And the opposite operation would be:
local_vec = global_transform.affine_inverse().basis * global_vec
This approach will not have the translation problem.
You can think of the Basis as a 3 by 3 matrix, and the Transform is that same matrix augmented with a translation vector (origin).
Quat
However, if you only want rotation, let us se quaternions instead:
var global_vec:Vector3 = global_transform.basis.get_rotation_quat() * local_vec
And the opposite operation would be:
local_vec = global_transform.affine_inverse().basis.get_rotation_quat() * global_vec
Well, actually, let us invert just the quaternion:
local_vec = global_transform.basis.get_rotation_quat().inverse() * global_vec
These will only rotate the vector (no scaling, or any other transformation, just rotation) according to the current orientation of the KinematicBody.
Rotating a Transform
If you are trying to rotate a Transform, either…
Do this (quaternion):
transform = Transform(transform.basis * Basis(quaternion), transform.origin)
Or this (quaternion):
transform = transform * Transform(Basis(quaternion), Vector3.ZERO)
Or this (axis-angle):
transform = Transform(transform.basis.rotated(axis, angle), transform.origin)
Or this (axis-angle):
transform = transform * Transform.Identity.rotated(axis, angle)
Or this (Euler angles):
transform = Transform(transform.basis * Basis(pitch, yaw, roll), transform.origin)
Or this (Euler angles):
transform = transform * Transform(Basis(pitch, yaw, roll), Vector3.ZERO)
Avoid this:
transform = transform.rotated(axis, angle)
The reason is that this rotation is always before translation (i.e. this rotates around the global origin instead of the current position), and you will end up with an undesirable result.
And yes, you could use rotate_x, rotate_y and rotate_z, or set rotation of a Spatial. But sometimes you need to work with a Transform directly.
See also: