在Unity3D中更改FBX模型的中心點(Unity3D/3DMax)
當我們將模型匯入到Unity3D中時,經常會遇到模型的中心點與物體中心點相差甚遠的情況,如下圖所示:
這種情況通常會對我們的物體位置控制產生一些不利影響(當然這種設定也有其存在的好處……)
要解決類似問題,我們通常可以在Unity3D中進行設定。
1. 設定一個空物體作為我們進行修改的模型的父物體,設定其座標為(0,0,0),隨後將我們需要修改的子物體拖動到與父物體座標系原點相重合的位置這樣便可實現我們預期的目標。
2. 通過程式碼設定中心點
/// <summary>
/// 重置模型的中心點位置
/// </summary>
[MenuItem("Tool/ResetCenterPosition" )]
public static void ResetCenterPosition()
{
Transform transform = Selection.activeTransform;
Bounds bounds = new Bounds(Vector3.zero, Vector3.zero);
Vector3 center = Vector3.zero;
//獲取物體的Bound最終合成資訊
foreach (var item in transform.GetComponentsInChildren<MeshRenderer>())
{
bounds.Encapsulate (item.bounds);
}
center = bounds.center;
//新建空物體,將原來中心點有問題的物體放置到該物體下作為子物體存在
GameObject obj = new GameObject();
obj.name = transform.name;
obj.transform.position = center;
obj.transform.rotation = Quaternion.identity;
//獲取原物體在模型中的路徑
string selectedObjPath = "";
Transform currentSelectTransform = transform;
while (currentSelectTransform.parent != null)
{
selectedObjPath = currentSelectTransform.parent.name + "/" + selectedObjPath;
currentSelectTransform = currentSelectTransform.parent;
}
//設定空物體的層級,使之與原物體處於同一層級
obj.transform.SetParent(GameObject.Find(selectedObjPath).transform);
transform.SetParent(obj.transform);
}
該方法同樣通過計算當前物體及子物體的Bounds的大小和位置,新建一個空物體,將空物體的位置放置在模型Bounds的中心點中,將原來的物體設定為空物體的子物體來實現座標點的重置。該方法為單個物體進行重置,也可以通過修改程式碼,自動將整個模型中的所有物體進行重置,但是需要注意的是該種方法並沒有改變原始物體MeshFilter的中心點位置,如果使用者要對其MeshFilter進行操作,可能會有其他的情況發生。
如果需要對物體進行碰撞或者射線檢測,然後在進行位置的操作,請先確定操作的物體是空物體還是有網格資訊的物體。否則不會出現預期的效果。
3. 通過將FBX檔案重新匯入到3DMax中進行設定來完成對Pivot的重置,該方法可以從本質上實現對模型中心點的設定。
將模型匯入到3DMax中後,全選所有物體,選擇右側工具欄的層次->軸->僅影響軸->居中到物件。然後再將模型匯出即可。
4. 另一種方式可以通過重新計算MeshFilter的方式進行,該種方法暫時無法得到模型準確的中心點,需要藉助Bounds來計算,但是無法通過MeshFilter中所有的點的平均位置來計算,因此暫時無法對不規則物體進行中心點重置,這種方法僅供參考,可以在此基礎上深入研究。
[MenuItem("Tool/ResetCenterPositionWithMeshFilter")]
public static void ResetCenterPositionWithMeshFilter()
{
Transform transform = Selection.activeTransform;
//獲取物體的Bound最終合成資訊
foreach (var item in transform.GetComponentsInChildren<MeshFilter>())
{
Vector3[] testVector = item.mesh.vertices;
for (int i = 0; i < testVector.Length; i++)
{
testVector[i] += new Vector3(1, 1, 1);
}
item.mesh.vertices = testVector;
item.mesh.RecalculateBounds();
item.mesh.RecalculateNormals();
item.mesh.RecalculateTangents();
}
}