3dmax用FBX格式把模型導出並導入unity時需要注意的問題。
目錄
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。
三、角度問題
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:這些操作(組、遞歸打開、旋轉軸、導出選定對象)用二次開發方式自動實現