Based on @DMGregory 's helpful comments, here is my solution:
To Cache (called in OnEnable()):
void CacheMeshAndSkeleton() {
if (originalBonePositions == null) {
originalBonePositions = new Vector3[skinnedMeshRenderer.bones.Length];
for (int boneIndex = 0; boneIndex < skinnedMeshRenderer.bones.Length; boneIndex++) {
originalBonePositions[boneIndex] = skinnedMeshRenderer.bones[boneIndex].position;
}
}
if (originalMesh == null) originalMesh = skinnedMeshRenderer.sharedMesh;
skinnedMeshRenderer.sharedMesh = Instantiate(originalMesh);
}
Note that the null-check isn't really needed. For me it was, since I'm running the script in edit mode using [ExecuteInEditMode], and edit mode seems to call OnEnable more than once, so I needed to prevent it from overwriting the original mesh with a deformed one.
To Reset:
void ResetMeshAndSkeleton() {
for (int boneIndex = 0; boneIndex < originalBonePositions.Length; boneIndex++) {
skinnedMeshRenderer.bones[boneIndex].position = originalBonePositions[boneIndex];
}
skinnedMeshRenderer.sharedMesh = Instantiate(originalMesh);
// Note that it seems to me that order might be important here.
// If you reset the the Mesh first, when you move the bones back,
// it will apply linearblendskinning to the mesh and deform it to the bone positions.
// Not sure why this matters, but seemed to in my testing
}
This seems to work great!
UPDATE:
I found an increase in performance by instead caching the mesh's arrays (vertices, etc) and swapping them back to restore.
I used the CopyTo array function. sourceArray.CopyTo(destinationArray, 0); where 0 is the index to start copying from.
In my case I was only manipulating the vertices, the tris, normals, etc were never altered, so just copying this one array saved a huge amount of performance vs. instantiation.