Unity Term Book
Physics

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 ModeFormulaUse when
Average(A + B) / 2Default, average
Minimummin(A, B)Ice (one side = 0 wins)
Maximummax(A, B)Rubber (maximum bounce)
MultiplyA × BSticky surfaces, multiply

Hands-on steps

1

Create a Physics Material

Project Panel → right-click → Create → Physics Material (3D) or Physics Material 2D. Name it after the surface (Rubber, Ice...).

2

Set Friction and Bounciness

Dynamic Friction (0–1), Static Friction (0–1), Bounciness (0–1). Use a preset table or experiment.

3

Pick a Combine Mode

Friction/Bounce Combine: Average is the default. Use Minimum for ice, Maximum for bouncy rubber.

4

Assign it to a Collider

Select the GameObject → Collider → "Material" slot → drag the Physics Material from the Project.

5

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

Basic

Swap 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

Advanced

Create 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