I'm at my Wits end with Re-sizing an Object during the game and having those changes saved

I have created a script with the help of this community to resize a gameobject when pressing Play in the Editor. The script is successful. My next step will be to upload the resized object to a database which I’m having problems figuring out. Anyways. The problem is, when I press Play again to be taken out of “Game” mode. The meshes retains the resize, but the transform appears to go BACK to before I hit play. Here are some screenshots, and then the code.

Before Play, very large object

After Hitting Play

Exiting Game Mode (scattered tiny pieces of couch everywhere)

My code recalculates bounds, normals, and everything. The Prefab itself is then appearing as scattered couch pieces. I’m worried if I try to upload this to the database it won’t be properly saved with the proper transforms.

Here is the code.

public class HiddenMonkTest : MonoBehaviour {
    public float setRealLifeSize;
    Vector3 center;
    Vector3 size;
    float largestDistance;
    float scale;
    MeshFilter[] objMeshFilter;
    CombineInstance[] combineMeshFilter;

    void Awake()
    {

        List<Vector3[]> allWorldCoords = new List<Vector3[]>();
        List<Vector3> centers = new List<Vector3>();
        MeshFilter[] objMeshFilter = this.GetComponentsInChildren<MeshFilter>();
     

        foreach (Renderer render in transform.GetComponentsInChildren<Renderer>())
        {
            allWorldCoords.Add(BoundsToWorldCoordinates(render.bounds));
            centers.Add(render.bounds.center);
        }

        center = Average(centers.ToArray()); //find center by getting average of all centers

        Vector3[] totalBound = new Vector3[8]; //we make each vector a default of the center vector so we can compare with sqrMagnitude
        for (int i = 0; i < totalBound.Length; i++)
        {
            totalBound[i] = center;
        }

        for (int i = 0; i < allWorldCoords.Count; i++)
        {
            for (int j = 0; j < totalBound.Length; j++)
            {
                if ((center - allWorldCoords[i][j]).sqrMagnitude > (center - totalBound[j]).sqrMagnitude)
                {
                    totalBound[j] = allWorldCoords[i][j];
                }
            }
        }

        size = GetCubeSize(totalBound);
        SetGreatesttDistance();
        SetScale();
        ResizeMeshCollection(objMeshFilter);

        Debug.Log(size.x);
        Debug.Log(size.y);
        Debug.Log(size.z);

    }
    void ResizeMeshCollection(MeshFilter[] collection)
    {
        foreach (MeshFilter mf in collection)
        {
            mf.GetComponent<MeshFilter>();
            Transform tf = mf.GetComponent<Transform>();
            Mesh mesh = mf.sharedMesh;
            Bounds bounds = mf.GetComponent<Renderer>().bounds;
            Vector3[] verts = mesh.vertices;

            for (int i = 0; i < verts.Length; i++)
            {
                verts[i].x = verts[i].x * scale;
                verts[i].y = verts[i].y * scale;
                verts[i].z = verts[i].z * scale;
            }
            tf.position = new Vector3((tf.position.x - center.x)* scale, (tf.position.y - center.y) * scale, (tf.position.z - center.z) * scale);
            mesh.vertices = verts;
            mesh.RecalculateBounds();
            mesh.RecalculateNormals();
        
        }
    }

    Vector3[] BoundsToWorldCoordinates(Bounds bounds)
    {
        return BoundsToWorldCoordinates(bounds.center, bounds.extents);
    }
    //
    Vector3[] BoundsToWorldCoordinates(Vector3 position, Vector3 extents)
    {
        Vector3[] worldCoordinates = new Vector3[8];
        worldCoordinates[0] = new Vector3(extents.x, extents.y, extents.z);
        worldCoordinates[1] = new Vector3(extents.x, extents.y, -extents.z);
        worldCoordinates[2] = new Vector3(extents.x, -extents.y, extents.z);
        worldCoordinates[3] = new Vector3(extents.x, -extents.y, -extents.z);
        worldCoordinates[4] = new Vector3(-extents.x, extents.y, extents.z);
        worldCoordinates[5] = new Vector3(-extents.x, extents.y, -extents.z);
        worldCoordinates[6] = new Vector3(-extents.x, -extents.y, extents.z);
        worldCoordinates[7] = new Vector3(-extents.x, -extents.y, -extents.z);

        for (int i = 0; i < worldCoordinates.Length; i++)
        {
            worldCoordinates[i] += position;
        }

        return worldCoordinates;
    }

    Vector3 GetCubeSize(Vector3[] vectors)
    {
        Vector3 center = Average(vectors);
        Vector3 size = Vector3.zero;

        float[] x = vectors.Select(a => a.x).ToArray();
        float[] y = vectors.Select(a => a.y).ToArray();
        float[] z = vectors.Select(a => a.z).ToArray();

        float xMin = x.Min();
        float xMax = x.Max();
        float yMin = y.Min();
        float yMax = y.Max();
        float zMin = z.Min();
        float zMax = z.Max();

        size.x = xMax - xMin;
        size.y = yMax - yMin;
        size.z = zMax - zMin;

        return size;
    }

    Vector3 Average(params Vector3[] vectors)
    {
        return AddAll(vectors) / vectors.Length;
    }

