Unity3D批处理脚本

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);
    }
}

 


继续探索中......



posted @ 2012-02-29 17:16  斯芬克斯  阅读(8298)  评论(0编辑  收藏  举报