- Home /
How do I permanently resize a model with children?
I am in the process of building some tools for level creation and asset management. We have a need to be able to permanently resize models to 1.0 unity units max, x, y, or z. Working from a solution provided by @robertbu, I have devised a script which works great for objects which have no children. However, I am having an issue with resizing objects which do have children. I have a function right now which will cycle through the bounds of the children to determine the total bounds of the object, and then resize their meshes and translate their positions relative to the parent, using a calculated scale.
The problem is that the meshes stay permanently resized as they should, but the new positions only apply to the instance, resulting in models whose children resize smaller and smaller every time they are placed because the new positions never permanently applied. How can I permanently change the child mesh positions relative to the parent?
Here is the function I am currently working with:
void ResizeMeshToUnit(GameObject g) {
int count = g.transform.GetChildCount();
float minX, minY, minZ, maxX, maxY, maxZ, finalX, finalY, finalZ, size;
//initialize variables.
finalX = finalY = finalZ = size = 0f;
minX = maxX = g.transform.position.x;
minY = maxY = g.transform.position.y;
minZ = maxZ = g.transform.position.z;
if (count < 1)
{
return;
}
//cycle through children bounds to get minimums and maximums for model
for (int i = 0; i < count; i++) {
Transform t = g.transform.GetChild(i);
var renderer = t.GetComponent<Renderer>();
if (renderer != null)
{
Bounds bounds = renderer.bounds;
if (bounds.min.x < minX)
{
minX = bounds.min.x;
}
if (bounds.min.y < minY)
{
minY = bounds.min.y;
}
if (bounds.min.z < minZ)
{
minZ = bounds.min.z;
}
if (bounds.max.x > maxX)
{
maxX = bounds.max.x;
}
if (bounds.max.y > maxY)
{
maxY = bounds.max.y;
}
if (bounds.max.z > maxZ)
{
maxZ = bounds.max.z;
}
}
}
//establish overall bounds
finalX = maxX - minX;
finalY = maxY - minY;
finalZ = maxZ - minZ;
//determine largest dimension
size = finalX;
if (size < finalY)
{
size = finalY;
}
if (size < finalZ)
{
size = finalZ;
}
//return if already correct scale
if (Mathf.Abs(1.0f - size) < 0.01f)
{
Debug.Log ("Already unit size");
return;
}
//calculate scale
float scale = 1.0f / size;
//use scale to resize child meshes and alter positions
for (int i = 0; i < count; i++)
{
Transform t = g.transform.GetChild(i);
MeshFilter mf = t.GetComponent<MeshFilter>();
if (mf != null)
{
Mesh mesh = mf.sharedMesh;
t.localPosition *= scale;
Vector3[] verts = mesh.vertices;
for (int j = 0; j < verts.Length; j++)
{
verts[j] = verts[j] * scale;
}
mesh.vertices = verts;
mesh.RecalculateBounds();
mesh.RecalculateNormals();
}
}
}
How can I get the positions to permanently stick in the model?
EDIT: The original question, which @robertbu provided a working approach for can be found here: http://answers.unity3d.com/questions/495977/how-do-i-scale-an-object-or-prefab-to-a-size-in-un.html
EDIT 2: Solution has been worked out and is contained in an an answer below.
It would help if you could reference the original question where RobertBu helped you re-size the mesh permanently. It would provide some context.
Just wondering why you can't just resize the scale of the parent when you've worked out the entire size of the children. I can't quite figure out why you need to go through and move and resize the children.
@Sajidfarooq I agree, the context may provide some help. I have edited the original post and provided a link.
@whydoidoit You are correct, I can resize the scale of the parent rather than changing and moving each of children. However the effect will only apply to each instance, and not permanently change the model unless the meshes of the children themselves are scaled and recalculated.
The reason I want to permanently change the scale of the model is so that I can avoid the problems with animations that arise from scaling an object after the animation is created, and to reduce additional overhead which may be needed to calculate objects which aren't at 1.0 scale.
If I can create a tool to permanently change the model correctly, the artists can import the models, use the tool to size them to exact scale, and then create $$anonymous$$ecanim animations to be used. If the animations are done first, and then the object instance is scaled, my understanding is they can produce undesired results.
Right but you could just create a prefab or just alter the model scale as @fattie says (which could be done automatically using your script as part of the asset import process).
Answer by Fattie · Aug 17, 2013 at 07:23 AM
LATER ...
dude, I think you're looking for the famous encapsulate function
you use it constantly with bounds ....... it makes things so easy
http://answers.unity3d.com/questions/360459/encapsulate-bounds-problem.html
Does that help!?
EARLIER ...
Shouldn't you just be changing the scale of the actual model on the importer ?
@Fattie this is a great question, but that would require the exact bounds of model to be known in advance so that an exact calculation of scale can be applied on the importer to make the object no wider, taller, or longer than 1 Unity unit. One of the purposes of the script is to be able to arrive at that calculation.
Ideally, artists would create the models at 1.0 Unity units in scale before importing, however, art is not my forte, and the artists I am working with are having fits over trying to create the models in the right size.
Green -- just one point.
"artists I am working with are having fits..."
it is a classic in the video game industry, that, modellers $$anonymous$$UST make models at correct size. it's like "point one" in the business.
(You can see 1000s questions on here about it.)
they simply have to utterly change their ways. Fact. if they are beginners you should just tell them this directly - see the 1000s questions on here - for their benefit
I don't really follow you here. Have an editor script called "Size Fixer"
it has I guess two lines of code. (1) look at the bounds to find the longest dimension. (2) change the scale so that it is 5 meters (or whatever your goal is)
this is a commonplace calculation ... here's an example where some GREAT AD$$anonymous$$IN explain it nicely! ;-) ..
http://answers.unity3d.com/questions/432009/resizing-a-gameobject-based-on-mouse-position.html
So, just run "Size Fixer" when you want, or automatically when a mesh is added
I apologize if I'm "missing something" about your question
@Fattie I readily admit that these artists are indeed beginners with Unity. They have much to learn. However, no need to apologize my friend, perhaps it is not you, but me who is "missing something": won't animations be affected by scaling down (or up) an object after the animation has been created in $$anonymous$$ecanim?
Also, "Size Fixer" looks great for objects with no children, but let's say we have a model which is comprised of child meshes. Let's also say that the object must be no bigger than 1.0 Unity units on any axis. Now we can't simply use this line anymore:
lengthNow = ourSprite.renderer.bounds.size.x;
Ins$$anonymous$$d, we've got to calculate the farthest x, y, and z bounds that renderers of children reach to arrive at an equivalent to "lengthNow", and then we can resize the objects, similar to this portion of code from the method in the original post:
//establish overall bounds
finalX = maxX - $$anonymous$$X;
finalY = maxY - $$anonymous$$Y;
finalZ = maxZ - $$anonymous$$Z;
//deter$$anonymous$$e largest dimension
size = finalX;
if (size < finalY)
{
size = finalY;
}
if (size < finalZ)
{
size = finalZ;
}
//**omitted for clarity**
//calculate scale
float scale = 1.0f / size;
regarding the important question scaling of an animation in $$anonymous$$ecanim ... I'm almost certain there is no problem with that or the whole game engine would fall apart ... but I'm not a Top Expert in $$anonymous$$ecanim. perhaps @whydoidoit can confirm that? cheers all
Answer by greenshadow · Aug 18, 2013 at 07:24 AM
I thought I would provide a solution to this issue here, so that those who took the time to help me can see what I came up with, and so that others can possibly learn from it. I ended up utilizing the direction provided by @Fattie and @whydoidoit, combining the elegant use of the encapsulate function, and looking hard at the capabilities of the the AssetPostProcessor class to create a script which will scale an object to a maximum of 1 Unity unit on any axis upon importing.
On Preprocessing the import, the script first sets the FBX globalscale to 1. Then, in Postprocessing, the script calculates the ratio necessary to resize the model into Unity units, and the model is then scaled down in size, before being written to the disk. The benefit here is that the change is "semi-permanent", in that any instances of this model will contain the same scale. The script works great, and will scale models to exact size, without sacrificing the quality of animations which are added afterwards. Thanks again @Fattie and @whydoidoit:
using UnityEngine;
using System.Collections;
using UnityEditor;
class MeshPostprocessor : AssetPostprocessor {
float desiredSizeInUnits = 1.0f;
void OnPreprocessModel ()
{
ModelImporter importer = (ModelImporter)assetImporter;
importer.globalScale = 1f;
}
void OnPostprocessModel (GameObject g)
{
Bounds combinedBounds = new Bounds(g.transform.position, new Vector3(0, 0, 0));
Renderer[] renderers = g.GetComponentsInChildren<Renderer>();
foreach (Renderer r in renderers)
{
combinedBounds.Encapsulate(r.bounds);
}
float size = combinedBounds.size.x;
if (size < combinedBounds.size.y)
{
size = combinedBounds.size.y;
}
if (size < combinedBounds.size.z)
{
size = combinedBounds.size.z;
}
if (Mathf.Abs(desiredSizeInUnits - size) < 0.01f)
{
return;
}
float scale = desiredSizeInUnits / size;
g.transform.localScale *= scale;
}
}
Thanks for posting that - very helpful to others browsing later.
Your answer
Follow this Question
Related Questions
postion scale and rotation greyed out and not working 1 Answer
Calculating mesh over GameObject scale 1 Answer
I tried to make a box to select units like you do in windows 1 Answer
Positioning gameobjects by a corner, not by center 0 Answers
Why the guismo of the GameObject is at the center but its "mesh" is not at all in the center? 0 Answers