    Vector3 AddAll(params Vector3[] vectors)
    {
        Vector3 vectorsSum = Vector3.zero;
        foreach (Vector3 vector in vectors)
        {
            vectorsSum += vector;
        }
        return vectorsSum;
    }

    void SetGreatesttDistance()
    {
        float localHighest;
        localHighest = size.x;
        if (localHighest < size.y) localHighest = size.y;
        if (localHighest < size.z) localHighest = size.z;
        largestDistance = localHighest;
        Debug.Log(largestDistance);
    }
    void SetScale()
    {
        scale = setRealLifeSize / largestDistance;
    }
}



bump

From a first glance, it looks to me like you’re waaaay overcomplicating things.

It seems as if you are doing all of these calculations so that you can resize and replace the meshes from a prefab in world space, but have their transform scale values still always be 1.
Why are you doing it this way? Why not allow transform scale values other than 1?

Anyway, I believe the MAIN answer to your problem is on line 59 and 69: You scale the mesh and then change the position of it’s transform to match your new scale. Good. Great! The problem is this: When exiting play mode, all of your transform positions will return to their PRE gameplay state, but since your code edits the sharedMesh (as opposed to the run-time mesh, which is instanced), the mesh doesn’t return to it’s pre gameplay state, and you have a bunch of small parts in their original positions.

If I were you, I’d just save the position, scale and rotation in your database rather than the entire mesh, but perhaps you can fill me in a little bit more about your project and why it’s important to do it this way.

Ive been randomly feeling like Ive been growing and shrinking lately, now I know why! :slight_smile:
(in case no one got the joke, he named the script after me ^^)

After a bit of digging I remember this thread we did now Getting the total x,y, z dimension of an object - Unity Engine - Unity Discussions

It does seem over complicated, since when I posted that code, I didn’t know of the method “Bounds.Encapsulate
which I later posted on that same thread, making things much much simpler. (but he didnt update his code with the simpler method)

All of the code he posted is somewhat irrelevant to the problem.
The question that I think he is basically asking is “How do I save changes made in edit mode?”

I never used this, but since I think you are mainly concerned with doing this in the editor and not in an actual build, maybe you can use this class

Im not sure, but maybe you can create and save your gameobject as a prefab after you made the changes.

Thank you very much again BenZed and once again HiddenMonk for helping me out. Yes you are saved as the test script ( always credit your Authors!), I had been doing a bunch of back and forth testing of different methods to accomplish my goals, and yours was the one I went with!

@BenZed I am trying to create a database that will correctly adjust for relative real world size with the HoloLens coming out. So Users will be importing their 3d models to unity with no understanding of how the object represents real world size, and they will know little to nothing about the Unity Editor. This script will hopefully give a standardization for ease of use and making sure the database is consistent when the hololens makes calls. I am not 100 percent familiar with Unity’s platform, and at times the documentation seems sparse, so this may not be the best way to accomplish what I need. But, forward progress is forward progress, and a learning experience more about Unity.
When you ask me to just save position, size, and rotation to the database, I am assuming I also will be saving the Meshes? It’s important to see the object as well! Do you have any good guides or good working examples of saving to a DB? Right now Microsoft hasn’t released Entity support for windows 10 apps, so I’m thinking I’ll go with sqlite or wait. :stuck_out_tongue: Again, thanks for your help. I will review editing run-time meshes on the instance itself later!

@HiddenMonk I think I did all the work and understood your code you gave me, and made all my changes I needed (I’m not showing all of it) So I didn’t want to mess with something that worked and try an easier method. I will look into saving it as a prefab, which is essentially what I want to do anyways. I am not up to speed with saving to the DB yet, but I think I can’t go wrong with saving this as a new prefab. Excellent advice as always.

For database stuff, maybe you can look at this

The idea would be to save the prefab as an assetbundle, then, maybe through the WWW class, or through pure c# using the System.Net namespace as described here
.net - Upload file to FTP using C# - Stack Overflow
you can send the file over through FTP.

I never done any of this, so cant be much of a help =)

Alright, I’m back. I’ve tried a few of your suggestions. First PrefabUtility and saving the object as a prefab. If I run

PrefabUtility.CreatePrefab("Assets/UploadedAssets/" + assetName + ".prefab", this.gameObject);

The original object has the meshes attached to them. The newly created Prefab only contains a reference to the mesh that is on the original object. If I were to upload this prefab to the database, or delete the original. I would no longer have the meshes on the new prefab. This doesn’t seem like too much of an issue in my mind, if I have to upload both, or somehow attach the mesh to the prefab, or store it in the database with a reference, that’s fine. I can look more into this.

Second. Changing the Transform.Scale. This appears to not work at all. I removed all my transform.position code. and sure enough when I hit play. tiny pieces of couch everywhere just the same in the image. I then edit the scale that is needed to match my mesh changes… and… nope, it doesn’t move the position closer to the other couch pieces unless I give it the inverse of the scale. Which would create the exact same large couch object!

I’m going to have to rethink this. I’ll have to make an application or a “game” in unity, that will accomplish all of this at runtime. Which is a much bigger pain in the ass. I’m having difficulty with the AssetBundle api because half of it is out of date, the other half contains little to no documentation, and the other half doesn’t seem to be doing what I want, and then it seems that I can’t build assetbundles at runtime?