欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Unity中Scale详解

程序员文章站 2024-03-22 12:30:16
...

1.缩放变换
Scale代表的是缩放。 
通常意义下的缩放变换,指的是利用缩放矩阵和物体的齐次坐标相乘而进行变换,缩放矩阵形如:

 
Scalex代表x轴方向的缩放 
Scaley代表y轴方向的缩放 
Scalez代表z轴方向的缩放 
当它与物体的齐次坐标相乘后,可以得到缩放后的物体坐标 
 
可以发现缩放矩阵将物体原本的坐标依据缩放比例进行了变换。 
这是几何上的缩放变换,那么在Unity中,缩放变换又是一种什么样的作用呢。

2.Unity中的缩放变换
在Unity中,对于导入的模型以及unity中自带的那些Object(例如 Cube 、Sphere…)是不能直接改变其本身属性坐标的大小的,只有通过缩放变换来改变其自身坐标系的大小来使其大小发生改变。也就是如果物体正常的长度为2,如果你本体坐标系的缩放为2,那么物体实际看到的长度就变为了4,但是这个物体在它本体坐标系下的长度仍然为2。在Unity中,Scale的变化你可以看做是对物体的本体坐标系进行的缩放变化,在这个缩放过程中,物体在其本体坐标系下的各项属性保持不变。 
 
 
如图这是一个Cube改变Scale之前的状态,接下来我们在Z轴对它进行缩放 
 
 
可以发现这个cube在z轴上的长度变为了原来的二倍,而它自身的坐标并未发生改变。

在unity中的物体的transform里,表示缩放的一共有两个量,lossyScale和localScale。

Localscale代表的是当前物体相对于父物体的缩放,既可以作为左值也可以作为右值。

Lossyscale代表的是当前物体在全局中的缩放,为只读变量,不可修改。

Inspector界面显示的scale表示的是localScale。

3.注意
在Unity中关于Scale容易出问题的地方就在于当物体之间包含父子关系时,如果父物体的Scale改变,会导致子物体的世界坐标(即transform.position)发生改变。(注意,inspector中的position为与父物体的相对坐标)

假定在父物体的Scale为(1,1,1)的情况下,父物体的世界坐标为(x1,y1,z1),子物体的世界坐标为(x2,y2,z2)。当父物体的Scale发生改变变为(1,1,2)时,父物体的世界坐标不发生改变,而子物体的世界坐标将变为(x1,y1,z1+(z2-z1)*2)。子物体的世界坐标发生这种改变的目的,是为了保证其相对于父物体本体坐标系的相对坐标的不变性。

演示一下
令Ojbect1为父物体,object2为obj1的子物体,object3为obj2的子物体 
如果在初始情况下object1的坐标为(0,0,-2),object2的坐标为(0,0,1.5),object3的坐标为(0,0,4) 
接下来改变三个物体的localScale。 
Object1的localScale为(1,1,1.5) object2的localScale为(1,1,2) object3的localScale为(1,1,3) 
改变过后,三者的lossyScale变为(1,1,1.5),(1,1,3),(1,1,9)。 
Obj1的position为(0,0,-2),obj2的坐标为(0,0,3.25),obj3的坐标为(0,0,10.75)。

改变前后三个物体的localPosition均未发生改变。

接下来解释obj2和obj3的坐标变化是如何得来的。 
3.25= -2+(1.5-(-2))*1.5 
10.75=[-2+ (1.5-(-2))*1.5]+(4-1.5)*3 
即子物体的当前世界坐标等于父物体的世界坐标加上子物体相对于父物体的相对坐标乘以父物体的lossyScale对应的值。

public class ObstacleCollect : MonoBehaviour
{
    void Awake()
    {
        BoxCollider[] boxColliders = GetComponentsInChildren<BoxCollider>();
        for (int i = 0; i < boxColliders.Length; i++)
        {
            float minX = boxColliders[i].transform.position.x -
                         boxColliders[i].size.x*boxColliders[i].transform.lossyScale.x*0.5f;
            float minZ = boxColliders[i].transform.position.z -
                         boxColliders[i].size.z*boxColliders[i].transform.lossyScale.z*0.5f;
            float maxX = boxColliders[i].transform.position.x +
                         boxColliders[i].size.x*boxColliders[i].transform.lossyScale.x*0.5f;
            float maxZ = boxColliders[i].transform.position.z +
                         boxColliders[i].size.z*boxColliders[i].transform.lossyScale.z*0.5f;
            Debug.Log(i+ "position  " + boxColliders[i].transform.position.x);
            Debug.Log(i + " size " + boxColliders[i].size.x);
            Debug.Log(i + " lossyScaleX " + boxColliders[i].transform.lossyScale.x);
            Debug.Log(i + "minX  " + minX);
            Debug.Log(i + "maxX  " + maxX);
            Debug.Log(i + "position  " + boxColliders[i].transform.position.z);
            Debug.Log(i + " size " + boxColliders[i].size.z);
            Debug.Log(i + " lossyScaleZ " + boxColliders[i].transform.lossyScale.z);
            Debug.Log(i + "minZ  " + minZ);
            Debug.Log(i + "maxZ  " + maxZ);
 
            //Debug.Log(boxColliders[i].transform.position.x);
 
 
            IList<Vector2> obstacle = new List<Vector2>();
            obstacle.Add(new Vector2(maxX, maxZ));
            obstacle.Add(new Vector2(minX, maxZ));
            obstacle.Add(new Vector2(minX, minZ));
            obstacle.Add(new Vector2(maxX, minZ));
            Simulator.Instance.addObstacle(obstacle);
        }
    }
 
    // Update is called once per frame
    void Update()
    {
    }
}

Unity中Scale详解