Collision misses - possibly not bullet through paper! (now with video)

Edit:
Inspired by @ExplodingRabbit I’ve now uploaded a video showing the experiments detailed below. The annotations can go by quite quickly, so pause it if you need to! 1

I’m experiencing difficulties with colliders. At first I thought this was the old “bullet through paper” issue, but after investigating further I no longer think so.
The behaviour I’m observing makes little sense to me. I’ve created a greatly simplified test scene to demonstrate the behaviour.

Background:

1. a sphere with:
• sphere collider
• is trigger = FALSE
• a ‘bouncy’ physics material
• rigidbody
• use gravity = TRUE
• is kinematic = FALSE
• discrete (collision detection) *
1. a cube collider:
• is trigger = FALSE
• no rigidbody *
• a MonoBehaviour implementing the OnCollisionEnter method
1. fixed timestep @ 0.02
2. gravity @ -9.81
3. The only other GameObjects in the scene are for diagnostics (e.g. GuiText for an updating velocity label)
4. Unity Version: 3.5.2f2 (Windows 7 64 bit Ultimate)

* I have experimented with collision detection with no success. I get very strange behaviour from the sphere - I explain more later.

Notes:

• the sphere moves in Y and Z (think ball)
• the cube collider is static (think tennis net)
• the sphere approaches the cube predominantly in the Z axis and slightly in Y (due to gravity)

Intent:

When the sphere collides with the cube two things should happen:

1. the cube collider should register the hit and fire an event
2. the sphere should bounce off of the collider

Problem

The actual behaviour appears unpredictable. Sometimes the intended behaviour occurs, other times the sphere passes straight through the cube collider.

Originally I thought that:

• Unity was not registering the collision (bullet through paper),
• that the cube collider needed to be enlarged to detect the sphere collider and/or
• that the physics’ fixed timestep needed to be decreased (e.g. 0.02 → 0.01) or
• that I needed to use the new dynamic collision detection on the rigidbodies;

however, when the sphere passes through the cube, the cube collider’s OnCollisionEnter method is called. This suggests that Unity is registering the collision, but that the sphere is not being affected by it.

From reading the Q&A sites, the perceived wisdom is often to increase the depth of the collider(s); however, from my experiments this is not always valid. For example, in Test One below I begin with a configuration that causes the sphere to pass through the cube, then in Test Two I increase the speed of the sphere and decrease the depth of the collider and the result is the collision I would expect - the sphere bounces off of the cube.

The experiments that fail (i.e. those where the sphere passes through the cube) can be corrected by decreasing the physics’ fixed time step; however, this is a somewhat brute force approach that doesn’t explain to me:

• why the OnCollisionEnter method can be called but the sphere not react to the collision, i.e. it appears that the collision HAS been detected?
• why decreasing the size of the collider and increasing the speed of the sphere can result in a bounce?
• why moving the cube closer to the sphere emitter can affect the bounce/pass outcome (is it related to the angle of the collision)?

Further, I would prefer not to reduce the fixed time step if possible since I will be targetting mobile devices with reduced processing power.

An alternative would be to use the “DontGoThroughThings” script - however, this is remedial action for an unknown cause - at least unknown to me since the behaviour doesn’t comply with the normal remarks re colliders.

Any advice would be greatly appreciated. Does anyone from Unity have any thoughts?

Notes on the Experiments & Test Scene:

I have included a test scene.
The scene consists of a sphere emitted at a given velocity and at a given frequency, aimed at a cube.
The sphere should bounce off of the cube.
If the cube’s OnCollisionEnter method is called, a visual indicator shows this on the screen.

In the scene there is a GameObject named _Main in the Hierarchy.
_Main allows the following to be tweaked:

• Sphere Period: the time in seconds between spheres
• Velocity: the velocity applied to the sphere when emitted
• Position: the position of the sphere when emitted
• There then follows a series of check boxes that, when checked, will reproduce the tests below.
• Only check one box at a time
• Checking a box will override the Velocity and Position settings above - uncheck all boxes to use the V&P controls

