Could use some guidance on gravity implementation edge cases

Hi JD. This has been an issue many times before, and there’s many posts both here and on the old forum… on this topic. Here’s one from the new forum.

First, a little history. The BJS built-in collisions system was originally designed for “first person shooter” games… using the FreeCamera. The FreeCamera has .applyGravity and ._needMoveForGravity = true; (start falling on scene READY)… and it has .ellipsoid and .ellipsoidOffset, and it’s “scrub-off angle” (ramp-climbing/wall-scrub-off-angle) is affected by user-settable Engine.CollisionsEpsilon.

MoveWithCollisions was a later add-on feature… attempting to deal with collisions that AREN’T a freeCamera colliding with an obstacle. (ie. mesh-to-mesh instead of cam-to-mesh). SO, for now, I will assume that your player is NOT a FreeCamera. Let’s pretend it’s a box. :slight_smile:

When using moveWithCollisions, setting .checkCollisions = true on grounds, heightMaps, or nearly ANYTHING that can collide with BOTTOM of box.ellipsoid… is probably a bad idea. (possible continuous collisions from “scrubbing against ground” as sideways/lateral moveWithCollisions (MWC) happen - especially problematic for non-level terrains.)

Instead, you would use the “air hockey puck” -approach… where you try to keep boxPlayer above the ground and above jumped-up-onto mesh… a tiny amount. (the air-cushion). But this is a problem for ramps, because… your down-shooting ray… shoots straight down the -y axis of playerBox. The playerBox.ellipsoid lower-area SIDES will strike the ramp… as if it were an obstacle instead of a floor.

Therefore, even up-ramps must be treated as if they are a floor or jump-up-onto mesh… and have .checkCollisions = false. Since the down-shooting ray happens directly below playerBox.origin (center)… fat playerBoxes will be seen protruding THRU the up-ramp… because the down-ray won’t see the changing hit.distance values until playerBox CENTER… reaches ramp inclination. It gets to a situation where you really can’t use moveWithCollisions AT ALL, anymore, and need to start doing custom onCollide testing of the player moves… yourself. The same kind of issues arise when dealing with very hilly heightMap terrains. Down-shooting rays… continuously checking for hits and distance to those hits… just can’t do a good job on ramps and steep hills.

What’s the solution? You got me. I once pondered 8 down-shooting picking-rays… positioned “around” the circumference of playerBox.ellipsoid. When playerBox approaches a ramp or steep hill, any forward-moving, backward-moving, or sideways-moving (strafe)… will cause one or more of the 8 down-rays… to see a hit on the ramp/hill… and its hit.distance will suddenly change. By comparing the changed-ray-distances (start of hill/ramp) with the un-changed ray distances (flat ground)… you can calculate a ramp-hill angle. From those calculations, you can determine what playerBox altitude (y-position) to set your playerBox above the ground/ramp. In essence, ground-following WITHOUT collision, so no gravity consids needed, and no Engine.CollisionsEpsilon tweaking.

Erf, huh? Could it BE any more complicated? Eight down-shooting rays… all doing hit-checks and distance-to-hit measurements… every move-step. OUCH! It almost makes you want to say goodbye to .moveWithCollisions, and just “fake” a third-person follow-cam system… by parenting playerBox to the front side of freeCamera… and getting back to using freeCamera’s collisions to get the job done.

But we land right back into the “can’t climb a ramp” problem because of freeCamera’s .applyGravity. Even THAT system seems to need the 8 down-rays (actually 9 down-rays… one straight down from player-center, and 8 surrounders) ground-contour-monitoring system… so you can determine WHEN to reduce/increase scene.gravity.y values.

Also, the freeCamera’s round ellipsoid shape… can cause “climb over the obstacle” problems on low-altitude obstacles, and dive-under on tall obstacles. Also, depending upon scene.gravity and Engine.CollisionsEpsilon settings, the camera can START to climb-over an obstacle or climb up a ramp, but its gravity keeps pulling it backwards/down… making the camera jitter during climb attempts. (see playground below)

The BJS built-in collision system is perfect for SOME applications, but for ramps and heightMap terrains… it can be a serious hassle, as you have discovered. You almost HAVE TO… SOMEHOW… determine the angle of the slope beneath the player… and quickly adjust scene.gravity.y and maybe also Engine.CollisionsEpsilon… on the fly… after each move is completed (to avoid sliding and allow further climbing).

I have never tried a 9-down-ray “terrain contour monitoring system”. If a single down-ray and hit.distance checker is performance-heavy, I would imagine NINE rays would be 9 times worse. And there will be some gruesome calculations after you have “queried” the 9 down-ray hit-distances… to set proper player altitude. (perhaps no .checkCollisions on ANY mesh that player could stand-upon, so YOU set player altitude every move-step). And we haven’t even thought about player jumping, yet. erf.

