如何设置GameObject父对象且不改变子对象的缩放比例
解决Unity中SetParent导致子物体缩放/旋转失真的问题
问题根源
当父物体存在非均匀缩放(x/y/z缩放数值不一致)+ 旋转时,父物体的变换矩阵会产生剪切变换。子物体的局部变换会与这个带剪切的矩阵相乘,导致子物体顶点被扭曲,最终表现为网格失真。你之前用空物体当中间层的思路是对的,但没处理好空物体和子物体的变换同步,才会在父物体旋转时出问题。
正确解决方案:用中间空物体隔离变换
创建一个空物体作为“变换隔离层”,承接父物体的变换,同时让子物体只继承该空物体的“干净”局部变换(无缩放、无旋转、无偏移),具体代码如下:
// 1. 记录子物体当前的世界变换状态(位置、旋转、缩放) Vector3 originalWorldPos = childObject.transform.position; Quaternion originalWorldRot = childObject.transform.rotation; Vector3 originalWorldScale = childObject.transform.lossyScale; // 2. 创建中间空物体并设置父节点 var transformWrapper = new GameObject("ChildTransformWrapper"); transformWrapper.transform.SetParent(parentObject.transform); // 3. 重置空物体的局部变换,确保它只继承父物体的世界变换,自身无额外偏移/旋转/缩放 transformWrapper.transform.localPosition = Vector3.zero; transformWrapper.transform.localRotation = Quaternion.identity; transformWrapper.transform.localScale = Vector3.one; // 4. 将子物体挂载到空物体下,并还原其世界变换状态 childObject.transform.SetParent(transformWrapper.transform); childObject.transform.position = originalWorldPos; childObject.transform.rotation = originalWorldRot; // 计算子物体相对于空物体的局部缩放(抵消空物体继承的父物体缩放) childObject.transform.localScale = Vector3.Scale(originalWorldScale, new Vector3(1/transformWrapper.transform.lossyScale.x, 1/transformWrapper.transform.lossyScale.y, 1/transformWrapper.transform.lossyScale.z));
为什么这样有效?
- 空物体的局部变换是完全“干净”的(缩放1、旋转0、偏移0),它会继承父物体的世界变换,但不会向子物体传递父物体的非均匀缩放和旋转带来的剪切矩阵。
- 还原子物体的世界变换后,Unity会自动计算子物体相对于空物体的局部变换,避免了父物体变换对其产生的扭曲。
额外提示
- 如果你不需要子物体随父物体的缩放/旋转变化,直接把空物体的
localScale和localRotation锁死为(1,1,1)和无旋转即可。 - 避免在父物体上使用非均匀缩放,这是Unity中很多变换问题的根源,如果必须用,尽量用这种中间层隔离的方式。
内容的提问来源于stack exchange,提问作者Aeneator
相关产品推荐
相关产品推荐

