分享

【新提醒】【再次认识我们熟悉的Transform之位移】

 鸿蛟家平 2018-02-07
 本帖最后由 RaymondChan 于 2018-2-6 21:15 编辑

注:本文属于基础系列,高手可以略过哦

1. 写在前面

你有没有过类似这样子的疑惑?
1.明明我只拖动了一个物体z轴,为何检视面板上其余两个轴的值也发生变化了?检视面板上显示的不就是本地坐标嘛,总不会是世界坐标?那也不对呀!
2.使用transform.localPosition移动一个物体,我们只是想让一个物体往它的z轴方向移动,为何实际运行时却不是,而是不知道往哪个方向移动了,这是什么鬼?

如果你已经想明白这些疑惑,那么请设想以下情形:
新建一个Cube,将其Rotation的Y值改为300,为其添加脚本,在Update中分别执行以下语句时,先想一想各自会怎么移动?然后对比一下后面的结果(可以注意下上方的Global与Local的切换)。如果你依然有疑惑,我觉得咱们可以继续往下看。
1 transform.Translate(Vector3.forward* Time.deltaTime);
2 transform.Translate(transform.forward * Time.deltaTime);
3 transform.position += Vector3.forward * Time.deltaTime;
4 transform.localPosition += Vector3.forward * Time.deltaTime;
5 transform.position += transform.forward * Time.deltaTime;
6 transform.localPosition+= transform.forward * Time.deltaTime;
7 Vector3 objVector3=transform.InverseTransformDirection(Vector3.forward);
transform.Translate(objVector3*Time.deltaTime);

实际结果如下:
1   transform.Translate(Vector3.forward * Time.deltaTime);


2  transform.Translate(transform.forward * Time.deltaTime);



3  transform.position += Vector3.forward * Time.deltaTime;



4 transform.localPosition += Vector3.forward * Time.deltaTime;



5 transform.position += transform.forward * Time.deltaTime;



6  transform.localPosition += transform.forward * Time.deltaTime;



7  Vector3 objVector3=transform.InverseTransformDirection(Vector3.forward);
    transform.Translate(objVector3*Time.deltaTime);





2. Unity坐标系基础


如果对上面的内容有疑惑,我们可能先需要重新了解一下Unity的坐标系。在Unity中常用的坐标系有全局坐标系、局部坐标系、相机坐标系、屏幕坐标系,我们今天主要涉及的是全局坐标系与局部坐标系。

全局坐标系
全局坐标系是用来描述游戏场景内所有物体位置和方向的基准,我们一般也叫它世界坐标系。在Unity场景中创建的物体都是以全局坐标系中的坐标原点来确定各自位置的。所以,全局坐标系是基准,我们可以使用世界坐标来保存一个物体的确切位置。

局部坐标系      
每个物体都有其独立的物体坐标系,并且随物体进行相同的移动或者旋转,也可以叫做模型坐标系或物体坐标系。模型Mesh保存的顶点坐标均为局部坐标系下的坐标。Unity工具栏上的Global/Local按钮可以切换显示全局坐标系和局部坐标系。这里要注意了,当切换到Local的时候,显示的是物体自身的坐标系,是自身的坐标系,是自身的坐标系,是自身的坐标系,重要的事多说几遍。

3. Transform中容易混淆的几个问题

transform.position与transform.localPostion(rotation同理)
transform.position 是物体的世界坐标,也就是相对世界坐标系原点的位置;
transform.localPosition 这个大家一般理解为本地坐标,而一般问题也就出在“本地”这两个字的理解上,这个“本地”不是物体的自身的坐标系(这个local不是工具栏上Global/Local中的Local),而是指父物体的坐标系,当没有父物体时,就是世界坐标系,换句话说如果这个物体有父物体,那么localPosition就是该物体的相对父物体的自身坐标系原点的位置,如果没有父物体,那么localPosition就会等于position。
给大家画个图方便大家理解一下。为了便于观察,我们使用二维坐标系来演示,如下图,A物体的position为(2,3),B物体的position为(5,4),如果A物体是B物体的父物体,那么B物体的localPosition就是以A点为原点的相对坐标(5-2,4-3)即(3,1)




