3dmax导入unity问题(1) 轴角度座标

3dmax用FBX格式把模型导出并导入unity时需要注意的问题。

目录

二、轴心位置问题

2.1、一个物体

2.2、两个物体

2.3 分部分导出

三、角度问题

3.1、问题研究

3.2、解决方案操作

四、旋转操作

4.1、简单旋转情况

4.2、复杂旋转情况

4.3、不同视图创建的物体

4.4、小结

4.5、开门问题(研究过程,可以不用看,避免混乱)

4.5.1 (我的)创建门的过程:

4.5.2 【偏移:局部】

4.5.3 【偏移:世界】

4.5.4 开门结论

五、缩放操作

七、结论


3dmax和unity的座标单位

没有修改单位的情况下,默认m为单位。

放到Unity中,结果能够和Unity里面的(1,1,1)大小的Cube重合

把3dmax的单位改成mm,结果就是1000mm的立方体和Unity里面1个单位的立方体是重合的。

说明Unity里面的1个单位就是3dmax里面的1m。

二、轴心位置问题

上面的问题也算是轴心的角度问题,这里讨论轴心位置问题。

2.1、一个物体

创建一个小球,座标设置成(0,0,0)

导入unity中,结果,座标也是(0,0,0)。

修改物体座标,再次导入unity中,物体有个初始座标了,拖出来到Hierarchy里面,会有个座标在物体上,但是修改物体座标为(0,0,0),模型能够显示在unity的原点位置,这种情况问题不大。

大部分模型拿来放到unity中也不是用它自己的初始化位置,而是会给他一个位置(无论手动添加到场景中还是代码设置)。

-------------------------------------

接下来要修改轴的位置了。

在上面的基础上,在unity中,创建一个子物体,座标是(0,0,0),这个子物体的位置就和3dmax导入的模型重合在一起的。

3dmax中修改轴的位置,移动到物体外面。

导入uinty,能看到轴心在小球物体外面了,而且P5这个对象有座标。

这个座标到底是什么呢?

可以看到这个代表unity原点的点,在3dmax的小球的里面,小球的位置是在(0,0,0)没错的,但是P5这个对象的座标则是(0,0,-6)的。

假如把P5的座标设置为(0,0,0)的话,小球就不在(0,0,0)上了。

创建一个(0,0,0)相对座标的子物体,

子物体会出现在轴心位置

结论:一个物体,在unity里面的座标值指的是轴心的座标。

注意,其实在unity里面点击物体看到的座标轴不一定就是模型的轴心,这里是1个物体,情况简单。

多个物体时,Unity会自动算一个轴心显示的,一般是几个模型的中心,这个显示轴心不一定就是模型的轴心。而相对座标(0,0,0)的子物体则一定就是轴心的位置。

2.2、两个物体

导入unity中

在unity中看到的和3dmax中一样的。

假如我把Sphere001的座标从修改为(0,0,0),改成(0,10,0)。

导入unity中也是一样的

但是,这种情况其实是有问题的

用小球看不出来,假如我创建一个大楼。

随便建,不用考虑大楼在世界座标中的位置。

导入unity后

大楼就偏了。

为什么说偏了呢?因为轴心偏了。问题和前面一个物体是手动把轴心拖出来是一样的。

这里明明P6座标是(0,0,0),大楼就是不在(0,0,0),不在下面正方形(假设是广场)的中心。

这个大楼不是整个世界,是一个大场景中的一部分,比如一个广场上的某一座大楼。Unity中的整个场景不会是全部用一个max文件创建的,会有多个max文件,多个人员,创建一个世界中的不同部分,然后合并组织成一个完整的场景的。

比如大楼原本计划在unity场景的(0,0,0)的,上面的导出模型的情况下,根本没有方便的操作去把大楼模型放到(0,0,0)的,因为它的轴心在模型的外面。

3dmax导出的模型的轴心必须在模型的中心,才能在场景组织时和其他模型能配合起来。

如何操作:3dmax中创建包含全部模型的顶层组,并把该组座标设置为(0,0,0)。

unity中好使用了。

--------------------------------

这里其实还有的小问题,大楼跑到地下去了。

