Max09在模型到處的模型和U3D場景的尺寸不一致,Max09中的1m導到U3D中,只有0.01m,這時可以在U3D中將模型的FbxImporter中將Scale Factor改為1。
上述事情也可以通過腳本直接處理:
using UnityEditor;
using UnityEngine;
using System.Collections;
public class FBXSeting : AssetPostprocessor
{
void OnPreprocessModel()
{
ModelImporter modelImporter = (ModelImporter)assetImporter;
if(assetImporter.assetPath.Contains(".fbx"))
{
modelImporter.globalScale = 1.0f;
modelImporter.generateMaterials = ModelImporterGenerateMaterials.None;
}
}
}
U3D有自動生成材質的功能(FbxImporter/Materials Generation,有3個選項可選),但我推薦使用腳本統一處理所有模型的材質。下面的代碼拋磚引玉,通過菜單修改模型材質的顏色:
using UnityEditor;
using UnityEngine;
using System.Collections;
public class MaterialGeneration
{
[MenuItem("Actor/Generate Material")]
static void Execute()
{
foreach (Object o in Selection.GetFiltered(typeof(Object), SelectionMode.DeepAssets))
{
if (!(o is GameObject)) continue;
if (o.name.Contains("@")) continue;
//if (!AssetDatabase.GetAssetPath(o).Contains("/characters/")) continue;
GameObject charFbx = (GameObject)o;
foreach (SkinnedMeshRenderer smr in charFbx.GetComponentsInChildren<SkinnedMeshRenderer>(true))
{
smr.material.color = Color.red;
}
}
}
}
上面是處理人物材質的蒙皮網格的材質,對於場景模型,則改為修改MeshRenderer的數據。思路大致如此,細節以此類推。
根據本人自己的經驗,將modelImporter.generateMaterials設為PerMaterial(支持多重材質),然后批處理Fbx模型的Mesh,找到其材質,並修改之(包括修改Shader及Shader數據)。不建議刪除現有材質,然后自己創建材質,並賦予給相應的Mesh,因為這種做法有個不好的地方:U3D重啟后,材質關聯丟失。而前面的方法,只是修改Mesh所關聯材質的數據,后者是修改關聯。
思緒:
U3D雖然降低了游戲編程門檻,不過定制功能真心強大,繼續探索中......
有些地方需要手動創建Prefab,可以通過以下代碼實現代碼批處理創建:
Object tempPrefab = EditorUtility.CreateEmptyPrefab("Assets/" + name + ".prefab");
tempPrefab = EditorUtility.ReplacePrefab(go, tempPrefab);
通過腳本給模型prefab添加AnimationEvent:
using UnityEditor; using UnityEngine; using System.IO; using System.Collections; using System.Collections.Generic; public class AnimationEventBatch { [MenuItem("Animation/AnimationEvent Batch")] static void Execute() { List<string> lstAnimName = new List<string>(); foreach (Object o in Selection.GetFiltered(typeof(Object), SelectionMode.DeepAssets)) { if (!(o is GameObject)) continue; if (o.name.Contains("@")) continue; if (o.name.Contains("anim") || o.name.Contains("ANIM")) continue; if (o.name.Contains("meta")) continue; GameObject charFbx = (GameObject)o; AnimationClip[] clips = AnimationUtility.GetAnimationClips(charFbx.animation); foreach(AnimationClip clip in clips) { if(clip.name.Contains("Take 0")) continue; List<AnimationEvent> events = new List<AnimationEvent>(AnimationUtility.GetAnimationEvents(clip)); if(HasStartEvent(events) && HasEndEvent(events)) continue; if(!HasStartEvent(events)) { AnimationEvent startEvent = new AnimationEvent(); startEvent.time = 0.0005f; startEvent.functionName = "StartCallBack"; events.Add(startEvent); } if(!HasEndEvent(events)) { AnimationEvent endEvent = new AnimationEvent(); endEvent.time = clip.length - 0.0005f; endEvent.functionName = "EndCallBack"; events.Add(endEvent); } AnimationUtility.SetAnimationEvents(clip, events.ToArray()); } EditorUtility.DisplayDialog("fbxname", clips[0].name, "OK"); } } static bool HasStartEvent(List<AnimationEvent> events) { foreach(AnimationEvent eventElem in events) { if(eventElem.functionName == "StartCallBack") return true; } return false; } static bool HasEndEvent(List<AnimationEvent> events) { foreach(AnimationEvent eventElem in events) { if(eventElem.functionName == "EndCallBack") return true; } return false; } }
上述代碼僅供參考,代碼中有幾個注意事項:
(1)一定要在現有AnimationEvent[]數組的基礎上添加,而不是新建一個這樣的數組,然后Set給對應的AnimationClip,這樣會導致現有的關鍵幀事件丟失;
(2)要避免重復添加同意關鍵幀事件(貌似u3d對於同樣時間同樣函數名的關鍵幀只會添加一次);
(3)可以看到,在添加關鍵幀事件時,只需要給出函數的名字,那么,在此動作執行時,U3D會檢查這個GameObject身上的所有組件腳本,如果組件A包含此名字的函數,則會執行此函數。並且所有組件的此名字的函數都會執行一次。
批量設置圖片的格式:
public class GuideUITextureProcess { [MenuItem("Editor/Texture/GuideUITexture")] static void Execute() { foreach (Object o in Selection.GetFiltered(typeof(Object), SelectionMode.DeepAssets)) { if (!(o is Texture)) continue; Texture tex = o as Texture; string path = AssetDatabase.GetAssetPath(tex); TextureImporter textureImporter = AssetImporter.GetAtPath(path) as TextureImporter; textureImporter.textureType = TextureImporterType.GUI; AssetDatabase.ImportAsset(path); } AssetDatabase.Refresh(); } }
Prefab.Apply操作的回調:
using UnityEngine; using UnityEditor; [InitializeOnLoad] public class PrefabExtension : MonoBehaviour { static PrefabExtension() { UnityEditor.PrefabUtility.prefabInstanceUpdated += OnPrefabInstanceUpdate; } static void OnPrefabInstanceUpdate(GameObject instance) { UnityEngine.Debug.Log("[Callback] Prefab.Apply on instance named :" + instance.name); GameObject prefab = UnityEditor.PrefabUtility.GetPrefabParent(instance) as GameObject; string prefabPath = AssetDatabase.GetAssetPath(prefab); UnityEngine.Debug.Log("@Prefab originPath=" + prefabPath); } }
繼續探索中......
