在Unity3D中,transform的lossyScale这个属性使用情况并不多,因此很多人对其没什么了解,笔者最近在做和Unity3D有关的服务器工作,需要了解其来源,因此对其做了一点研究。
在Unity3D的官方文档里,是这样介绍lossyScale的:
然而,这样的介绍,对实现该属性并无多大意义,当然,为什么要实现该属性,因为Unity3D中的基本碰撞体是使用lossyScale伸缩的,以保证基本碰撞体不变形,如下图所示:
Box的RenderMesh已经变形成平行四面体,但BoxCollider仍然是长方体,至于为什么BoxCollider不能变形成平行四面体,是受制于其物理引擎PhysicX未提供平行四面体。
该限制只限于基本碰撞体,对于MeshCollider(无论是否是凸包)则不存在这一限制,如下图所示:
好了,扯了这么多,无非是想说lossyScale还是有点用的,计算该值是有必要的,那么如何通过层级Transform的localPosition, localRotation和localScale来计算lossyScale呢?
回到基本的矩阵变换,我们有:
如果知道M, T和R,我们就能得到代表伸缩的S矩阵:
伸缩矩阵S和lossyScale到底有什么关系呢,通过实验发现lossyScale是伸缩矩阵对角线元素,我们构建了一个两层的GameObject:
随便设置下GameObject和Cube的transform:
计算lossyScale并对比的代码如下图所示:
结果如下图所示:
很明显的可以看到,lossyScale就是变换矩阵M的S矩阵的对角线元素。
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()
{
}
}