查看: 1824|回复: 1
打印 上一主题 下一主题

Unity3D 烘焙材质到单一贴图的脚本

[复制链接]

2508

主题

2

听众

3万

积分

资深设计师

Rank: 7Rank: 7Rank: 7

纳金币
32806
精华
12

最佳新人 活跃会员 热心会员 灌水之王 突出贡献

跳转到指定楼层
楼主
发表于 2012-4-12 15:15:22 |只看该作者 |倒序浏览
这个脚本由 CocoaChina 版主 “四角钱” 分享,可以将复杂的材质(比如有法线贴图的材质)进行"烘焙",转变为单一的贴图。可用来将 Unity 的游戏移植到移动平台时候使用。请将脚本放 Editor 文件夹里,使用时选择一个 Material 材质,然后在菜单种"Custom/Bake Material"打开并调整照明和其他参数,点击Bake按钮就会生成一个单一的贴图。

class BakeMaterialSettings

{

    private static var kEditorPrefsName = "BakeMaterialSettings";

   

    static var kBakingLayerShouldBeUnusedInScene = 30;

    static var kStandardTexNames = new Array ("_MainTex", "_BumpMap", "_Detail", "_ParallaxMap", "_Parallax");



    var bakeAlpha = false;

    var bakeMainTexAsWhite = false;

    var minTextureResolution = 8;

    var maxTextureResolution = 2048;



    var emptyScene = false;

    var useCustomLights = false;

    var ambient = Color.black;

   

    static var kLights = 3;

    var enableLight = new boolean[kLights];

    var colorLight = new Color[kLights];

    var dirLight = new Vector2[kLights];

   

    function BakeMaterialSettings ()

    {

        Load ();

    }

   

    function Load ()

    {

        bakeAlpha = EditorPrefs.GetBool(kEditorPrefsName + ".bakeAlpha");

        bakeMainTexAsWhite = EditorPrefs.GetBool(kEditorPrefsName + ".bakeMainTexAsWhite");

        minTextureResolution = EditorPrefs.GetInt(kEditorPrefsName + ".minTextureResolution", 8);

        maxTextureResolution = EditorPrefs.GetInt(kEditorPrefsName + ".maxTextureResolution", 2048);



        emptyScene = EditorPrefs.GetBool(kEditorPrefsName + ".emptyScene");

        useCustomLights = EditorPrefs.GetBool(kEditorPrefsName + ".useCustomLights");

        ambient.r = EditorPrefs.GetFloat(kEditorPrefsName + ".ambient.r");

        ambient.g = EditorPrefs.GetFloat(kEditorPrefsName + ".ambient.g");

        ambient.b = EditorPrefs.GetFloat(kEditorPrefsName + ".ambient.b");

        ambient.a = EditorPrefs.GetFloat(kEditorPrefsName + ".ambient.a", 1.0f);

        

        for (var q = 0; q < kLights; ++q)

        {

            enableLight[q] = EditorPrefs.GetBool(kEditorPrefsName + ".enableLight" + q);

            colorLight[q].r = EditorPrefs.GetFloat(kEditorPrefsName + ".color.r" + q, 0.5f);

            colorLight[q].g = EditorPrefs.GetFloat(kEditorPrefsName + ".color.g" + q, 0.5f);

            colorLight[q].b = EditorPrefs.GetFloat(kEditorPrefsName + ".color.b" + q, 0.5f);

            colorLight[q].a = EditorPrefs.GetFloat(kEditorPrefsName + ".color.a" + q, 1.0f);

            dirLight[q].x = EditorPrefs.GetFloat(kEditorPrefsName + ".dir.x" + q);

            dirLight[q].y = EditorPrefs.GetFloat(kEditorPrefsName + ".dir.y" + q);

        }

    }

   

    function Save ()