在3dmax中把组的轴心拖到地板中心

进入unity中,则模型P8,拖动出来就有个初始座标了(0,-3.4,0)。

把座标改成(0,0,0),则:

所以我们要求的模型轴心有两种:物体中心或者底面中心。

两种都可以,设备一般要求物体中心,大楼等建筑物体中心和地面中心都行,大楼等物体中心的情况下,代码上也是能统一处理的。

---------------------------------------------------------------------

其实这里就不是一定要把顶层组设置(0,0,0)了,和最前面的一个物体的情况一样。大不了有个初始座标,使用是设置一下座标就好了。

没有顶层组的情况下,3dmax导出的模型的轴心是原来3dmax中的世界座标的(0,0,0)的位置。有顶层组的情况下,顶层组作为一个物体考虑,模型的轴心就是组的轴心,一般也就是组下面的模型的中心。

--------------------------------------------------------------------------------------------------------

2.3 分部分导出

我们项目一般是一个园区建模,拿到的模型需要将园区的地形和建筑分别导出给我们,我们再在unity里面搭建成完整的场景。

对于这种整体和部分的情况下的位置问题在这里研究一下。

创建一个3dmax场景模拟一下。

【偏移:世界】旋转90度,导入unity

座标从3dmax里面的(100,200,300)变成了unity里面的(-100,300,-200),这个先不管。

接下来把各个部分单独导出。

有两种方式

1.选择子物体(分组)保存为max文件,打开max文件再导出fbx。

打开导出的文件,发现会多一个园区。

2.选择子物体(分组),导出子物体为fbx。

结果来看,两种方式都可以。看3dmax的分工合作方式。这块我还不了解,作为一个软件开发人员。(如果我来分配建模工作,首先位置以地形为主,先把地形建好,其他建筑正确摆放到地形上,再导出。)

要注意的是,因为前面导出fbx导出时先【“按递归方式打开”,选择全部物体,旋转轴】了,如果现在选择一个组,导出选定对象或者保存选定对象时,只会导出这个组,组里面的东西都没有。这个还挺不习惯的。

需要做的操作是先关闭组,再打开组,这样子选择的子物体(组)时,其实就是把子物体(组)里面的物体也都包括了。

//todo:其实按我设想,应该可以二次开发,做个自动将顶级组(如:园区)下面的一级子组(如:地形等)自动导出成fbx的工具。

-------------------------------------------------------

本来想说可能导出后部分的座标可能有问题,所以这部分放在这里。但拖到unity里面,能保持建筑在正确的位置上的。

不过能注意到,每个子物体多了一层。其实这点从前面的子物体的max文件也能看到的,明明选择导出的是地形,结果保存的max打开里面多了个园区。

正确操作是,这种情况下,不要顶级分组了,就只有各个部分的分组(这样也不要做前面提到的打开操作了,不过有”按递归方式打开“的话,还是要先关闭了)。

各个分组导选定对象,并导入unity。

三、角度问题

参考:【3dsmax】导入Unity3D需要注意的轴问题

3.1、问题研究

先创建一个Demo场景,能辨认出朝向的。

放入unity里面结果

模型对象角度是(0,0,0)的,子物体对象角度是(-90,0,0)的,不行。

需要注意的是,前面导出的高级设置轴转换,无论是Y向上还是Z向上结果是一样的。

------------------------------------------

加个顶级分组再导出

这种情况就变成模型对象(根对象)是(-90,0,0),子物体是(0,0,0)了。

多加几层分组也是一样的:

1.在没有顶级分组的情况下,导入Unity中,根物体的角度是(0,0,0),第一级子物体(或分组)的角度是(-90,0,0),后续子物体(或分组)的角度是(0,0,0)

2.在有顶级分组的情况下,根物体角度是(-90,0,0),下面的子物体角度都是(0,0,0)

3.2、解决方案操作

旋转轴:在3dmax中选中物体,切换到层次,仅影响轴。

在没有顶级分组情况下:

红色的轴是X轴,绿色的是Y轴,蓝色的是Z轴,默认是Z轴向上的。

进入旋转操作,注意要选中角度捕捉,设置90度。

旋转90°

