Trying to fix Plane .projection directional distortion for character movement

Godot Version

4.3

Hi all, first time posting here, not sure if to post this here in help/programming or physics. It’s more of a vector math problem than a collision body issue. Sorry if I’m in the wrong place.

Background

Short and to the point: I’m using the floating-collider-and-raycast method for my player character and moving it using camera relative direction(intended_direction). The raycast checks ground below and takes the normal of the surface we’re moving on. The character movement uses the ground’s normal (ground_normal) vector for smooth consistent movement on ramps and inclines though I do apply a correction to the character’s vertical position using the raycast after applying physical movement.

Problem

I noticed that when moving on certain inclines the movement of the player character becomes skewed: for instance you’d hold forward but the character would move in a somewhat diagonal direction rather than properly forward of the camera’s heading. I normally use vector3 final_calc = Plane(ground_normal).project(intended_direction) to take the current incline into account and this seems to be what’s causing this distortion of direction. I created a dedicated scene that uses raycasts to visualize the vector calculations (red for simulated ground_normal, blue for intended_direction and yellow for the final_calc calculation using stated method) and a plane mesh facing the ground normal for reference. And indeed, viewing it from the top, the Plane normal actually does rotate the final calculation vector away from the direction intended by the player by quite a bit!

For reference the simulated ground_normal is x:0.47275, y: 0.534897, z:0.700281

Attempted Solutions:

I’ve figured all I really want from the ground_normal an incline normal parallel with the intended_direction so I made the purple raycast to represent an attempted fix: Vector3 plane_fix.

  1. I’ve tried making a temp vector3 that’s plane projected using the ground’s normal like usual. Then I take the vectors Y value and apply it to a vector that uses intended_direction’s X/Z values. This didn’t work out. While the yellow final_calc cast sticks the surface of the reference plane perfectly the purple plane_fix will either rise from the surface of the plane or sink into in.

  2. Next thing I tried was making a stand-in ground normal by using Vector3.project: stand_in = intended_direction.project(ground_normal).normalized() then plane_fix = Plane(stand_in).project(intended_direction). Ran that and still no joy, it produced similar results for the purple raycast as the method before.

  3. My more elaborate attempt for a solution: Taking the intended_direction and the world ‘up’ Vector3.UP and using those to create a cross product between the two, assigning the result to a vector plane_norm. I then used this plane_norm to Plane project the ground_normal (new_ground_norm = Plane(plane_norm).project(ground_normal) in an attempt to isolate the vector of ground_normal’s incline parallel to intended_direction. Then applied plane_fix = Plane(new_ground_norm).project(intended_direction) but still, again, no success, I get similar behavior from the vector not sticking to the reference plane mesh while the raycast for final_calc sticks smoothly to it.

Sorry if this post is a little wordy, it’s just I’ve hit a brick wall with this. I can’t seem to find a solution to this. Am I missing something here? Is there a function to Plane or Vector3 I’m not utilizing that could fix this? I was sure the last attempt would of worked out. Surely someone may have run into this too.

thanks.