Physics Material
A Physics Material asset controls surface physics — how much friction and bounciness apply when two Colliders touch, from ice slides to rubber balls in Unity.
Imagine...
A Physics Material is the surface of a playground. Rough concrete → the ball stops quickly (high friction). Polished stone → it slides far (low friction). Rubber → it bounces high (high bounciness). Sand → it thuds (low bounciness). In Unity you create a Physics Material as a standalone asset, then assign it to any Collider to change how it interacts with the world.
The concept in detail
A Physics Material (file .physicMaterial in 3D, .physicsMaterial2D
in 2D) is a ScriptableObject-like asset with four main fields:
Dynamic Friction (while sliding, 0–1),
Static Friction (to start moving from rest, usually
higher than Dynamic), Bounciness (0 = no bounce, 1 =
full bounce), and two combine modes —
Friction Combine and
Bounce Combine (Average/Min/Max/Multiply).
When two Colliders with different Physics Materials meet, Unity combines their values. With Average: friction = (frictionA + frictionB) / 2. With Minimum: friction = min(frictionA, frictionB) — useful for ice (one side at 0 always wins). Combine priority: Average < Minimum < Maximum < Multiply.
Important: Bounciness = 1 in Unity is not
a lossless bounce. Damping and gravity still apply between bounces. For near-perfect bounce,
use Bounciness = 1, Bounce Combine = Maximum, and Rigidbody drag = 0.
You can swap Physics Materials at runtime via collider.material or
collider.sharedMaterial. Use sharedMaterial when the change should
affect every instance that shares the same asset (saves memory).
Real-world material presets
🧱 Brick
Dynamic Friction: 0.6
Static Friction: 0.6
Bounciness: 0.0
🧊 Ice
Dynamic Friction: 0.02
Static Friction: 0.02
Bounciness: 0.0
🏀 Rubber
Dynamic Friction: 0.8
Static Friction: 0.8
Bounciness: 0.8
🪵 Wood
Dynamic Friction: 0.48
Static Friction: 0.48
Bounciness: 0.0
| Combine Mode | Formula | Use when |
|---|---|---|
| Average | (A + B) / 2 | Default, average |
| Minimum | min(A, B) | Ice (one side = 0 wins) |
| Maximum | max(A, B) | Rubber (maximum bounce) |
| Multiply | A × B | Sticky surfaces, multiply |
Hands-on steps
Create a Physics Material
Project Panel → right-click → Create → Physics Material (3D) or Physics Material 2D. Name it after the surface (Rubber, Ice...).
Set Friction and Bounciness
Dynamic Friction (0–1), Static Friction (0–1), Bounciness (0–1). Use a preset table or experiment.
Pick a Combine Mode
Friction/Bounce Combine: Average is the default. Use Minimum for ice, Maximum for bouncy rubber.
Assign it to a Collider
Select the GameObject → Collider → "Material" slot → drag the Physics Material from the Project.
Play and tweak
Enter Play Mode, watch how bodies move, and adjust values. You can edit the Physics Material while playing.
Interactive simulator
Tune Friction and Bounciness, then drop the ball to see the effect.
Set the values and press "Drop ball"
Code example
BasicSwap Physics Materials at runtime when the character stands on different surfaces.
using UnityEngine;
public class SurfaceMaterialSwapper : MonoBehaviour
{
public PhysicMaterial normalMat, iceMat, rubberMat;
Collider col;
void Start() => col = GetComponent<Collider>();
void OnCollisionStay(Collision collision)
{
// Read the ground tag
string tag = collision.gameObject.tag;
col.material = tag switch
{
"Ice" => iceMat,
"Rubber" => rubberMat,
_ => normalMat,
};
}
void OnCollisionExit(Collision _)
{
col.material = normalMat; // Restore when leaving the ground
}
}Code example
AdvancedCreate a Physics Material at runtime and tweak it from game state — no asset file required.
using UnityEngine;
// Create and own a PhysicMaterial at runtime — no Project asset
public class DynamicPhysicsMaterial : MonoBehaviour
{
Collider col;
PhysicMaterial dynMat;
[Range(0f, 1f)] public float friction = 0.4f;
[Range(0f, 1f)] public float bounciness = 0f;
void Awake()
{
col = GetComponent<Collider>();
// Runtime PhysicMaterial, no Project asset needed
dynMat = new PhysicMaterial("Dynamic")
{
dynamicFriction = friction,
staticFriction = friction * 1.2f,
bounciness = bounciness,
frictionCombine = PhysicMaterialCombine.Average,
bounceCombine = PhysicMaterialCombine.Maximum
};
col.material = dynMat;
}
// Call from elsewhere to change live (e.g. character frozen)
public void SetIce()
{
dynMat.dynamicFriction = 0.01f;
dynMat.staticFriction = 0.01f;
col.material = dynMat; // Re-assign so Unity picks up the new values
}
}📌 Quick recap
- ▸0 = no friction / no bounce, 1 = maximum
- ▸Static Friction > Dynamic Friction (real physics)
- ▸Minimum Combine: one side at 0 → result is 0 (ideal ice)
- ▸col.material makes a private copy; sharedMaterial is shared
- ▸Re-assign col.material after editing a PhysicMaterial at runtime
⚠️ Common mistakes
❌ Set collider.material.bounciness = X without re-assigning
Unity does not detect the inner change — values stay stale
✅ Build the new values and assign: col.material = updatedMat;
❌ Bounciness = 1 but the ball still loses energy
Rigidbody.drag > 0 and gravity eat energy
✅ Set drag = 0 and Bounce Combine = Maximum