注意,这时虽然看起来全选了,实际上选择就只有顶级的4个分组和物体,旋转的也是这4个的轴。导入Unity中,后上面的4个对于与第2级物体了,是(0,0,0)的,而第3级变成了(-90,0,0),4级则还是(0,0,0)了。

就算按ctr+a,或者全部框选,看起来像选中所有的物体,旋转所有物体的轴。

再导出FBX导入Unity,发现还是有些是(-90,0,0)。

正确操作是,先全选,然后选择按递归方式打开,然后再全选(这样才能选中全部物体),再旋转轴。

导出到Unity中后,所有的层级的物体都是(0,0,0)了。

---------------------------------------------------------------------------

在有顶级分组的情况下,假如旋转顶级分组本身的轴,导入Unity中则会是2级物体是(-90,0,0),其他都是(0,0,0)

正确操作还是和上面一样,要选择按递归方式打开,再旋转全部轴。

四、旋转操作

4.1、简单旋转情况

绕z轴(向上)旋转:

 

绕y轴旋转

旋转物体时,轴也是一起旋转的(这里有先把轴居中了)

在3dmax里面是沿着y轴旋转30度,到unity里面就变成了(-60,-90,90)。

假如这时按导出FBX要旋转轴90度的操作,因为按全面的教程操作是会把全部旋转的。但是有个问题,旋转的参考座标系,默认是世界,这时的旋转的圈和轴方向就不一致了。

沿着世界座标的x轴,旋转90度,结果在unity里面角度就是(0,-30,0)了。

把角度改成(0,0,0)的话,水平方向转了一下,垂直方向的角度还是斜的。

也就是说这时,这种倾斜的状态就是物体的原始角度(0,0,0)状态了。

参考座标系改为局部(只有这个座标系旋转控制的圈是和物体的轴方向一致的),沿局部座标x轴旋转90度,导出后坐标是(0,0,30)。

这时把角度改成(0,0,0)物体就回正了。

从逻辑上讲,这种状态更符合直观逻辑。

4.2、复杂旋转情况

沿y轴旋转10度

沿z轴旋转20度

沿x轴旋转30度

结果:

还是和上面一样的,“局部”座标系,旋转90度,导出fbx。到unity里面。

把Box001的角度调整为(0,0,0),就又回正了。

4.3、不同视图创建的物体

3dmax还有个问题,在不同视图下创建的物体的轴方向(“局部”座标系下)是不同的。

发现:

1.顶、前、左创建的物体,在对应视图下都是x轴向右,y轴向上,z轴向里。

2.正交和顶视图创建的物体的轴方向一致。

(成顶级组+局部轴旋转后)导出到unity里面,正交和顶角度是(0,0,0),前和左各有角度。

这里说明一下为什么要注意物体的角度,或者说是物体的轴的角度。

模型提供给unity后,不是静止的,在unity中会用脚本对物体进行操作,比如向某个方向移动,如向上移动。

假如角度不一致,用相同的脚本,实现的效果就会很怪。

public class Move : MonoBehaviour
{
    //private Vector3 speed=new Vector3(0,1,0);

    // Update is called once per frame
    void Update()
    {
        Vector3 speed = new Vector3(0, 1, 0);
        transform.Translate(speed);//正交和顶视图向上移动,前和左向左移动。
        //transform.localPosition += transform.up;//正交和顶视图向上移动,前和左向左移动。
        //transform.localPosition += speed;//全部物体朝上移动
    }
}

public class Rotate : MonoBehaviour
{
    void Update()
    {
        Vector3 speed = new Vector3(0, 1, 0);
        transform.Rotate(speed);//正交和顶视图一起旋转,前和左向一起旋转。
        //transform.localEulerAngles += transform.up;//正交和顶视图一起旋转,前和左向各自旋转。
        //transform.localEulerAngles += speed;//全部物体一起旋转
    }
}

对于前面这种简单方向移动的情况,在3dmax中把所有物体的轴改成(90,0,0),导入unity中,所有物体的轴方向就一致,都是(0,0,0)了。

注意这里的座标系是“世界”了,如果选局部的话,没个物体的绝对角度都是(0,0,0)了。

4.4、小结

