2017-08-25 00:23:57 biezhihua 阅读数 4290

3D坐标系是3D游戏开发的基础概念。一般3D软件都是采用笛卡尔坐标系来描述物体的坐标信息。笛卡尔坐标系分为左手坐标系和右手坐标系:

  • 左手坐标系是Y轴指向上方,X轴指向右方,Z轴指向前方。
  • 右手坐标系是Y轴指向上方,X轴指向右方,Z轴指向后方。

这里写图片描述

在Unity中使用的是左手坐标系,其中X轴代表水平方向,Y轴代表垂直方向,而Z轴代表深度。

Unity有如下几种坐标系统。

1,全局坐标系(world coordinate system)

全局坐标系是用于描述场景内所有物体位置和方向的基准,也称为世界坐标系(也就是上面提到的笛卡尔左手坐标系)。

在Unity场景中创建的物体都是以全局坐标系中的坐标原点(0,0,0)来确定各自的位置。

2,局部坐标系(local coordinate system)

每个物体都有其独立的物体坐标系,并且随物体进行相同的移动或旋转,也称为模型坐标系或物体坐标系。

通过点击工具栏中的GlobalLocal,可以清楚的看到物体的局部坐标系与全局坐标系的不同。

如果一个物体有父物体,那么父子之间的坐标系是相互关联的,此时子物体会以父物体作为自身局部坐标系的坐标原点。

3,相机坐标系

以摄像机视角出发,观察物体的位置和方向建立的坐标系。使用此坐标系可以方便的判断物体是否在相机前方以及物体之间的先后遮挡顺序。

4,屏幕坐标系

建立在屏幕上的二维坐标系,用来描述像素在屏幕上的位置。

说道3D坐标系就必须提到Transform,Transform表示一个物体的位置、旋转、缩放等信息。

1,位置(position/localPosition)

先阐述两个最基本的概念:

  • transform.position:表示该物体在全局坐标中的位置信息。
  • transform.localPosition:表示该物体相对于父物体的位置信息。

最普通的方法Transform.Translate,可以将自身在某个方向上移动某段距离,方向(direction)和距离(distance)由第一个参数(translation)指定。于是我们可以看到如下的代码:

public class ExampleClass : MonoBehaviour {
    void Update() {
        // 将自身(局部坐标系)在前方(Z轴)移动(1*一帧的持续时间)的距离
        transform.Translate(Vector3.forward * Time.deltaTime);
    }
}

Translate方法还有第二个参数Space可供选择,Space表示使用的坐标空间(全局、局部),于是就会有如下代码:

public class ExampleClass : MonoBehaviour {
    void Update() {
        // 将自身(全局坐标系)在上方(Y轴)移动(1*一帧的持续时间)的距离
        transform.Translate(Vector3.up * Time.deltaTime, Space.World);
    }
}

该段代码与段代码最重要的不同在于,前者应用Translate到局部坐标系,而后者应用Translate到全局坐标系,源码可以清晰的表现出这段关系:

/// <summary>
///   <para>Moves the transform in the direction and distance of translation.</para>
/// </summary>
/// <param name="translation"></param>
/// <param name="relativeTo"></param>
public void Translate(Vector3 translation, [DefaultValue("Space.Self")] Space relativeTo)
{
  if (relativeTo == Space.World)
    this.position += translation;
  else
    this.position += this.TransformDirection(translation);
}

// 如果没有第二个参数或参数为Space.Self,那么先将`translation`由局部坐标系转为全局坐标系,再与自身`position`相加。
// 如果第二个参数为Space.World,那么直接与自身`position`相加。

在Unity中,Transform组件的Transform.TransformPoint方法可以将坐标点从局部坐标系转换到全局坐标系,Transform.InverseTransformPoint可以将坐标点从全局坐标系转换到局部坐标系。而Transform.TransformDirectionTransform.InverseTransformDirection则用于对向量在局部坐标系和全局坐标系之间进行转换。

根据上述,下面两段代码效果是相同的:

// 先将方向从全局坐标系转换到局部坐标系,再通过Translate内部调用TransformDirection方法将方向从局部坐标系转换为全局坐标系,最后加到自身的position上。
Vector3 up = transform.InverseTransformDirection(Vector3.up);
transform.Translate(up * Time.deltaTime, Space.Self);