    {

        EditorPrefs.SetBool(kEditorPrefsName + ".bakeAlpha", bakeAlpha);

        EditorPrefs.SetBool(kEditorPrefsName + ".bakeMainTexAsWhite", bakeMainTexAsWhite);

        EditorPrefs.SetInt(kEditorPrefsName + ".minTextureResolution", minTextureResolution);

        EditorPrefs.SetInt(kEditorPrefsName + ".maxTextureResolution", maxTextureResolution);



        EditorPrefs.GetBool(kEditorPrefsName + ".emptyScene", emptyScene);

        EditorPrefs.SetBool(kEditorPrefsName + ".useCustomLights", useCustomLights);

        EditorPrefs.SetFloat(kEditorPrefsName + ".ambient.r", ambient.r);

        EditorPrefs.SetFloat(kEditorPrefsName + ".ambient.g", ambient.g);

        EditorPrefs.SetFloat(kEditorPrefsName + ".ambient.b", ambient.b);

        EditorPrefs.SetFloat(kEditorPrefsName + ".ambient.a", ambient.a);



        for (var q = 0; q < kLights; ++q)

        {

            EditorPrefs.SetBool(kEditorPrefsName + ".enableLight" + q, enableLight[q]);

            EditorPrefs.SetFloat(kEditorPrefsName + ".color.r" + q, colorLight[q].r);

            EditorPrefs.SetFloat(kEditorPrefsName + ".color.g" + q, colorLight[q].g);

            EditorPrefs.SetFloat(kEditorPrefsName + ".color.b" + q, colorLight[q].b);

            EditorPrefs.SetFloat(kEditorPrefsName + ".color.a" + q, colorLight[q].a);

            EditorPrefs.SetFloat(kEditorPrefsName + ".dir.x" + q, dirLight[q].x);

            EditorPrefs.SetFloat(kEditorPrefsName + ".dir.y" + q, dirLight[q].y);

        }

    }

}



class BakeMaterial extends EditorWindow

{

    private static var kMateriBakeNodeName = "__MateriaBakeSetup";

    private static var kWindowMinSize = Vector2 (300, 386);

   

    private static var settings : BakeMaterialSettings;

    private static var visible : boolean = false;

   

    private var camera : GameObject;

    private var plane : GameObject;

    private var previewTexture : Texture;

    private var lights : GameObject[] = new GameObject[BakeMaterialSettings.kLights];

    private var stateChanged = false;

   

    private var texViewScrollPosition = Vector2.zero;

    private var lastMaterial : Material;

   

    private var originalScene = "";

   

    private var scheduleBakeOnNextUpdate = false;



   

    private function Setupscene ()

    {

        DestroyScene ();

        var oldGo = GameObject.Find(kMateriBakeNodeName);

        if (oldGo)

            DestroyImmediate (oldGo);

        camera = new GameObject (kMateriBakeNodeName, Camera);

        plane = GameObject.CreatePrimitive (PrimitiveType.Plane);



        var cam = camera;

        cam.camera.backgroundColor = Color.black;

        cam.camera.clearFlags = CameraClearFlags.SolidColor;

        cam.camera.orthographic = true;

        cam.camera.orthographicSize = 5.0;

        cam.camera.cullingMask = 1 << settings.kBakingLayerShouldBeUnusedInScene;

        

        plane.transform.parent = cam.transform;

        plane.transform.position = Vector3.forward * 10.0;

        plane.transform.rotation = Quaternion.Euler (0, 0, 180) * Quaternion.Euler (-90, 0, 0);

        plane.layer = settings.kBakingLayerShouldBeUnusedInScene;

        

        for (var l in lights)

        {

            l = new GameObject ("Light", Light);

            l.light.type = LightType.Directional;

            l.light.cullingMask = 1 << settings.kBakingLayerShouldBeUnusedInScene;

            l.transform.parent = cam.transform;

            l.active = false;

        }

    }

   

    private function UpdateScene (m : Material)

    {

        for (q = 0; q < settings.kLights; ++q)

        {

            lights[q].active = settings.useCustomLights & settings.enableLight[q];

            lights[q].light.color = settings.colorLight[q];

            lights[q].transform.rotation =

                Quaternion.AngleAxis(settings.dirLight[q].x, Vector3.up) *

                Quaternion.AngleAxis(settings.dirLight[q].y, Vector3.right);

        }

        

        if (settings.useCustomLights)

            RenderSettings.ambientLight = settings.ambient;

        else if (settings.emptyScene)

            RenderSettings.ambientLight = Color.white;

            

        plane.renderer.material = m;

    }

        

    private function DestroyScene ()

    {

        GameObject.DestroyImmediate (camera);

        GameObject.DestroyImmediate (plane);

        GameObject.DestroyImmediate (previewTexture);

    }



    function UpdateMaterialPreview (m : Material) : RenderTexture

    {

        if (!m)

            return;

        

        var saveAmbientLight = RenderSettings.ambientLight;

        var saveMainTexture = m.mainTexture;

        if (settings.bakeMainTexAsWhite)

            m.mainTexture = null;

   

        

        // setup

        if (!camera)

            SetupScene ();

        camera.SetActiveRecursively(true);

        UpdateScene (m);

        

        var res = FindLargestTextureResolution (plane.renderer.sharedMaterial, settings.minTextureResolution, settings.maxTextureResolution);

        var rt = RenderCameraToRenderTexture (camera.camera, res.x, res.y);

        

        // restore

        camera.SetActiveRecursively(false);

        RenderSettings.ambientLight = saveAmbientLight;

        m.mainTexture = saveMainTexture;

        

        previewTexture = rt;

        return rt;

    }

   

