Up until now we’ve treated all surfaces as walkable. This works fine until we want to create a distinction for non-walkable surfaces: surfaces we’d like for characters to slide off of. Whenever a character sits just above a non-walkable surface we will treat them as being non-grounded or airborne. Being grounded will now be used to mean that a character sits just above a surface on which they can walk on or stick to.
We can determine if a character is grounded by querying the triangles about the character. For each triangle we compute the closest point to the character and discard them if they our outside of some small contactDistance. For each remaining point we check that the contact normal at the contact point (formed by the vector from that point to the character position) is oriented upwards. This is done by checking whether the dot product of the contact normal with world up is greater than zero.
From the remaining contact normals, we check whether each normal is sufficiently upright to be considered walkable. The value we choose to compare against (a value between 0 and 1) will determine how steep slopes can be before being considered non-ground. Values closer to 0 allow for steeper slopes.
Optionally we can tag triangles as always ground or not ground (independent of contact normal). For contact points on triangles with tags, we use the tag as the determinator.
Some of the points we find that are within contactDistance may not be actual contact points. Some may be inner points: points that would always be superseded by a contact point closer to the character. We want to filter out inner points so as not to include them in our grounded checks. We perform a spherecast from the character position in the direction of each point and prune any results where the first intersecting triangle is different than the triangle for the point we’re testing.
Characters can sometimes become wedged in the space formed by non-ground triangles. In these instances characters can remain stuck in an airborne state even though they can no longer move downwards. We want these areas to be consider ground as well.
We can determine if a character is in such a spot by considering subsets of contact points about the character. We evaluate whether any subset of two normals forms a crevice or any subset of three normals forms a pit. In both cases there exists no downward vector along which a character could move downwards from their current position.
For every contact point below the character we compute the direction the character would slide along had they intersected a hypothetical plane defined by the contact normal. From here we consider all contact normals, including those that may point downwards. We see if there is any other contact normal that points opposite of the slide direction. If there is, we compute the cross product of the two normals to produce a perpendicular vector corresponding to the remaining direction the character could move along. If that perpendicular direction has a slope that is sufficiently upright, the character is in a crevice and deemed grounded. If not, we check to see if any third contact normal points opposite of the cross product direction. If so, the character is in a pit and also deemed grounded. If none of these hold, the character is airborne.