Detecting Sharp Edges (Raycasting)
- Edited
- Best Answerset by paftdunk
paftdunk I think you first need to decide how exactly will movement be working. Without that it's hard to give useful suggestions.
But to answer directly what you asked; try to raycast from the point that's slightly offset in skate's forward direction and goes into skate's down direction. Limit the length of the ray. If the ray doesn't hit anything or if a signed angle between the current normal and the rayhit normal is larger than some threshold - you have a "sharp" convex edge ahead.
The vertex normals do look kinda strange. Looks like your hard edges are not truly hard 
xyz Right now, the movement is the basic approach to CharacterBody3D movement. Apply velocity on z basis based on forward/back input, rotate player by constructing a new transform based on left/right input. I apply gravity to the velocity each frame.
When, and only when, the player is grounded, do I snap to the surface normals. Also, the surface alignment snap does not affect the y-axis (no offset, etc.). So I perform the jump by adding a force to the velocity - as soon as is_on_ground() returns false, the snapping stops and gravity takes care of the rest. Snapping resumes as soon as is_on_ground() returns true.
That is what I have right now; however, I can see how the combination of the normal snapping and gravity (added on to the CharacterBody's sliding behavior) may add some complexity to the ramp behavior.
xyz Ah - much better 

- Edited
xyz I've noticed as I've experimented with rounder objects this definitely seems to be the case. I think what I'll do is update the up_direction to be the interpolated normal, but through other means decide what angles we should stop snapping to.
xyz I do have a question about this:
If the ray doesn't hit anything or if a signed angle between the current normal and the rayhit normal is larger than some threshold - you have a "sharp" convex edge ahead.
When I hit this condition - the sharp edge being detected - I'm not sure what course of action to take. Here's an example:

Say the RED arrow is the raycast that is used for normal calculations for alignment. Say the PURPLE arrow is the raycast that checks ahead. The GREEN line is a very tiny face on the mesh right before hitting the hard edge.
If the PURPLE arrow detects the hard edge, and then I disable floor alignment at that point, the RED arrow still hasn't hit that last segment (the green one). So, the player will continue to move in their respective forward direction without having aligned to the green segment because I turned it off too early; it'd still be aligned with the normal that it hit right before I detected the edge (technically not the one I want it to be aligned with).
Does that make sense? Would I simply just need to move the forward-checking raycast back, closer to the raycast that is used for floor alignment?
- Edited
paftdunk If the green distance is very small it may be good enough as the difference between the actual surface tangent and the current forward would be negligible.
If you want the exact tangent then take the face normal at the red position (returned by red raycast), and rebuild the basis using it and the current forward direction in the first cross product.
- Edited
xyz Excellent, this looks good already! I'm using that method for now rather than checking the angle. I'm also going to make it a "rule" for when I'm making my meshes to not make any faces that may cause that scenario I described - shouldn't be hard to avoid with the style I'm going for.
Related - I'm running into a slight issue (well, kinda) with the velocity. This is what I want to create:

However, because the last normal isn't exactly 90 degrees, there is a bit of velocity on the the x-axis. This causes the character body to overshoot the ramp and end up going behind it (on the x-axis).
This makes logical sense of course, this ramp isn't launching me exactly perpendicular to the ground so I'd still have velocity on all axes. IDEALLY, they'd just continue to move up and come right back down to slide down the ramp. So I'd only want velocity on the y and z axes even though this isn't realistic (I'm going for stylized movement after all).
Here's an example from THPS. I don't think it purely uses rigidbody simulation - there's definitely a lot of kinematic movement from testing I've done, which I why I use this as a reference:

You can see that the ramp is not perfectly 90 degrees at the point at which the skater leaves.
I was thinking I could lock the character body into some sort of spline/curve that would keep this from happening, but somehow keep the gravity in control for the y-axis and allow movement on the z-axis. Or I could just lock x-velocity while they are in the air and turn it back on once they land, but this feels like a hacky solution that may not be ideal in all situations, so I'm not sure that's a good path. What would you say would be a good approach to this?
- Edited
paftdunk Check if the horizontal component of the velocity at the time of detachment from the ramp is below some threshold. If yes, set it to zero, keeping only the vertical component. You'll have to experiment a bit to determine the exact threshold. It may also depend on game mechanics and movement stylization you're after.
Alternatively (or additionally) you may gradually push the skater away from the ramp (in the last attached normal direction) for some brief time following the detachment.
To get the horizontal velocity component, project the velocity vector onto the horizontal plane and take its length.