// 直接将translation加到自身的position上。
transform.Translate(Vector3.up * Time.deltaTime, Space.World);

Transform源码在这里

2,旋转(rotate/localRotate)

由于和位置很类似就不赘述了。

2016-12-03 23:46:04 q529560107 阅读数 331

Unity3D使用的是左手坐标系,即伸出左手,让拇指和食指成“L”形,大拇指向右,食指向上。其余的手指指向前方。这样就建立了一个左手坐标系。拇指、食指和其余手指分别代表X,Y,Z轴的正方向。

1.世界坐标系:Unity3D中所有的Gameobjet在视图中都是以世界坐标显示在场景中(左手坐标系,3d空间),由transform.position可以获得该位置坐标。

2.屏幕坐标系:以像素定义的,以屏幕左下角为(0,0)点,右上角(Screen.width,Screen.height),Z的位置以相机的世界单位来衡量,实际上将一个空间3d的坐标转换到2d平面的一个坐标。(鼠标和手指触摸都属于屏幕坐标)

3.ViewPort Space(视口坐标):视口坐标是标准的和相对于相机的。相机的左下角为(0,0)点,右上角为(1,1)点,Z的位置是以相机的世界单位来衡量的。

【坐标系的转换】

1、世界坐标→屏幕坐标:Camera.WorldToScreenPoint(transform.position);

2、屏幕坐标→世界坐标:Camera.ScreenToWorldPoint(transform.position);

3、屏幕坐标→视口坐标:Camera.ScreenToViewportPoint(Input.GetTouch(0).position);

4、视口坐标→屏幕坐标:Camera.ViewportToScreenPoint();

5、视口坐标→世界坐标:Camera.ViewportToWorldPoint();

其中Camera为场景中的Camera对象。


InverseTransformPoint: 绝对坐标转相对坐标,也就是世界坐标转你想要放到的父节点下的相对坐标,

TransformPoint: 相对坐标转绝对坐标,也就是你想要放到的父节点下的相对坐标转成世界坐标,



我们经常在Inspect窗口查看的position是本地坐标LocalPostion(没有父节点的Gameobject除外,它的本地坐标与世界坐标相等),本地坐标系就是相当于父节点的坐标位置。

注意:坐标系中计算坐标位置是以pivot轴点的位置计算的。

2018-03-03 12:15:50 laiyizhou 阅读数 1151

坐标系,是一位叫笛卡尔的人提出的。

而后面提及的左手坐标系右手坐标系中,在数学定义上,便使用了向量的一种运算,这种运算也是以笛卡尔命名,叫笛卡尔积

在Unity3D中,坐标系至少存在如下三种:世界坐标系屏幕坐标系视口坐标系

(当然,在世界坐标系中的坐标叫世界坐标屏幕坐标视口坐标 定义同理,不再赘述。)

其一,世界坐标

世界坐标,是Unity3D里面每一个场景(Scene)默认的,是一个独立的初始化空间。

所以,假如一个物体的世界坐标是(0, -10, 0),可以被视为是一个“绝对坐标”。其中,虽然可以通过移动窗口或者F键的方式把该物体移到视觉中间,但(0, -10, 0)还是(0, -10, 0),不会改变,只不过看起来在视觉中间了。

——怎么获取呢?

——使用gameObject.transform.postion,这个值获取到的就是该物体的世界坐标。

当然,在tranform下,还有一个是localPosition

localPositionposition 的区别就在于:前者是相对父物体的相对世界坐标;后者是在初始化空间里的绝对世界坐标;当然,如果一个物体没有父物体,则二者等效

其中,在Unity3D的Inspector面板中,显示的便是每一个物体的localPosition 数值。



举个例子:ParentGameObject 没有父物体,而ParentGameObject 的世界坐标是 (0, -10, 0),其下的ChildGameObject 相对世界坐标是(0, 10, 0);于是,按照上述说法:

对于ParentGameObject而言:

ParentGameObject.tranform.position = (0, -10, 0);

同时,它没有父物体,localPosition与position等价,所以,ParentGameObject.tranform.localPosition = (0, -10, 0);

对于ChildGameObject而言:

ChildGameObject.tranform.localPosition = (0, 10, 0) 自然不用多说;

重要的是,此时,ChildGameObject.tranform.position 应该等于(0, 0, 0)。

