Skip to content

Instantly share code, notes, and snippets.

@jcx
Forked from FreyaHolmer/RigidbodyMassCalculator.cs
Created December 19, 2015 09:17
Show Gist options
  • Save jcx/709ea9e5538326bd71a3 to your computer and use it in GitHub Desktop.
Save jcx/709ea9e5538326bd71a3 to your computer and use it in GitHub Desktop.
Used to approximate a proper mass value for all the colliders in a given Rigidbody
using UnityEngine;
using System.Linq;
[RequireComponent(typeof(Rigidbody))]
public class RigidbodyMassCalculator : MonoBehaviour {
public float density = 1f;
public bool recalculateOnAwake = true;
Rigidbody rb;
void Awake () {
rb = GetComponent<Rigidbody>();
if( recalculateOnAwake )
RecalculateMass();
}
public void RecalculateMass() {
Collider[] cols = GetComponentsInChildren<Collider>();
float volume = cols.Sum( x => GetVolume( x, transform.localScale ) );
rb.mass = volume * density;
}
static float GetVolume( Collider c, Vector3 scale ) {
if( c is BoxCollider )
return BoxVolume( Vector3.Scale(( c as BoxCollider ).size, scale) );
if( c is MeshCollider ) // Approximate. Might want to use actual convex polytype volume
return BoxVolume( Vector3.Scale( c.bounds.extents * 2, scale ) );
float uniScale = scale.x * scale.y * scale.z;
if( c is SphereCollider )
return SphereVolume( ( c as SphereCollider ).radius * uniScale );
if( c is CapsuleCollider ) {
CapsuleCollider cc = c as CapsuleCollider;
return CapsuleVolume( cc.height * scale[cc.direction], cc.radius * uniScale );
}
if( c is CharacterController ) {
CharacterController chc = c as CharacterController;
return CapsuleVolume( chc.height * scale.y, chc.radius * uniScale );
}
Debug.Log( "Invalid attempt to get volume of " + c.GetType().Name, c.gameObject );
return 0f;
}
static float BoxVolume( Vector3 size ) {
return size.x * size.y * size.z;
}
static float SphereVolume( float r ) {
return r * r * r * Mathf.PI * ( 4f / 3f );
}
static float CylinderVolume( float h, float r ) {
return h * r * r * Mathf.PI;
}
static float CapsuleVolume( float h, float r ) {
float cylHeight = h - 2 * r;
float sphereVol = SphereVolume( r );
// If radius is twice as large or bigger than h - it degenerates into a sphere
if( cylHeight <= 0 )
return sphereVol;
float cylVol = CylinderVolume( cylHeight, r );
return sphereVol + cylVol;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment