Centre of mass not recalculated after scaling

I am spawning a prefab object at runtime (actually, in the Start() method of another object), and I need to apply a scaling to the object. I made a little component to handle this:

public class Spawner : MonoBehaviour {

public Transform SpawnPrefab;
public Vector3 Scale;

void Start () {
var spawn = Instantiate(SpawnPrefab, Vector3.zero, Quaternion.identity);
spawn.localScale = Vector3.Scale(spawn.localScale, Scale);
// spawn.GetComponent<Rigidbody>().ResetCenterOfMass();  // Has no effect
}
}


The pivot point of the prefab I am spawning does not coincide with the centre of mass of the object. Therefore, the rescaling means that the centre of mass location relative to the pivot will change. However, it's not being updated automatically, so my spawned object has unexpected physics.

I tried adding a call to GetComponent<Rigidbody>().ResetCenterOfMass() immediately after the call to Scale() (the commented-out line above), but this has no effect.

However, if I put the call to ResetCenterOfMass() in the Start() method of a separate little component added to the spawned object, e.g.

public class COMReset : MonoBehaviour {
void Start() {
GetComponent<Rigidbody>().ResetCenterOfMass();
}
}


this does cause the centre of mass to be recalculated correctly. However, the spawned object appears to have already been through at least one physics update with the wrong COM by this time, and so has already acquired some unexpected momentum.

Why isn't the COM being automatically recalculated, without me having to call ResetCenterOfMass() explicitly? And if I must trigger it manually, can I do that immediately after the calls to Instantiate() and Scale(), rather than deferring like this?

• Hm, I'd thought the center of mass was stored in local coordinates and wouldn't be affected by uniform scaling. But the intertia tensor may change. Have you tried this with a call to Physics.SyncTransfotms to push your scale changes to the physics engine immediately after scaling? Jul 18 '18 at 10:36
• @DMGregory According to Rigidbody.centerOfMass the center of mass "will not reflect the transform's scale". I guess that's saying that the center of mass coordinates are not true local coordinates, due to the treatment of scale. Regardless, I can definitely see that applying a uniform scale to the transform requires that the COM vector is scaled identically (unless it happens to be at [0,0,0]), but that's not happening automatically. Unfortunately, Physics.SyncTransforms is having no effect, but thank you for the idea. Jul 18 '18 at 11:06
• @DMGregory Apologies: Physics.SyncTransforms is working. I don't know what I was doing wrong before. Thank you again! Jul 20 '18 at 16:22
• Cool! I'd never used that method before. Want to write up an answer based on your experience with it? Jul 20 '18 at 16:23
• Yep, I'll post an answer shortly. Jul 20 '18 at 16:24

With thanks to @DMGregory for the suggestion, a call to Physics.SyncTransforms before invoking Rigidbody.ResetCenterOfMass fixes the problem:

public class Spawner : MonoBehaviour {

public Transform SpawnPrefab;
public Vector3 Scale;

void Start () {
var spawn = Instantiate(SpawnPrefab, Vector3.zero, Quaternion.identity);
spawn.localScale = Vector3.Scale(spawn.localScale, Scale);
Physics.SyncTransforms();
spawn.GetComponent<Rigidbody>().ResetCenterOfMass();
}
}


Evidently this direct modification of the transform scale isn't being automatically passed through to the physics engine, but Physics.SyncTransforms lets us manually flush those changes down to PhysX, so that the ResetCenterOfMass computation is then based on the correctly scaled transform.