(注:在Unity3D里面,(0, 0, 0) 用Vector3.Zero表示即可。)

——接下来的问题是:这个默认的世界坐标系是采用左手坐标系还是右手坐标系?

——答案是:左手坐标系


此外,再插一个题外话:InverseTransformVectorTransformPoint

上述二者,实现localPositionpostion 的互相转化

比如:

#1 : 求A物体下相对世界坐标为(10, 10, 10)的物体,其绝对世界坐标是多少?

A.tranform.TransformPoint(new Vector3(10, 10, 10));

#2 : 求绝对世界坐标为(20, -20, 20)的物体,相对于A物体的相对世界坐标是多少?

A.tranform.InverseTransformVector(new Vector3(20, -20, 20));

其二,屏幕坐标

屏幕坐标,是在Unity3D里面 Game视图下的坐标,此时,屏幕大小也需要纳入考虑。

其中,以左下角为起点(0,0),右上角为终点(Screen.width,Screen.height)


但是,请注意:千万不要以为屏幕坐标是一个二维坐标!屏幕坐标,也是一个三维坐标!

——那么,z轴坐标值怎么算?

——根据Camera的位置来算。

比如,Camera的世界坐标是(0, 0, -10),那么屏幕坐标中任何一点的z轴坐标值都是10(当然,x轴、y轴坐标值另当别论);换句话说,屏幕坐标的z轴坐标值就是camera位置的z值的相反数

于是,根据上述所说,屏幕坐标跟两个因素有关:屏幕大小和Camera的世界坐标。所以,举个例子:Camera的世界坐标是(0, 0, -10),屏幕大小为800x600,那么,屏幕里中间点的屏幕坐标是多少?是(400, 600, 10)。


当然,在Unity3D中不需要人为计算,使用方法WorldToScreenPoint() 即可把一个物体的世界坐标转换成屏幕坐标Camera.main.WorldToScreenPoint(GameObject.tranform.position);

其三,视口坐标

关于,视口坐标,其实一句话便可以讲清楚:视口坐标是标准化后的屏幕坐标。

也就是说,它和屏幕坐标的属性是一样的。只不过其范围是,左下角为起点(0,0),右上角为终点(1, 1)。其余,与屏幕坐标同理。

比如:Camera的世界坐标是(0, 0, -10),屏幕大小为800x600,那么,屏幕里中间点的视口坐标是多少?是(0.5, 0.5, 10)。

当然,在Unity3D中也不需要人为计算,使用方法WorldToViewportPoint() 即可把一个物体的世界坐标转换成视口坐标Camera.main.WorldToViewportPoint(GameObject.tranform.position);

总结:相互转换

  1. 同样是世界坐标

    相对世界坐标转绝对世界坐标:TransformPoint();

    绝对世界坐标转相对世界坐标:InverseTransformVector();

  2. 世界坐标转换为屏幕坐标:Camera.main.WorldToScreenPoint();

  3. 屏幕坐标转换为世界坐标:Camera.main.ScreenToWorldPoint();

  4. 世界坐标转换为视口坐标::Camera.main.WorldToViewportPoint();

  5. 视口坐标转换为世界坐标:Camera.main.ViewportToWorldPoint();

  6. 视口坐标转换为屏幕坐标:Camera.main.ViewportToScreenPoint();

  7. 屏幕坐标转换为视口坐标:Camera.main.ScreenToViewportPoint();

2014-01-03 19:40:17 wlj613613 阅读数 10544

问题      

   3ds Max直接导出的FBX导入到Unity3D里,会发现x轴旋转度为-90,如下图所示:



解答

     这是因为3ds Max采用的是右手坐标系统,Unity则是左手坐标系统。接下来将演示告诉你如果修正这一问题。


1.随便新建个茶壶模型。



2.选择层次——仅影响轴



3.选中工具栏里面的 选择并旋转 按钮



4.将底部坐标栏中的X改为90



5.可以发现我们的轴方向变成如图所示一样了



6.导出,并在高级选项中将 轴转化 中的向上轴 改为 Y-up


7.这样资源的旋转度在Unity里面就完全归零啦



Unity3D之坐标变化

阅读数 616

Unity3D坐标转换

阅读数 225

unity3d 的 坐标系统

阅读数 159

没有更多推荐了,返回首页