Reduce mesh size during run time with deformation

I’m using a script from this tutorial to create a “cube sphere” and saved its mesh. And then use its MeshDeformer script to deform my mesh during runtime. The mesh sort of needs to be detailed when I have only one ball on the screen. But when I’ve got multiple balls and the camera a bit further away, I’d like to reduce the mesh size of these balls. But as the script stores vertices and stuff for the deformed mesh I don’t know how to change the mesh size without deleting all the mesh deformation info.

I’m not that good at mesh related stuff so I’d appreciate if someone can explain to me how to do it or show me some code.

Also If you’ve got any suggestions for improving the AddDeformingForce or UpdateVertex functions from the MeshDeformation Script it would help me out a lot in terms of performance.

Below is the entire MeshDeformer script to make it easier.

    using UnityEngine;
    using UnityEngine.AI;

    [RequireComponent(typeof(MeshFilter))]
    public class MeshDeformer : MonoBehaviour {

        public float springForce = 20f;
        public float damping = 5f;
        public float uniformScale = 1f;
        public float speed = 10f;
        public float snapDistance = 1.0f;
        public float blobAnimForce = -100f;
        Mesh deformingMesh;
        Vector3[] originalVertices, displacedVertices;
        Vector3[] vertexVelocities;

        Vector3 blobSpikeStart;
        Vector3 blobSpikeEnd;
        Vector3 slerpedVec3;

        void Start () {
            deformingMesh = GetComponent<MeshFilter>().mesh;
            originalVertices = deformingMesh.vertices;
            displacedVertices = new Vector3[originalVertices.Length];
            for (int i = 0; i < originalVertices.Length; i++) {
                displacedVertices[i] = originalVertices[i];
            }
            vertexVelocities = new Vector3[originalVertices.Length];

            blobSpikeStart = Random.onUnitSphere + transform.position;
        }




        void Update () {
            if (Vector3.Distance(slerpedVec3, Vector3.Slerp(blobSpikeStart, blobSpikeEnd, Time.time * speed)) < snapDistance){
                blobSpikeEnd = Random.onUnitSphere + transform.position;
                blobSpikeStart = slerpedVec3;
            }
            slerpedVec3 = Vector3.Slerp(blobSpikeStart, blobSpikeEnd, Time.time * speed);

            //Quaternion.Slerp(blobSpikeStart, blobSpikeEnd, Time.time * speed);
            AddDeformingForce((slerpedVec3 * this.transform.localScale.x), blobAnimForce);



            uniformScale = transform.localScale.x;
            for (int i = 0; i < displacedVertices.Length; i++) {
                UpdateVertex(i);
            }
            deformingMesh.vertices = displacedVertices;
            deformingMesh.RecalculateNormals();
        }

        void UpdateVertex (int i) {
            Vector3 velocity = vertexVelocities[i];
            Vector3 displacement = displacedVertices[i] - originalVertices[i];
            displacement *= uniformScale;
            velocity -= displacement * springForce * Time.deltaTime;
            velocity *= 1f - damping * Time.deltaTime;
            vertexVelocities[i] = velocity;
            displacedVertices[i] += velocity * (Time.deltaTime / uniformScale);
        }

        public void AddDeformingForce (Vector3 point, float force) {
            point = transform.InverseTransformPoint(point);
            for (int i = 0; i < displacedVertices.Length; i++) {
                AddForceToVertex(i, point, force);
            }
        }
        void AddForceToVertex (int i, Vector3 point, float force) {
            Vector3 pointToVertex = displacedVertices[i] - point;
            pointToVertex *= uniformScale;
            float attenuatedForce = force / (1f + pointToVertex.sqrMagnitude);
            float velocity = attenuatedForce * Time.deltaTime;
            vertexVelocities[i] += pointToVertex.normalized * velocity;
        }
    }

Generally this problem is handled by a process called LOD switching, which stands for Level Of Detail switching. The simplest example is you have two versions of the mesh, one with low polygon count, one with high, and then as the mesh gets a certain distance from you, you switch to the lower count one.

Unity already includes an LOD management mechanism, but it is generally distance-based. If you are looking to reduce based on total count of balls, then you need another mechanism to track how many balls you have, then start reducing them to use lower-polygon versions.

In practice however, dynamically reducing the complexity at runtime is far too computationally intensive, not to mention difficult to do right in all conditions, so pre-made levels of detail are generally used.

Im perfectly fine with switching mesh size based on camera distance, that’s not really the problem. I don’t know how to remap the new smaller meshes’ vertices to the vertices array I have in the script. My meshes are deforming constantly, replacing it with my LOD mesh will be jarring as the new mesh won’t be deformed exactly like the one I had previously.

Also as the deformation happens due to some random factors, I can’t really know how it will be deformed.

Assuming the shapes are at least somewhat “correlated” between their high LOD and low LOD versions (i.e., both are spheres, or both are cubes, etc.), just traverse the low LOD shape when you bring it in, and find correlatedly “near” vertices (some number of them) in the undeformed high LOD mesh, and for each of those verts, see how far the high LOD one is deflected from its home spot, and then apply that filtered deflection to the low LOD mesh.

That’s the naive approach, but given reasonable constraints I imagine it will get you a long way towards what you’re trying to achieve. Everything else after that is just filter parameters and coefficients: falloff over distance, relevant points to consider, etc.

Same goes for scaling back up to high LOD… interpolate!