Experiments:

Test One:

• cube collider Z scale @ 0.2
• sphere Z velocity @ 10
• sphere is 4 units from the cube in Z (1 in Y)
• sphere passes through the cube
• OnCollisionEnter IS called

Test Two: Shrinking the cube collider whilst speeding up the sphere results in the sphere bouncing off of the cube.

• reduce the Z scale of the cube collider from 0.2 to 0.01
• increase the Z velocity of the sphere from 10 to 11.7
• the sphere now bounces off of the cube!
• OnCollisionEnter is called

Test Three: Increasing the speed of the sphere further results in the sphere passing through the cube.

• increase the Z velocity of the sphere from 11.7 to 11.8
• the sphere now passes through the cube
• OnCollisionEnter is called

Test Four: The slight speed increase to 11.8 allows the cube to be enlarged from 0.01 to 0.34 and still the sphere passes through the cube

• increase the Z scale of the cube collider from 0.1 to 0.34
• the Z velocity of the sphere should be 11.8
• the sphere now passes through the cube
• OnCollisionEnter is called

Test Five: At a depth of 0.35, the cube collider will now deflect the incoming sphere

• increase the Z scale of the cube collider from 0.34 to 0.35
• the Z velocity of the sphere should be 11.8
• the sphere now bounces off of the cube
• OnCollisionEnter is called

Translating the cube in Z so that it is closer to the sphere emitter affects the result

Test Six: A slim cube results in a fast sphere passing through it

• cube collider Z scale @ 0.01
• sphere velocity @ 20
• cube Z position @ 0
• sphere is emitted @ Z position -4.5
• the sphere now passes through the cube
• OnCollisionEnter is called

Test Seven: A slim cube moved closer to the sphere emitter results in a fast sphere bouncing off of it

• cube collider Z scale @ 0.01
• sphere velocity @ 20
• cube Z position @ -1.55 (cube is now closer to the sphere emitter)
• sphere is emitted @ Z position -4.5
• the sphere now bounces off of the cube
• OnCollisionEnter is called

And just to confuse things further:

Test Eight: A slim cube and a very fast sphere results in bounce

• cube collider Z scale @ 0.01
• sphere velocity @ 40
• cube Z position @ 0
• sphere is emitted @ Z position -4.5
• the sphere now bounces off of the cube
• OnCollisionEnter is called

So far, the cube’s OnCollisionEnter method has been called, regardless of bounce or pass through, but:

Test Nine: A slim cube and a slower sphere can result in pass through AND NO OnCollisionEnter method call

• cube collider Z scale @ 0.01
• sphere velocity @ 10
• cube Z position @ -1.31 (cube is now closer to the sphere emitter)
• sphere is emitted @ Z position -4.5
• the sphere now passes through the cube
• OnCollisionEnter is NOT called

Rigidbody & Collision Detection

I have read that to overcome “bullet through paper” problems:

• the sphere should have a rigidbody with Continuous Dynamic collision detection
• the cube should have a rigidbody with Continuous collision detection, and Is Kinematic = true (since it is stationary)

Setting these values in the test scene results in (seemingly) crazy behaviour. For example with Test Two: (2)

• the sphere (generally) passes through the cube
• the sphere springs back towards the cube
• the sphere then seems to roll around on the vertical face of the cube, defying gravity
• the sphere never bounces off of the cube
• the velocity of the sphere goes crazy:
• X is affected (we never apply force to X)
• Y increases and decreases
• Z increases and decreases

I really hope that such obscure behaviour is a result of me having an incorrectly configured Unity environment/scene, otherwise this is quite worrying!

Thanks for any help,

James

First, let’s simplify your testcase a bit:

