Repository: three.js
Issue: SkinnedMesh+InstancedMesh: Removing the buffer array in onUploadCallback throws errors while rendering
Labels: Suggestion

### Description

I'm using `onUploadCallback` to remove the array because it saves hundreds of MB of RAM in our application.
```
//delete the buffer after uploading to GPU to free RAM
BufferAttribute.prototype.onUploadCallback = InterleavedBuffer.prototype.onUploadCallback = function()
{
	this.array = null;
};
```
With r150, this was a safe operation that didn't have any problems. Starting with r151 though, there have been a few changes to the `WebGLRenderer`'s render pipeline regarding the bounding sphere's usage: #25913, #25591. In the case of `SkinnedMesh` and `InstancedMesh`, the bounding sphere is now stored on the `Object3D` itself, which can cause the bounding sphere to recompute after `onUploadCallback` runs. I'm seeing errors like this:

![scrumptious-2023-04-30-00-59-54](https://user-images.githubusercontent.com/19977842/235340193-410e98d2-6e0d-46ef-b15b-161127757afc.png)

I'm able to use this workaround during model initialization to prevent the renderer from doing the computation too late:
```
var o3dCopy = THREE.Object3D.prototype.copy;
THREE.Object3D.prototype.copy = function(source, recursive)
{
	this.boundingSphere = source.boundingSphere?.clone(); //applicable to SkinnedMesh and InstancedMesh
	return o3dCopy.apply(this, arguments);
};

avatar.traverse(function(node)
{
	if((node.isSkinnedMesh || node.isInstancedMesh) && !node.geometry.boundingSphere)
	{
		//both node.boundingSphere and node.geometry.boundingSphere are used by WebGLRenderer, but node.geometry.boundingSphere isn't computed until after onUploadCallback runs
		//guessing that referencing both is a mistake and only node.boundingSphere should be used?
		node.geometry.computeBoundingSphere();
	}
});
```

Here's my best guest as to how this can be fixed in three.js source:
1. In `Object3D.copy()` (or in each applicable subclass), make sure to copy the `boundingSphere` that `Skinned/InstancedMesh` creates if it exists. If we look in `BufferGeometry.copy`, it also clones the bounding sphere.
2. In `WebGLRenderer.projectObject()`, during depth sorting, use `object.boundingSphere` instead of `geometry.boundingSphere` for the case of `Skinned/InstancedMesh`. If we look in `Frustum.intersectsObject()`, it's doing the same distinction that I think `projectObject()` should also be doing. (It's a little awkward though that `boundingSphere === null` vs. `boundingSphere === undefined` is how `Frustum` distinguishes between a normal `Mesh` vs. `Skinned/InstancedMesh`)
3. To clean up the API, it would be nice to have just `Mesh.computeBoundingSphere/Box()` and override the pair in `Skinned/InstancedMesh`. Then we could remove `BufferGeometry.computeBoundingBlah()` entirely and never have to detect whether to use `object.boundingSphere` vs. `geometry.boundingSphere`.

### Reproduction steps

1. [Try out this modified version of the collada loader skinning demo.](https://pastebin.com/Ns5S4Jps) The changes I made were:
a. Change `BufferAttribute.prototype.onUploadCallback` to set the array to null
b. Clone the stormtrooper mesh (clonetrooper??)
2. You will see the same error as the above console screenshot
3. Uncomment the workaround inside the loader callback. Error goes away


### Code

/

### Live example

/

### Screenshots

_No response_

### Version

r152

### Device

Desktop

### Browser

Chrome

### OS

Linux