Quick answer: Set bounce on a PhysicsMaterial assigned to physics_material_override on your RigidBody, not on the CollisionShape. Both colliding bodies contribute — if the floor has bounce 0, your ball’s bounce alone may not produce a visible effect. Set bounce on both surfaces or use absorbent=false.
Here is how to fix Godot PhysicsMaterial bounce not working. You drop a ball RigidBody3D onto a floor StaticBody3D. You set bounce to 1.0 on the ball expecting a perfect rebound. The ball hits the floor and stops dead. No bounce, no rebound, just a thud. The bounce value is clearly set, but the physics engine ignores it. The problem is almost always where and how the material is assigned.
The Symptom
A RigidBody with a non-zero bounce value collides with a surface and does not rebound. The body either stops immediately on contact or slides along the surface with zero vertical velocity after impact. Setting bounce to higher values (even above 1.0) makes no difference.
What Causes This
PhysicsMaterial not assigned to the body. In Godot 4, bounce is a property of PhysicsMaterial, which must be set on physics_material_override on the RigidBody node itself. Setting bounce-related properties on the CollisionShape or as a standalone resource not connected to a body does nothing.
Only one surface has bounce. The final bounce value is computed from both surfaces in contact. Godot uses the maximum of the two bounce values by default. However, if either body has absorbent set to true on its PhysicsMaterial, the bounce is forced to zero regardless of the other body’s value.
Friction killing velocity before bounce. High friction values can absorb enough energy on the contact frame that the resulting bounce velocity is negligible. This is especially noticeable with small bodies or low-speed impacts.
Continuous collision detection interfering. CCD mode (continuous_cd on RigidBody3D) can sometimes resolve penetration in ways that zero out the rebound velocity. This is rare but happens with thin surfaces.
The Fix
Step 1: Assign PhysicsMaterial correctly.
# In the editor:
# 1. Select your RigidBody3D node
# 2. Inspector > physics_material_override > New PhysicsMaterial
# 3. Expand the material > set bounce = 0.8
# Or via code:
extends RigidBody3D
func _ready():
var mat = PhysicsMaterial.new()
mat.bounce = 0.8
mat.absorbent = false
physics_material_override = mat
The material must be on physics_material_override, not anywhere else. This applies to both RigidBody3D and RigidBody2D.
Step 2: Set bounce on both colliding surfaces. For reliable bouncing, assign PhysicsMaterial to the floor as well:
# floor_setup.gd - attached to StaticBody3D
extends StaticBody3D
func _ready():
var mat = PhysicsMaterial.new()
mat.bounce = 0.5
mat.friction = 0.3
mat.absorbent = false
physics_material_override = mat
With ball bounce 0.8 and floor bounce 0.5, Godot takes the maximum (0.8) for the collision response. If you want the average or minimum, you need a custom approach since Godot 4 uses max by default.
Step 3: Disable absorbent flag. The absorbent property on PhysicsMaterial forces bounce to zero for that contact. Ensure both materials have absorbent = false:
var mat = PhysicsMaterial.new()
mat.bounce = 1.0
mat.absorbent = false # Critical - true kills all bounce
physics_material_override = mat
Step 4: Reduce friction for clean bounces. If the body is rotating on impact, friction converts kinetic energy into angular velocity rather than rebound. Lower friction for bouncy objects:
var mat = PhysicsMaterial.new()
mat.bounce = 0.9
mat.friction = 0.1 # Low friction preserves bounce energy
mat.absorbent = false
physics_material_override = mat
Testing Bounce Properly
Drop the body from a known height and measure the rebound height. A bounce of 1.0 should return to original height (perfect elastic collision). Use a simple script to verify:
extends RigidBody3D
var max_height: float = 0.0
var tracking: bool = false
func _physics_process(_delta):
if tracking and linear_velocity.y > 0:
max_height = max(max_height, global_position.y)
elif tracking and linear_velocity.y <= 0 and max_height > 0:
print("Rebound height: ", max_height)
tracking = false
“Bounce is a two-body property. Both surfaces contribute. If your floor absorbs everything, no amount of bounce on the ball will help.”
Related Issues
For collision shape issues, see CollisionShape Disabled Not Re-Enabling. For physics body movement on slopes, see CharacterBody2D Floor Snap.
PhysicsMaterial on the body, not the shape. Both surfaces matter. Disable absorbent. Bounce works.