• disable the sphere’s gravity, it’s irrelevant for the result
• to actually see what’s going on, set the physics time scale to 0.1, it doesn’t influence the computations
• now, to not wait for ages between events, set SpherePeriod to 0.2, and Position to -0.4
• disable the “static” setting on the cube - it’s irrelevant for physics, but it makes things harder to see on Windows, since if it is on, the collider will be scaled, but the mesh will NOT be scaled
• set the Cube’s scale.z to 0.01, to better see what’s going on (but don’t use your testcases then, or the value will be reset)

Now you can simply play with the single parameter Position.z to reproduce all the different behaviours you described - all other settings (Velocity, cube position, angles, collider scale, …) are merely circumstantial. The only relevant fact is: “Where is the sphere located at a physics time step?”

Now, for the default timestep of 0.02, we get 50 physics steps per second, so for a velocity of z=10 the +z shift of the sphere will be 0.2 each frame.

Sphere and 0.01-scaled Cube will touch (the enter event) at radius/2+cubesize.z/2, which is z=-0.055, and similarly will completely have left the Cube (the exit event) at z=+0.055

Using only Position.z, the individual cases and situations occuring at a physics time step can now be broken down to:

• Sphere intersects after two time steps, the intersection occurs in the “front” half (see below): z=-0.455…-0.4 (which is -0.4-0.055)
• Sphere intersects after two time steps, the intersection occurs in the “back” half: z=-0.4…-0.345 (which is -0.4+0.055)
• Sphere does NOT intersect after two time steps: z=-0.345…-0.255 or -0.545…-0.455 (which are just the remaining intervals)

Note that:

• for all settings in the third case, the sphere always passes through; this is just a case of “object is too fast for physics simulation, and therefore passes through” (i.e., “bullet through paper”)
• the Sphere also passes through in the second case
• the Sphere always bounces in the first case
• the Sphere bounces if and only if the rightmost hemisphere (the half “in front”) lies at least partially within the left half of the cube (i.e., the interval -0.455…-0.4)
• the “Collision enter” is no longer reliable - needs further investigaion. On my machine (Windows 7 64bit), it will trigger only once in a regular(!) time interval of about 2 seconds (play with time scale here, the time interval when it triggers doesn’t change much)
• the rigidbody.collisionDetection setting is irrelevant

You can verify the fourth (and most important) fact by playing with the collider scale of the cube: Over a value of 0.3, the sphere will always bounce. For smaller scales, the sphere will only bounce for the interval -i-(sphereScale.z+cubeScale.z)/2…-i, with i being a multiple of 0.2 (i.e., the z translation of the sphere per physics step). E.g., for the near-limit case cubeScale.z=0.29, the sphere will pass through for values between -0.4…-0.395 (watch out for floating point imprecisions, so use a slightly smaller interval, such as -0.3999…-0.3951)

So my conclusion at this point would be:

• rigidbody.collisionDetection does not work as expected, it always behaves as “discrete”
• for some reason, the PhysX engine does not test the full bounding box/collider volume, but only half of it (for both source and target)
• OnCollisionEnter and the PhysX collision detection use different bounds-/detection algorithms and are unrelated (which might makes sense if the one is provided by the PhysX engine, and the other is computed by the Unity engine)
• OnCollisionEnter is in itself buggy/unreliable
• we currently still need the workaround of DontGoThroughThings.js for fast objects to work correctly/better

I have not tried @whydoidoit’s suggestion to do the actual parameter initializations in FixedUpdate() instead of in a Coroutine. This should be investigated, but I cannot spend more time on this, ATM.

EDIT: Now that I also read the last section of your question (cough), it seems rigidbody.collisionDetection is only evaluated if both objects have a rigidbody. I can see an improvement when setting the Sphere to “Continuous”, but so far I haven’t tried to quantify this. Also, the erratic behaviour which can be seen in your last video happens (only) if none of the objects is set to “Discrete”, and at least one of the objects is set to “Continous dynamic”.