vector3.forward与transform.forward(up、right同理)
vector3.forward 这个值大家看到forward很容易将它与世界坐标联系起来,但它就只是一个三维向量,forward只是一个记法而已,官方表述是shorthand,它的值永远都是(0, 0, 1),与世界坐标没有任何关系,你将它用在世界坐标(position)里,它就代表着世界坐标的(0,0,1),你将它用在本地坐标上(localPosition),那么它就代表着本地坐标中的(0,0,1),这一点要记住,否则很容易搞错;
transform.forward 这也是一个三维向量,方向是该物体的自身坐标系的z轴方向,长度是世界坐标系中的1,由于这个向量的方向是该物体自身z轴方向,所以这个三维向量的值是会变化的,是基于世界坐标系计算得到的值。

Transform在检视面板上的显示的值



这里的Position是localPosition的值,是在父物体的坐标系下的值,也就是相对父物体原点的位置。这与工具栏上的Local是不一样的。所以才会出现直接拖拽物体的z轴,而检视面板中不一定是z的值在变化。

Translate是指定坐标系的
public void Translate(Vector3 translation, Space relativeTo = Space.Self);
public void Translate(Vector3 translation, Transform relativeTo);
Translate方法具有多个重载方法,当我们不指定坐标系时,默认是按自身坐标系进行位移,我们也可以指定为世界坐标系,当然也可以指定为其他任意物体自身的坐标系。所以当我们使用默认坐标系时,要记住这是物体自身的坐标系。



4. 对1中7种移动的分析

1transform.Translate(Vector3.forward* Time.deltaTime);
Translate方法具有多个重载方法,可以指定坐标系,当只给出一个三维向量参数时,默认按自身的局部坐标系移动,所以虽然是Vector3.forward即(0,0,1),但是在自身坐标系中表示就是此时物体的transform.forward,因此我们看到的是物体沿着自身坐标系的z轴移动
2transform.Translate(transform.forward * Time.deltaTime);
由于物体已经经过旋转了,局部坐标系也发生了旋转,而transform.forward是基于世界坐标系的表示,因此此时仍然按transform.forward移动的话,实际上是相当于世界中两倍的transform.forward与Vector3.forward的夹角上移动(。。。有点没说清楚,但是这种移动一般不需要,是错误的)
3transform.position += Vector3.forward * Time.deltaTime;
transform.position的值是物体在全局坐标系中的位置,因此在这个位置上加上(0, 0, 1)也就是按全局坐标系的z轴移动
4transform.localPosition += Vector3.forward * Time.deltaTime;
transform.localPosition的值是物体在父物体的局部坐标系中的位置点,而这个局部坐标系的原点就是父物体的位置,在这里没有父物体,所以localPosition所使用的坐标系等同于全局坐标系,所以也是按全局坐标系的z轴移动
5transform.position += transform.forward * Time.deltaTime;
虽然transform.forward表示的是物体自身的z轴方向,但它是基于世界坐标系表示的,所以与position是匹配的,因此是沿着物体自身的z轴移动
6transform.localPosition+= transform.forward * Time.deltaTime;
由于没有父物体,效果同5
7Vector3 objVector3=transform.InverseTransformDirection(Vector3.forward);
transform.Translate(objVector3*Time.deltaTime);
这里先将全局坐标系的(0,0,1)三维向量转换为局部坐标系的三维向量,然后再使用Translate让其按照局部坐标系进行移动,效果就相当于沿着全局坐标系的z轴移动了。

5. 再次思考


我们加点改变,在上述的Cube下新建一个子物体cube,与父物体拉开一段距离,进行一点任意旋转,只对子物体同样执行以上语句,子物体cube都会怎么移动?
这里我就不再赘述啦,大家可以自己尝试哦。如果这个依然可以想明白,那么到这里基本上就OK啦。




6. 小结


带着大家回顾了下Unity中的全局坐标系与局部坐标系,分析了几种容易混淆的问题以及几种移动的方式,希望可以给大家带来一点帮助。

工程文件(Unity 2017.3.0f3):
链接:https://pan.baidu.com/s/1bqiT9FL 密码:xd11




    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多