- Home /
Weird bounce on collision with perfectly aligned (generated) meshes for fast object
Context:
I am working on a procedurally generated marble/ball track. For that, I generate the track-mesh based on direction and orientation of a bezier curve. To enhance performance, I cut this mesh into smaller pieces which align perfectly as you can see in the wireframe pictures
Problem
When the marble rolls over a point where two meshes touch, it happens that the marble jumps randomly up like there was a little step. You can see this in the following gif:
Details
The ball uses
CollisionDetectionMode.ContinuousDynamic
collision detectionThe track is a kinematic rigidbody with
CollisionDetectionMode.ContinuousSpeculative
collision detection. Usually, Just continuous collision should be used but since kinematic rigidbodies do not support that, I use speculative instead (see this document: https://docs.unity3d.com/ScriptReference/Rigidbody-collisionDetectionMode.html)The ball has a physics material attached:
dynamic friction = 1 static friction = 1 bounciness = 0 friction combine = maximum bounce combine = minimum
Note, that the ball rolls completely fine when using a single mesh.
the movement of the ball is achieved entirely by controlling the angular velocity. The friction handles the rest
Does anyone have an idea why the ball jumps even if there is no reason to?
Best regards Felix
Answer by Ermiq · May 30, 2021 at 03:09 PM
Just a guess.
Collision detection works like this: when 2 colliders intersect each other by some value (default is 0.01) the collision is triggered and the physics engine starts to adjust the velocities of the objects.
While your marble rolls along the first mesh, it is always drown into the mesh for 0.01 units and constantly tries to fall down further but the engine pulls it back up. In this process, the velocity of the marble is kept aligned with the mesh surface plane (marble velocity + gravity + mesh surface counter force = approximately parallel to the mesh surface).
At some moment the marble touches the next mesh, intersects it for the same 0.01 units, and the engine detects that there is a new collision happened. And the place where it happens is the next mesh's edge (probably 2 perpendicular planes: 1st is aligned with the previous mesh, 2nd goes down from the edge).
And if the marble velocity magnitude is high enough than it is treated as a hard crash into the edge of the new mesh, and the engine applies a big counter force impulse to the marble that consists off the up force from the horizontal plane and backwards force from the plane that is perpendicular to the upper surface, and when it is applied to the current velocity the velocity leans closer to Vector3.up.
Thanks for your guess! I experimented a little bit and that may actually be the problem. I moved the colliders a little bit so they intersect. The deeper the intersection was, the less did the ball jump. At about 0.03 units, there was no jump at all. I will now continue testing with different speeds to verify that this is not just a lucky coincidence. Thanks a lot already!
Ok so unfortunately, that did not work. I simulated a full acceleration run ten times for each acceleration value before I increased that value. The jumping occurred at least four out of ten times for each value... Any Idea how to work around this?
Well, first thing I would try to do is adjust the colliders the way that next mesh on the track would be a bit lower than the previous one, kind of like stairways, with a step 0.01 or maybe 0.02.
As another option (not sure if it would work though), monitor the OnCollisionEnter(...)
and check the velocity change after the collision has been detected and processed by the physics engine, and if the velocity has changed too much towards world up vector, revert it back to previous value manually. Probably you'll need to check the velocity on next FixedUpdate()
after the OnCollisionEnter(...)
using a coroutine with yield return new WaitForFixedUpdate()
.
I actually already tried both your suggestions yesterday (sort of...)
The stairs did work "a little bit". It felt like the bouncing happened less likely the larger the step becomes. But even after a step of size 0.05, it still happened sometimes. Additionally, that step is visible and you can see the ball "fall down". So I just replaced a weird bounce by a weird step.
For the second idea I did some quick mafs and found a pretty accurate method of detecting that jump. In OnCollisionEnter I calculated the dot product of the balls velocity with the collision normal(s). Usually, those vectors are close to perpendicular so the product would be close to zero (about 0.0005). But everytime the bounce happened, it was at around 0.2. So I stored velocity, position and angularVelocity in FixedUpdate and used them to overwrite the actual values whenever the bounce happened. Unfortunately this actually did nothing..... So I will try to play around with a coroutine as you suggested. Any idea why applying the previous values does not prevent the bounce?
So, it looks like with this always-running coroutine, I can at least prevent the ball from jumping out of the track private IEnumerator PreventBouncing() { while(true) { previousVelocity = _rigidbody.velocity; previousAngularVelocity = _rigidbody.angularVelocity; yield return new WaitForFixedUpdate(); if (bounceDetected) { _rigidbody.velocity = previousVelocity; _rigidbody.angularVelocity = previousAngularVelocity; bounceDetected = false; } } }
bounceDetected is set to true when the dot product in OnCollisionEnter gets too large. There is still a jump visible but its height is about 10% of the balls height. Does not look good but the ball stays in the track
Answer by ahsen35813 · May 30, 2021 at 03:18 PM
This is a pretty well known glitch in most physics engines. Even when two things are perfectly aligned, there is occasionally a bump, but only at high speeds. For example, in a game called Trackmania, this is a well known glitch that the car bounces on the edges of track blocks where different blocks meet. You may just have to work around it. I think it might have something to do with precision errors in calculating high speed collisions.
Answer by lelaksi · Apr 13 at 11:01 AM
I guess I'm kind of late here, but what did end up working for me was decreasing the default contact offset value (Edit -> Project Settings -> Physics -> default contact offset) from 0.01 to 0.001, but the jumps still happen sometimes. I think you can set the value even lower, but the result at 0.001 was good enough for me (from 1 in 10 to 1 in 300)
Your answer
Follow this Question
Related Questions
How to remove internal triangle/faces when combining mesh 0 Answers
Raycasting not working on a procedural mesh with a mesh collider. 1 Answer
Detect collision between kinamatic rigidbodie and gameobject without rigidbody but with colliders 0 Answers
combining meshes 0 Answers
Collision with Plane fails 0 Answers