    function CaptureMaterial(m : Material)

    {

        var matAssetPath = AssetDatabase.GetAssetPath (m);

        var assetPath = System.IO.Path.Combine (System.IO.Path.GetDirectoryName (matAssetPath), System.IO.Path.GetFileNameWithoutExtension (matAssetPath));



        var rt = UpdateMaterialPreview (m);

        RenderTextureToPNG (rt, settings.bakeAlpha, assetPath + ".png");

    }



    function OnEnable ()

    {

        if (!settings)

            settings = new BakeMaterialSettings ();

        SetupScene ();

        visible = true;

    }

   

    function OnDisable ()

    {

        DestroyScene ();

        settings.Save ();

        visible = false;

    }



    static function GetTargetMaterial () : Material

    {

        return EditorUtility.InstanceIDToObject (Selection.activeInstanceID) as Material;

    }



    function OnSelectionChange ()

    {

        Repaint ();

    }



    function Update ()

    {

        var rebuildScene = false;

        if (scheduleBakeOnNextUpdate)

        {

            Bake ();

            scheduleBakeOnNextUpdate = false;

            rebuildScene = true;

        }

        

        if (originalScene == "" && EditorApplication.currentScene == "")

            settings.emptyScene = true;

            

        if (settings.emptyScene && originalScene == "" && EditorApplication.currentScene != "")

        {

            DestroyScene ();

            if (EditorApplication.SaveCurrentSceneIfUserWantsTo ())

            {

                originalScene = EditorApplication.currentScene;

                EditorApplication.NewScene ();

            }

            else

                settings.emptyScene = false;

            rebuildScene = true;            

        }

        else if (!settings.emptyScene && originalScene != "")

        {

            EditorApplication.OpenScene (originalScene);

            rebuildScene = true;

            originalScene = "";

        }

        

        if (rebuildScene)

        {

            SetupScene ();

        }

        

        if (rebuildScene || stateChanged || !settings.emptyScene)

        {

            UpdateMaterialPreview (lastMaterial);

            Repaint ();

            stateChanged = false;

        }

    }

   

    function OnGUI ()

    {

        var material = GetTargetMaterial ();

        if (lastMaterial != material)

            UpdateMaterialPreview (material);

        if (material)

            lastMaterial = material;

        

        EditorGUILayout.BeginHorizontal();

            EditorGUILayout.BeginVertical(GUILayout.MaxWidth(200));

                if (!(originalScene == "" && EditorApplication.currentScene == ""))

                {

                    settings.emptyScene = !EditorGUILayout.BeginToggleGroup("Scene ligthing", !settings.emptyScene);

                    EditorGUILayout.EndToggleGroup();

                }

                settings.useCustomLights = EditorGUILayout.BeginToggleGroup("Custom lighting", settings.useCustomLights);

                if (settings.useCustomLights)

                {

                    EditorGUI.indentLevel = 1;

                    settings.ambient = EditorGUILayout.ColorField("Ambient", settings.ambient);

                    for (var q = 0; q < settings.kLights; ++q)

                    {

                        settings.enableLight[q] = EditorGUILayout.BeginToggleGroup("Light", settings.enableLight[q]);

                        EditorGUI.indentLevel = 2;

                            settings.colorLight[q] = EditorGUILayout.ColorField("Color", settings.colorLight[q]);

                            settings.dirLight[q] = EditorGUILayout.Vector2Field("Direction", settings.dirLight[q]);

                        EditorGUILayout.EndToggleGroup();

                    }

                }

                EditorGUI.indentLevel = 0;

                EditorGUILayout.EndToggleGroup();

               

                settings.bakeAlpha = EditorGUILayout.Toggle("Bake Alpha", settings.bakeAlpha);

                settings.bakeMainTexAsWhite = !EditorGUILayout.Toggle("MainTex", !settings.bakeMainTexAsWhite);

                settings.minTextureResolution = EditorGUILayout.IntField("Min Resolution", settings.minTextureResolution);

                settings.maxTextureResolution = EditorGUILayout.IntField("Max Resolution", settings.maxTextureResolution);

                settings.minTextureResolution = Mathf.Max(2, settings.minTextureResolution);

                settings.maxTextureResolution = Mathf.Max(settings.minTextureResolution, settings.maxTextureResolution);



                EditorGUILayout.BeginHorizontal();

                if (GUILayout.Button("Bake"))

                {

                    CaptureMaterial (lastMaterial);

                }

                if (GUILayout.Button("Bake Selected"))

                {

                    scheduleBakeOnNextUpdate = true;

                }

                EditorGUILayout.EndHorizontal();

               

            EditorGUILayout.EndVertical();

            

            texViewScrollPosition = EditorGUILayout.BeginScrollView (texViewScrollPosition);

                var r = GUILayoutUtility.GetAspectRect(1.0f);

                if (previewTexture)

                    EditorGUI.DrawPreviewTexture(r, previewTexture);

            EditorGUILayout.EndScrollView();        

        EditorGUILayout.EndHorizontal();

        

        if (GUI.changed)

        {

            stateChanged = true;

        }

    }

   

