`

复杂材质烘焙成一张贴图

 
阅读更多
这个脚本可以将复杂的材质,比如有法线贴图的材质进行"烘焙",转变为单一的贴图,可用来将



将这个脚本放Editor文件夹里,使用时选择一个Material材质,然后在菜单种"Custom/Bake Material"打开并调整照明和其他参数,点击Bake按钮,就会生成一个单一的贴图.

脚本:BakeMaterial.js

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);
    }
}
  • 大小: 658.1 KB
分享到:
评论

相关推荐

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

    【烘焙材质到单一贴图的脚本2】是Unity3D中的一个自定义脚本,主要功能是将具有复杂纹理和光照信息的材质简化为一张单一的贴图,以适应移动平台等资源有限的环境。这个过程通常被称为“烘焙”(Baking),它将原本...

    烘焙到材质脚本2

    《烘焙到材质脚本2》是针对Unity3D游戏开发中的一个重要工具,它主要用于优化复杂的材质,特别是包含法线贴图的材质。在Unity中,法线贴图用于模拟物体表面的微小细节,增加真实感,但这些复杂的计算会消耗大量资源...

    Unity3d使用烘焙贴图

    通过烘焙,可以将复杂的光照效果(如环境光遮蔽、阴影等)转化为简单的纹理贴图,从而减少实时计算量,提高游戏运行效率。 #### 二、Unity3d烘焙贴图工作流程 1. **UVW贴图处理**: - 完成模型的UVW贴图制作,...

    Unity3d 烘焙到材质 脚本 BakeMaterial.js

    在Unity中,“烘焙到材质”的技术主要用于处理那些包含高级光照效果(如法线贴图)的复杂材质。通过将这些复杂材质烘焙成一张或几张单一的纹理贴图,可以极大地减少实时渲染的计算量,这对于性能有限的移动设备来说...

    Unity动态加载烘焙好的光照贴图

    在Unity引擎中,光照贴图烘焙(Lightmap Baking)是一种优化光照计算的方法,它可以将复杂的光照信息预先计算并存储到贴图中,以便在运行时以较低的性能成本渲染场景。然而,当游戏场景中存在大量预制体(Prefab)且...

    u3d5.x 动态添加烘焙贴图

    在Unity引擎中,烘焙贴图(Baked Lightmaps)是一种优化光照处理的技术,它将静态光照信息预先计算并存储在纹理中,以减少运行时的计算负担。在Unity5.x版本中,开发者可以实现动态添加烘焙贴图的功能,这对于那些...

    5.x unity 烘焙贴图代码

    在Unity中,烘焙贴图将光照信息编码到纹理中,这些纹理随后被应用到游戏对象的材质上,使得在运行时无需进行复杂的实时光照计算。这一过程包括光照数据的捕捉、转换和存储,通常包括光照贴图(Lightmaps)和阴影贴图...

    Unity3D烘焙灯光贴图后,阴影及法线的问题与解决方法1

    在Unity3D游戏开发中,灯光烘焙是一种优化技术,它能够预先计算光照信息并存储到贴图中,从而减轻运行时的计算负担。然而,在实际应用中,烘焙灯光贴图可能会遇到一些问题,如阴影丢失或法线效果不正确。本文将详细...

    u3d贴图烘焙

    - **多材质烘焙**:当一个模型包含多种材质时,可以使用不同的UV通道来烘焙不同的材质。这样可以更好地利用UV空间,提高贴图的分辨率。 - **纹理翻耕**:对于复杂场景,可以通过多次烘焙和合并纹理的方式来优化最终...

    maya中烘焙AO

    5. **统一材质类型**:所有模型的材质球应设置为Lambert 1,这是Maya的基本漫反射材质,适合烘焙。 烘焙Normal Map(法线贴图)的步骤如下: 1. 在Maya的Rendering选项卡中,展开Lighting/Shading,选择Transfer ...

    Unity 烘焙教程 for 3dsMax

    Unity烘焙教程 for 3dsMax 本教程主要讲述了如何在Unity中导入和使用烘焙贴图,从3dsMax中...本教程提供了详细的指导,帮助用户快速掌握Unity中的烘焙贴图和Lightmapped 材料的使用,并提高模型的现实感和材质效果。

    Unity自带LightMapping和3Ds Max烘焙贴图的小对比1

    在虚拟现实和游戏开发中,烘焙贴图是一种常见的优化光照效果的技术,它允许开发者在有限的硬件资源下实现接近真实光照的表现...同时,烘焙过程中的等待时间也是一个重要因素,复杂的模型可能需要较长时间才能完成烘焙。

    UE4动画烘焙器-ue4.27

    动画烘焙是将复杂的动画逻辑和计算转换为预烘焙的数据,以便在游戏中实时播放时减少CPU负担。这包括将骨骼动画、蒙皮权重、IK(反向动力学)解决方案等预先计算并存储,使得在游戏运行时可以快速读取和播放,提高...

    高模烘焙的低模加贴图的石头文件FBX

    它能存储包括几何数据、材质、纹理、骨骼动画等多种信息,方便在不同软件之间交换模型数据。在这个模型中,FBX文件包含了低模的几何信息,可以导入到各种3D软件或游戏引擎中进行进一步处理或展示。 2048的贴图文件...

    20210705-中信建投-立高食品-300973-冷冻烘焙先发优势形成,尽享烘焙市场成长红利.pdf

    冷冻烘焙行业作为现代食品工业的一个分支,近年来在中国市场展现出强劲的成长动力和发展潜力。立高食品作为冷冻烘焙领域的先行者之一,在该行业中占据了有利的市场地位。以下将从多个方面详细解读冷冻烘焙行业的相关...

    模型材质网格烘焙合并优化工具插件:Super Combiner 1.6.6

    因为优化对于游戏至关重要,特别是那些针对移动设备(甚至更多在 VR 中)的游戏,Super Combiner 将烘焙材质和网格,充分利用静态和动态批处理。 绝对非破坏性工作流程(源资产保持绝对完整) 非常容易使用且优化的...

    i烘焙商业计划书.pdf

    i烘焙商业计划书.pdfi烘焙商业计划书.pdfi烘焙商业计划书.pdfi烘焙商业计划书.pdfi烘焙商业计划书.pdfi烘焙商业计划书.pdfi烘焙商业计划书.pdfi烘焙商业计划书.pdfi烘焙商业计划书.pdfi烘焙商业计划书.pdfi烘焙商业...

    Blender插件-快速烘焙PBR贴图材质 Bakemaster Full V1.0

    它使用原生的 Blender 烘焙操作符来烘焙基于 PBR 的贴图、默认的 Blender Cycles 贴图和特殊蒙版贴图。该插件发出并推进了 Blender 的烘焙过程,使其成为适用于任何场景设置的强大、功能齐全的一站式解决方案。...

    Unity3D教程:关于LightMapping和NavMesh烘焙的动态加载2

    首先,LightMapping是Unity3D的一种光照预计算技术,它将复杂的光照计算结果烘焙到场景中的物体表面,从而在运行时减少GPU的负载。烘焙过程包括计算全局光照、阴影和环境光等,并存储在纹理中。通常,LightMapping是...

Global site tag (gtag.js) - Google Analytics