- Home /
How do I scale an object or prefab to a size in Unity units?
I'm working on a game in which most of the objects will all fit into 3d grid spaces in the scene, which are 1x1x1 Unity units in size. I am currently in the process of programming a level editor for the game, where the level designers would be able to simply choose a prefab in the inspector, and then click on a spot in the scene grid to instantiate the object in the selected grid space.
However, we have a few different artists making assets for the game, and the prefabs come in different sizes. How would I programmatically instantiate a prefab with a scale that makes the object exactly 1.0 Unity units high? There must be a way to standardize this process, but I can't seem to find it.
By the way, I am using C#, though I don't think that would change the approach (just the syntax).
It would be better if you got the artists to standardize. You don't want to touch scale if it's not strictly necessary, since it's best for performance if objects remain at a scale of 1.0.
@Eric5h5 Thanks for the feedback. I am inclined to agree with you; just for the sake of it, is there an approach to achieve this in code?
Possibly; maybe somebody will answer the question. ;) That's why I posted a comment, since it's not a direct answer.
Answer by robertbu · Jul 19, 2013 at 05:52 AM
I'm going to go out on a bit of a limb here since I don't have a lot of experience with meshes. First, you can use the mesh.bounds.size and set the Transform.localScale at runtime to get a one-unit sized object. As @Eric5h5 mentions, it is better if you don't do it this way (i.e. resize using the Transform), but it may be workable in your situation.
Second, you could also resize the mesh in the editor. Here is a bit of code to show you the concept:
void ResizeMeshToUnit() {
MeshFilter mf = GetComponent<MeshFilter>();
if (mf == null)
return;
Mesh mesh = mf.sharedMesh;
Bounds bounds = mesh.bounds;
float size = bounds.size.x;
if (size < bounds.size.y)
size = bounds.size.y;
if (size < bounds.size.z)
size = bounds.size.z;
if (Mathf.Abs(1.0f - size) < 0.01f) {
Debug.Log ("Already unit size");
return;
}
float scale = 1.0f / size;
Vector3[] verts = mesh.vertices;
for (int i = 0; i < verts.Length; i++) {
verts[i] = verts[i] * scale;
}
mesh.vertices = verts;
mesh.RecalculateBounds();
mesh.RecalculateNormals();
}
You could put something like this in an editor script and resize the meshes. Note if you put this function in a script and execute it at runtime in the editor, it will permanently change the mesh.
Thank you sir. This is valiant effort, and does work as described, with a $$anonymous$$or tweak:
void Resize$$anonymous$$eshToUnit(GameObject t) {
$$anonymous$$eshFilter mf = t.GetComponent<$$anonymous$$eshFilter>();
if (mf == null)
return;
$$anonymous$$esh mesh = mf.shared$$anonymous$$esh;
//***Set this to renderer bounds ins$$anonymous$$d of mesh bounds***
Bounds bounds = t.renderer.bounds;
float size = bounds.size.x;
if (size < bounds.size.y)
size = bounds.size.y;
if (size < bounds.size.z)
size = bounds.size.z;
if ($$anonymous$$athf.Abs(1.0f - size) < 0.01f) {
Debug.Log ("Already unit size");
return;
}
float scale = 1.0f / size;
Vector3[] verts = mesh.vertices;
for (int i = 0; i < verts.Length; i++) {
verts[i] = verts[i] * scale;
}
mesh.vertices = verts;
mesh.RecalculateBounds();
mesh.RecalculateNormals();
}