You’ll still want .checkCollisions = true on real obstacles… un-climb-ables. No passing thru trees or walls. :slight_smile: I wonder what might happen with three (invisible?) stacked boxes for player, and thus… three stacked collider ellipsoids (all parented together). Center ellipsoid is active and moved-with-collisions… for sideways collisions. Then another for feet, and another for head… which you DON’T moveWithCollisions, yet they come along for the ride, via parented to center (invisible?) box. What added powers would THAT system… provide? Hmm. Still, we need MESH.CollisionsEpsilon… a separate setting for each ellipsoid. THAT would be cool.

I dunno, JD. Stay tuned for other comments… if some are available. I believe @splash27 stayed-with built-in collision system, and @Givo went with physics engine, but even with the physics engine… Givo needed special handling to keep player from sliding down ramps and steep terrain hills. I don’t know if either of these users were ever 100% happy with the systems they tried. Maybe they will visit and comment.

https://www.babylonjs-playground.com/#1GL6RR#8 There’s a NON-moveWithCollisions ramp-climb test… using the FreeCamera’s arrow-keys to move. Try holding-down the up-arrow. Line 51 - even with Y-gravity at 1/3 normal, we can’t climb the ramp. Camera tries to climb, gravity pulls it back to ground… causing jitter. We start to ponder WHAT IS AN OBSTACLE and WHAT IS GROUND, eh? nod. HeightMaps are even worse, because putting an ellipse-shaped collider on a heightMap with mountains… is a giant waste of effort. (bad fit)

Is our player wearing spiked mountain-climbing boots? Is there a way to kill gravity.y upon player move complete? Will player moving EVER finish… if player is moving DOWN a hill/ramp?

We sure could use a getAngleOfMeshFaceBeneathPlayer(), eh? hmm. Such a method MIGHT need 9 down-shooting rays to accomplish, and COULD get confused if player is sitting in a “valley” where 3-6 mountains begin in various directions. It might be quite difficult to calculate angleOfMeshFaceUnderPlayer(), in that case… but player sitting in a valley where 3-6 mountains intersect… is likely a common occurrence in hilly country. Using physics engines is really no help at all, here… unless you attempt anti-slide things like Givo tried. (I think he “froze” [repeatedly set] player.impostor.linearVelocity() at 0,0,0 when the move’s linearVelocity neared 0,0,0.)

Gruesome challenge… been happening for years… never really solved. Not sure if it CAN be solved… without a very intelligent terrain-angles monitoring system (what is terrain shaped-like, under and around player).

I wish I had better news for you, JD. If you beat this long-hassle issue… you will be a superstar. :slight_smile: Be sure to test various values in Engine.CollisionsEpsilon… which COULD affect back-sliding. Unfortunately, it also affects the angle to determine scrub-off angles on the SIDES of the ellipsoid collider, too… not just the top and bottom. This means… if you push the player against a wall at some angle, that value will determine WHAT ANGLE is needed… to stop the player “dead stop”… versus allow the player to slide-along the wall (scrubbing). I call it “scrub-off angle”. It also affects top and bottom of ellipsoid scrub-off angle… thus it affects climb-over issues with low-altitude obstacles, and dive-under issues with tall obstacles.

Perhaps we need Engine.CollisionsEpsilon to be split in two… VerticalCollisionsEpsilon (for top/bottom of ellipsoid) and HorizontalCollisionsEpsilon (for sides of ellipsoid).

Sorry for so much talking, gang. I’ve talked about this issue SO MANY TIMES… that I got it all memorized. heh. It would be real nice to solve this repeating problem forever, eh? We need a high-performance .getAngleOfMeshfaceBeneath(player), eh? That would at least be a START… for designing smarter anti-slide/easy-climb player-moving systems, eh? nod.

I believe ray pickInfo object… returns the FaceID number for where upon the “hit” object… the ray intersected. But that is not the ANGLE of that face. AND… we really need the angles of the faces in 8 more directions. Even then… a telephone pole or fence post obstacle… rising from a ramp… could cause all sorts of problems.

And ideally, no matter how steep the ramps or surrounding mountains, even though we are using “air hockey puck” for player altitude and no playerbottom checkCollsions… the mesh should never go partially inside the hill or ramp. If player is a box, and it has spherical .ellipsoid collider, the box corners and edges COULD go inside the steep surrounding mountains or steep surrounding ramps. Only physics engine colliding knows about the corners of the box… due to box Impostors. We have no box colliders for BJS built-in collisions system. Sigh.

I fear that the only real solve… is very advanced use of a physics engine, but moving/turning a mesh with physics applyForce, applyImpulse, or setLinearVelocity/angularVelocity… is challenging, direction-setting-wise and friction/mass-wise (move speed). player.physicsImpostor needs fixedRotation on X and Z axis… to keep from tipping over when colliding with a low obstacle like a squirrel… but it still needs full Y-rotation abilities… for player to turn in any direction. erf. Yet it also probably needs X and Z rotation… to climb/descend ramps/mountains (especially true for vehicles. Humans stay upright when climbing ramps).

God, I’m STILL talking, aren’t I? When will I stop? heh.

I MUST SAY… JD… “edge cases” is pretty funny in your post title… considering you are talking about walking off-of cliffs. I got a good chuckle from THAT one… nice work. :slight_smile:

2 Likes