- Home /
How do I set the global scale of an object in a transform hierachy?
I've written a COLLADA importer that uses the element of the COLLADA file to define rotation, translation, and scale values for transforms. The values of the matrix are as follows:
xx,xy,xz,t1,yx,yy,yz,t2,zx,zy,zz,t3,0,0,0,1
Rotation and translation are working correctly by creating the coordinate basis from the x,y, and z axes, and taking the x,y, and z position values. The problem is that scale values, which are derived from the magnitude of the basis vectors represent scaling in the global coordinate system (not the local system as one would assume). This is a problem because after creating the transform, parenting it, and setting it's translation and rotation, the local system is rotated and setting transform.localScale (the only scale property available) applies the global scale values to the local system.
How do I set a transform's global scale in a transform hierarchy?
These are naive brute force approaches: Could you not just traverse the hierarchy and compute local scale relative to the parents? Even more simply, could you not store the parent, detach from it, scale and then re-attach to it?
Do you mean you're writing your own COLLADA-to-Unity importer? Why? Unity can import COLLADA files already...
It's part of my app that downloads 3D models and builds them in Unity at run-time. So I needed a script to parse COLLADA models. Also, my script reads extra information inside the COLLADA.
Answer by Alex 17 · Apr 18, 2011 at 10:30 AM
Maybe it will be helpful:
function GetParentScale(): Vector3 { var sf: Vector3 = Vector3.one;
var parentTransform: Transform = null;
if (thisTransform.parent) parentTransform = thisTransform.parent;
while (parentTransform) {
sf.x *= 1.0f / parentTransform.localScale.x;
sf.y *= 1.0f / parentTransform.localScale.y;
sf.z *= 1.0f / parentTransform.localScale.z;
if (parentTransform.parent) {
parentTransform = parentTransform.parent;
} else {
parentTransform = null;
}
}
return sf;
}
function SetScale(globalScale: Vector3) { var parentGlobalScale: Vector3 = GetParentScale(); thisTransform.localScale.x = globalScale.x parentGlobalScale.x; thisTransform.localScale.y = globalScale.y parentGlobalScale.y; thisTransform.localScale.z = globalScale.z * parentGlobalScale.z; }
where thisTransform = gameObject.transform
This is why .lossyScale
exists -- in most cases, if any of the parents is rotated, this function will return the wrong result.
Answer by ikeo · Sep 18, 2010 at 03:12 AM
It was much easier than I was making it out to be. The COLLADA matrices make complete sense if you decompose them and set the localPosition, localScale, and localRotation as follows:
Vector3 x = new Vector3((float)matrix[0], (float)matrix[4], (float)matrix[8]); Vector3 y = new Vector3((float)matrix[1], (float)matrix[5], (float)matrix[9]); Vector3 z = new Vector3((float)matrix[2], (float)matrix[6], (float)matrix[10]); float xScale = x.magnitude; float yScale = y.magnitude; float zScale = z.magnitude;
newParentTrans.localPosition = new Vector3((float)matrix[3] conversion, (float)matrix[7] conversion, (float)matrix[11] * conversion); newParentTrans.localScale = new Vector3(xScale, yScale, zScale);
Quaternion rotation = newParentTrans.rotation; rotation.SetLookRotation(z/zScale,y/yScale); newParentTrans.localRotation = rotation;
Because well-formed COLLADA files have one top-level element, you can rotate the entire scene by -90 deg around the x axis, if Z_UP is true.