Can I make 2d Physics bounce the same as the 'Multiply' bounce combine mode in 3d physics?

In 3D physics materials, we have the setting “Bounce Combine” which decides how the two phys materials in the collision combine to determine the overall bounce of the collision. The choices are Average (of the two bounciness values), Minimum, Maximum, and Multiply which just multiplies the bounciness values together

Multiply is the mode I really want, but this setting of ‘Bounce Combine’ is not available for 2D Physics materials, and the way it works by default is the equivalent of ‘Maximum’.

In a previous engine I used, I could edit a single line in box2d directly, but as far as i know, this is off limits in unity, so I feel like i’d have to recreate my own bounce code using OnCollisionEnter2d collision contacts, and reduce all physics materials bounciness to 0

Does anyone have any other ideas? Or how to go about making this code? Getting circles to bounce correctly off flat kinematic objects seems okay, but when it’s boxes and other shapes, and they’re bouncing against other moving things, I have no idea how to code for that. Another approach could be to set bounciness of all phys materials to 1 and instead reduce the velocity according to my own bounciness value, but i don’t know if this is any easier.

I’d appreciate any input, thanks!

Unity - Scripting API: Physics.ComputePenetration for 3D
Unity - Scripting API: Physics2D.GetContacts for 2D

Either can be used to get a bunch of information around the object for further processing / manual resolution I guess, depending on 2D or 3D.

1 Like

I know about how to get contact information, (can also get the info from OnCollisionEnter/Stay2D) I just don’t know what to do with the information to get a good bouncing behavior. Ultimately I think I need to add impulses at contact points in the normal direction, but how to calculate it correctly using the contact info is beyond me.

Unity uses default Box2D implementation:
https://github.com/erincatto/Box2D/blob/master/Box2D/Dynamics/Contacts/b2Contact.h#L35

Friction is combined as “Multiply”, and bounce is combined as “Maximum”. The justification is stated in the code comments:

/// Friction mixing law. The idea is to allow either fixture to drive the friction to zero.
/// For example, anything slides on ice.
/// Restitution mixing law. The idea is allow for anything to bounce off an inelastic surface.
/// For example, a superball bounces on anything.

Yeah, Edy, I saw that line on the box2d github, I don’t agree with their idea

I’m making a physics-based platformer (character has a lot of momentum and mechanics use physics, it’s deliberately not a conventional feeling platformer), and the character should be totally inelastic. Currently, because of the maximum combine mode, the character and the ground both need to be 0 bounciness, but the character can also jump and move on top of any physics object that is big enough, so i’d need to make all of those things 0 bounciness too… this sucks cos then nothing is bouncy, it looks strange seeing boxes and other stuff not have any bounce when hitting the ground.

Also it seems to me that the maximum bounce mode is wrong from a realistic standpoint, nothing in real life acts like their ‘superball’, the bounciest things are stuff like rubber balls, but a sponge could totally absorb their bounce

It’s also really frustrating that the line in box2d is so simple… all i’d need to change is
return restitution1 > restitution2 ? restitution1 : restitution2
to
return restitution1 * restitution2

I’ve kinda solved my problem, I’ve imported Photon’s ‘TrueSync’ asset, it includes Farseer which is a port of Box2d and I can edit the line mentioned in the previous comment. Haven’t implemented t it yet though, seems like a lot of work, but I’m planning on doing networking anyway so this could be a good thing.

/// Restitution mixing law. The idea is allow for anything to bounce off an inelastic surface.
/// For example, a superball bounces on anything.
this is so wrong it bothers me quite a lot. it has hindered several projects and forced me to use the 3D engine instead simply so i can change it to multiply.

Here is my simple justification for why their statement is totally wrong
This really needs to be fixed, this is how it should be.

//different materials with different bounciness
steel ball bounciness = .95f
marble slab bounciness = .95f
wood slab bounciness = .5f
mud bounciness = 0.0f

//example cases
steel + marble slab = 0.90f
steel + wood slab = 0.475f
steel ball + mud = SHOULD equal 0.0f.

In unity with the above you simply get .95f in all cases and it makes NO sense. What the ball is hitting matters! a steel ball does not bounce on mud. nor does a "superball"

sure, you could set the steel ball to zero bounce and that would half work, until you had 2 steel balls colliding with each other as well as hitting different materials around the scene.

you could solve this by changing bounciness values before the collision happens with a trigger volume…but what a pain that is. and it also adds other incorrect corner cases.

Now, for some actual physics justification
“The COR (Coefficient of restitution) is a property of a pair of objects in a collision, not a single object. If a given object collides with two different objects, each collision would have its own COR. When an object is described as having a coefficient of restitution, as if it were an intrinsic property without reference to a second object, it is assumed to be between identical spheres or against a perfectly rigid wall.”

in the case of unity, the bold statement is rendered invalid. cause it doesn’t matter what the second objects COR is. it will always just use the maximum

it should atleast give the option to change it.

2 Likes

Mud is not an inelastic surface. Box2D assumes inelastic surfaces, so no surface is allowed to reduce the bounciness of other objects.

Just change the speed of the rigidbody after the collision in accordance with the bounciness value of the other material.

Here is a simple solution for single collisions (not multiple or angles).
To be assigned to the bouncing object (with rigidbody).
Code not optimized.

using UnityEngine;

public class AverageBounce : MonoBehaviour
{
    private void OnCollisionEnter2D(Collision2D other) {
        // Obtain bounciness from the two Colliders ( or Rigidbodies)
        float myB = GetComponent<Collider2D>().bounciness;
        float otherB = other.collider.sharedMaterial.bounciness;
        // Average Bounciness
        float averageBounciness = (otherB+myB)/2;
        // Select the Max bounciness
        float max = myB > otherB ? myB : otherB;
        // Modify object velocity according to the new bounciness
        GetComponent<Rigidbody2D>().velocity *= averageBounciness/max;
    }
}