    @MenuItem("Custom/Bake Material ...", false, 5)

    static function CreateBakeEditor()

    {

        var window = EditorWindow.GetWindow(BakeMaterial);

        window.title = "Bake Material";

        window.minSize = kWindowMinSize;

        window.Show();

    }



    @MenuItem("Custom/Bake Selected Materials", false, 4)

    static function Bake()

    {

        var instanceIDs = Selection.instanceIDs;

        var currentScene = EditorApplication.currentScene;

   

        var wasAlreadyVisible = BakeMaterial.visible;

        var window = EditorWindow.GetWindow(BakeMaterial);

        

        if (window.settings.emptyScene)

        {

            if (!EditorApplication.SaveCurrentSceneIfUserWantsTo ())

                return;

            EditorApplication.NewScene ();

        }

        

        window.SetupScene ();

        for (var i in instanceIDs)

        {

            var m : Material = EditorUtility.InstanceIDToObject (i) as Material;

            if (m)

                window.CaptureMaterial (m);

        }

        window.DestroyScene ();

        

        if (window.settings.emptyScene && currentScene)

        {

            EditorApplication.OpenScene (currentScene);

        }

        

        if (!wasAlreadyVisible)

            window.Close ();

    }

   

    static function FindLargestTextureResolution (m : Material, minTexRes : int, maxTexRes : int) : Vector2

    {

        var res = Vector2 (minTexRes, minTexRes);

        for (var n in BakeMaterialSettings.kStandardTexNames)

        {

            if (!m.HasProperty (n))

                continue;

        

            var t : Texture = m.GetTexture (n);

            if (!t)

                continue;

            

            res.x = Mathf.Max (res.x, t.width);

            res.y = Mathf.Max (res.y, t.height);

        }

        res.x = Mathf.Min (res.x, maxTexRes);

        res.y = Mathf.Min (res.y, maxTexRes);

        return res;

    }

   

    static function RenderCameraToRenderTexture (cam : Camera, width : int, height : int) : RenderTexture

    {

        var rt = cam.camera.targetTexture;

        if (rt && rt.width != width && rt.height != height)

            DestroyImmediate(rt);

        if (!rt)

            rt = new RenderTexture (width, height, 24);

        cam.camera.targetTexture = rt;

        cam.camera.Render ();

        return rt;

    }

   

    static function RenderTextureToPNG (rt : RenderTexture, bakeAlpha : boolean, assetPath : String)

    {

        RenderTexture.active = rt;

        

        var screenShot = new Texture2D (rt.width, rt.height, bakeAlpha? TextureFormat.ARGB32 : TextureFormat.RGB24, false);

        screenShot.ReadPixels (Rect (0, 0, rt.width, rt.height), 0, 0);

        

        RenderTexture.active = null;

        

        var bytes = screenShot.EncodeToPNG ();

        System.IO.File.WriteAllBytes (assetPath, bytes);

        

        AssetDatabase.ImportAsset (assetPath, ImportAssetOptions.ForceUpdate);

    }

}
分享到: QQ好友和群QQ好友和群 腾讯微博腾讯微博 腾讯朋友腾讯朋友 微信微信
转播转播0 分享淘帖0 收藏收藏0 支持支持0 反对反对0
回复

使用道具 举报

5472

主题

6

听众

1万

积分

版主

Rank: 7Rank: 7Rank: 7

纳金币
76544
精华
23

活跃会员 荣誉管理 突出贡献 优秀版主 论坛元老

沙发
发表于 2012-4-12 15:51:20 |只看该作者
厉害呀
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

手机版|纳金网 ( 闽ICP备2021016425号-2/3

GMT+8, 2025-4-20 08:30 , Processed in 0.068068 second(s), 28 queries .

Powered by Discuz!-创意设计 X2.5

© 2008-2019 Narkii Inc.

回顶部