参考:3dmax参考座标系怎么设置

发现我们建模人员没有改过参考座标系的设置,从头到尾都是用”视图“。视图一定程度上相当于”世界“了。

结合前面的,导出fbx,旋转轴有3种操作:

4.4.1、”世界“座标系,轴角度【绝对:世界】设置为(90,0,0)。

导入到unity后所有物体的角度就都是(0,0,0)。

4.4.2、"世界"座标系,轴角度【偏移:世界】设置为(90,0,0),这个和手动绕x轴旋转90度的操作是一样的。

导入unity后,物体的角度会发生变化,参考前面的【4.1】部分的情况。

4.4.3、“局部"座标系,x轴偏移旋转90度(或者手动绕x轴旋转90度),导入unity后,物体角度保存3dmax中的角度。

这种情况下的旋转轴90度操作只是为了消除3dmax导入unity造成的(-90,0,0)角度的偏移,物体本身还是有角度的。

参考前面的【4.1】部分的情况。

对于

 

4.5、开门问题(研究过程,可以不用看,避免混乱)

对于门这种模型,特别是双开门,两个门板在创建时会有可能用了对称的方式复制出来,这样的话,它们的轴也是对称的。

4.5.1 (我的)创建门的过程:

1.在透视视图创建一个长方体A。

2.修改长方体的轴,移动并对其到一边的中心。要开启轴约束

3.镜像一个长方体B,复制方式

4.将B和A对其

5.另外创建一个门框

6.创建其他东西,并分组

4.5.2 【偏移:局部】

采用【4.4.3】局部座标系偏移旋转90度的方式,结果很奇怪

旋转过程中,发现通过镜像方式创建出来的物体在[仅影响轴]的状态下跟着轴一起旋转了:

这个说实话,很奇怪,非常奇怪。

镜像自身,不复制,也是会变成旋转轴旋转物体。

 

我原本是想推荐“【偏移:局部】“的方式旋转的,因为通过【绝对:世界】方式设置轴角度,会导致在unity中所有的轴都是(0,0,0),那样的话门的轴就不对称了。具体看下面的4.5.2。

本来打算先不用镜像的操作,手动复制一个物体并旋转物体和轴的方式,使两个门的轴对称。

居然做不到!

这里的轴对称是指

用几何体方式镜像出来的物体不会出现旋转轴旋转问题的问题

问题是这样镜像出来的东西轴不对称,保存和原来的物体的轴一样的角度

4.5.3 【偏移:世界】

在4.5.1的过程创建的模型的基础上用"偏移:世界"([4.4.2])的方式旋转(90,0,0)度

旋转后

导入unity后DoorLeft是(0,0,0),DoorRight是(-180,0,0)

给Door1添加开门脚本

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class DoorOpen : MonoBehaviour
{
    public Vector3 speed = new Vector3(0, 1, 0);
    public Space space = Space.Self;
    public Transform Left;
    public Transform Right;
    void Start()
    {
        if (Left == null)
        {
            Left = transform.Find("DoorLeft");
            
        }
        if(Left)
        print("left:" + Left.up);

        if (Right == null)
        {
            Right = transform.Find("DoorRight");
        }
        if (Right)
            print("right:" + Right.up);
    }

    void Update()
    {
        
        //transform.Translate(transform.forward);
        if(Left)
            Left.Rotate(speed, space);
        if(Right)
            Right.Rotate(speed, space);//默认就是Space.Self

        //Left.Translate(speed,Space.World);
        //Right.Translate(speed, Space.World);
    }
}

speed是(0,1,0),其实也是旋转角度,space是Self。

效果:

再改一下,左侧相对完整的一个开门脚本

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class DoorOpen : MonoBehaviour
{
    public Vector3 speed = new Vector3(0, 1, 0);
    public Space space = Space.Self;
    public Transform Left;
    public Transform Right;
    public float angleMax = 90;
    void Start()
    {
        if (Left == null)
        {
            Left = transform.Find("DoorLeft");
            
        }
        if(Left)
        print("left:" + Left.up);

        if (Right == null)
        {
            Right = transform.Find("DoorRight");
        }
        if (Right)
            print("right:" + Right.up);
    }

    private int direction = 1;

    public bool loop = true;

    public bool isMove = true;

    public Vector3 currentAngle;

    void Update()
    {
        if (isMove == false) return;
        currentAngle += speed * direction;//因为左边是0->90,右边是180->90;需要另外记录一下旋转角度
        if (Left)
        {
            Left.Rotate(speed * direction, space);
        }
        if (Right)
        {
            Right.Rotate(speed * direction, space); //默认就是Space.Self
        }
        if (currentAngle.y > angleMax || currentAngle.y < 0)
        {
            if (loop)
            {
                direction *= -1; //旋转一下角度
            }
            else
            {
                isMove = false;//停止运行
            }
        }
    }
}

效果:

4.5.4 开门结论

用【偏移:世界】方式旋转轴导出的门模型,可以用脚本方便的制作开门动画。有些建模人员可能从来就没操作过局部视图,导出前的旋转使用默认的”视图“参考座标系就好了。

五、缩放操作

对于缩放操作,简单的一个物体,缩放为200%,导出到unity里面后就是(2,2,2)了

之所以需要导出给unity的模型不要有缩放比例,即Scale要为(1,1,1),是因为在Unity里面会对模型进行一下操作。

虽然我们在计算一个物体的大小时是有考虑Scale参数的,但是还有其他子物体的操作情况,总之,设置为(1,1,1)是最保险的。

现在的问题是在3dmax里面有缩放需求的情况下,如何导入unity后Scale为(1,1,1)。

1.附加

附加到一个没有缩放的物体上。

物体A比例是200%,物体B比例是100%。

选择物体B,转换成可编辑多边形,点击附加,选中物体A,结果A就不见了,合并到物体B里面了。

同时物体B的轴、比例都不变,合并后的物体以B为准,A的200%的缩放也就不存在了。

附加后物体A就不存在的,对于需要操作物体A的情况来说,可能不大方便。

因为最终实际的模型是A,B只是为了消除缩放的影响,B物体可以是一个半径为0的球,且居中到物体A的中心,通过对齐方式。

2.加组

给有缩放的一个或者相关的多个物体加上组,结果组上面的缩放则是100%。

物体上的缩放是不变,不过这种情况下一般也就操作组,物体仅仅是作为一个子部件存在了。

3.缩放子元素

通过转换成可编辑多边形,选中所有点,缩放点的方向来改变物体的大小。

修改点后物体的比例还是100%的。

发现,简单的整体模型,Box,无论用点线面缩放都行的。

但是需要注意的是像茶壶这种的有多个部分组成的模型,如果不是用点缩放,用线、面等缩放,各个部分会独立缩放,导致整体就怪怪的了。

而用点缩放,则结果正常。

旋转操作也可以通过这几种方式消除对角度的影响

七、结论

1.Unity里面的1个单位就是3dmax里面的1m。

2.max文件导出前文件中必须有一个顶层组,有且只有一个。

3.必须选择“按递归方式打开”,再旋转“全部”模型的轴的角度,旋转成Y轴(绿色)向上,注意这时的参考座标系为视图或者世界(默认就是视图的)。

4.整个园区的各个部分的导出时不需要顶级组,只需要选中各个部分,并导出选中物体就行(参考前面2.3)。

    备注:老版本(2012)的3dmax没有“按递归方式打开”,则必须升级max版本,因为人工打开的话,很容易出错,工作量也大。

 

鉴于导出fbx给unity前需要做这些操作,而后续可能还需要在原来基础上编辑修改模型。可以在改完模型的分组,建立顶级分组后,旋转轴之前,另存为一个专门用于导出fbx的max文件。在该max文件中做修改并导出为FBX文件,导出后这个文件就没用了。修改模型还是原来的文件,每次导出fbx都要再做一次旋转轴操作。

不将旋转轴的操作放到另一个max文件中的话,可能会导致轴混乱,比如,在旋转好轴的模型的基础上,再添加其他模型,新的模型的轴和前面的模型的方向就不一致了。下次导出fbx时必须人工区分开来两种轴的物体。

//todo:这些操作(组、递归打开、旋转轴、导出选定对象)用二次开发方式自动实现

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章