Unity中对预制体烘焙光照贴图,在其他Scene中使用或者动态生成带光照贴图的预制体

这篇具有很好参考价值的文章主要介绍了Unity中对预制体烘焙光照贴图,在其他Scene中使用或者动态生成带光照贴图的预制体。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

记录个人开发笔记,如果有大佬有更好的方法或者觉得我这个方法哪里有问题欢迎指正!

首先说下为什么会弄预制体烘焙光照贴图,因为项目需求需要动态生成一个房间的,因此是将房间弄成预制体,动态生成就好了,这个很简单,但是呢最后程序是在一体机中跑的,性能比较差,所有美术调好的效果后如果是实时光,性能开销就比较大,烘焙呢又因为不需要一开始显示而且必须在同一个scene中所有才去弄了这么个烘焙预制体光照贴图。(既然是预制体烘焙,因此此方法也可以跨工程使用,所有有时候美术调效果时可以直接只烘焙一个预制体给到开发人员,不用再给开发人员整个场景了)

接下来直接说怎么操作:

先简单的搭建了一个Plane和Cube再打了一个点光源 

unity烘焙光照贴图,unity教程,unity,贴图,游戏引擎

接下去,我们再需要烘焙的预制体的最外层父节点上挂上一个PrefabLightmapsData的脚本(具体脚本内容会在最后提供)

unity烘焙光照贴图,unity教程,unity,贴图,游戏引擎

 后面将我们需要烘焙光照贴图的物体都勾上Static,让他成为静态物体,同时我们要点击Static旁边的小箭头,取消Batching Static

unity烘焙光照贴图,unity教程,unity,贴图,游戏引擎

当然了,别忘了把我们的光(这边是点光源)改成Baked

unity烘焙光照贴图,unity教程,unity,贴图,游戏引擎

 然后打开Lighting Setting一样按照需求设置光照贴图数据就行 

unity烘焙光照贴图,unity教程,unity,贴图,游戏引擎

但是接下来烘焙需要注意不再是点击Lighting setting里的Generate Lighting按钮烘焙了,再之前的PrefabLightmapsData脚本中提供了一个简单的编辑器扩展的烘焙按钮,在最上方有个Tools->Bake Prefab Lightmaps的按钮,我们点击这个按钮进行烘焙

unity烘焙光照贴图,unity教程,unity,贴图,游戏引擎

顺便提一下,通过我们编辑器扩展的按钮烘焙的时候,烘焙进度不在原来的引擎自带的地方显示了,而是在下方的任务栏上那个Unity图标上会有一个绿色的进度

unity烘焙光照贴图,unity教程,unity,贴图,游戏引擎

烘焙完成后,我们就可以在PrefabLightmapsData上的三个数组中看到这些模型和光照贴图的数据了 

unity烘焙光照贴图,unity教程,unity,贴图,游戏引擎

接着我们可以创建一个新的Scene,然后把预制体拖进去看下效果,下图我们可以看到新的场景中是没有任何光照灯的,但是看到的效果却是有正常光照贴图的效果,如果没看到效果,因为是在Awake中设置的,可以运行后再看就会有效果了

unity烘焙光照贴图,unity教程,unity,贴图,游戏引擎

到这里基本上预制体烘焙光照贴图就已经完成了,下面放上PrefabLightmapsData脚本的代码,以及最后会写几点之前我使用时踩到过的几个坑。

(脚本有更新,原先的脚本不支持地形的光照贴图设置)

using System.Collections.Generic;
using UnityEditor;
using UnityEngine;

[DisallowMultipleComponent]
[ExecuteInEditMode]
public class PrefabLightmapsData : MonoBehaviour
{
    [System.Serializable]
    struct RendererInfo
    {
        public Terrain terrain;
        public Renderer renderer;
        public int lightmapIndex;
        public Vector4 lightmapOffsetScale;
    }

    [SerializeField]
    RendererInfo[] m_RendererInfo;
    [SerializeField]
    Texture2D[] m_LightmapsColor;
    [SerializeField]
    Texture2D[] _lightmaps;

    void Awake()
    {
        if (m_RendererInfo == null || m_RendererInfo.Length == 0)
            return;

        var lightmaps = LightmapSettings.lightmaps;
        var combinedLightmaps = new LightmapData[lightmaps.Length + m_LightmapsColor.Length];

        lightmaps.CopyTo(combinedLightmaps, 0);
        for (int i = 0; i < m_LightmapsColor.Length; i++)
        {
            combinedLightmaps[i + lightmaps.Length] = new LightmapData();
            combinedLightmaps[i + lightmaps.Length].lightmapColor = m_LightmapsColor[i];
            combinedLightmaps[i + lightmaps.Length].lightmapDir = _lightmaps[i];

        }

        ApplyRendererInfo(m_RendererInfo, lightmaps.Length);
        LightmapSettings.lightmaps = combinedLightmaps;
    }


    static void ApplyRendererInfo(RendererInfo[] infos, int lightmapOffsetIndex)
    {
        for (int i = 0; i < infos.Length; i++)
        {
            var info = infos[i];
            if (info.renderer != null)
            {
                info.renderer.lightmapIndex = info.lightmapIndex + lightmapOffsetIndex;
                info.renderer.lightmapScaleOffset = info.lightmapOffsetScale;
            }
            else if(info.terrain!=null)
            {
                info.terrain.lightmapIndex = info.lightmapIndex + lightmapOffsetIndex;
                info.terrain.lightmapScaleOffset = info.lightmapOffsetScale;
            }
        }
    }


#if UNITY_EDITOR
    [UnityEditor.MenuItem("Tools/Bake Prefab Lightmaps")]
    static void GenerateLightmapInfo()
    {
        if (UnityEditor.Lightmapping.giWorkflowMode != UnityEditor.Lightmapping.GIWorkflowMode.OnDemand)
        {
            Debug.LogError("ExtractLightmapData requires that you have baked you lightmaps and Auto mode is disabled.");
            return;
        }
        UnityEditor.Lightmapping.Bake();

        PrefabLightmapsData[] prefabs = GameObject.FindObjectsOfType<PrefabLightmapsData>();

        foreach (var instance in prefabs)
        {
            var gameObject = instance.gameObject;
            var rendererInfos = new List<RendererInfo>();
            var lightmapsColor = new List<Texture2D>();
            List<Texture2D> lightmapsDir = new List<Texture2D>();

            GenerateLightmapInfo(gameObject, rendererInfos, lightmapsColor, lightmapsDir);

            instance.m_RendererInfo = rendererInfos.ToArray();
            instance.m_LightmapsColor = lightmapsColor.ToArray();
            instance._lightmaps = lightmapsDir.ToArray();


            var targetPrefab = PrefabUtility.GetCorrespondingObjectFromOriginalSource(instance.gameObject) as GameObject;
            if (targetPrefab != null)
            {
                GameObject root = PrefabUtility.GetOutermostPrefabInstanceRoot(instance.gameObject);

                if (root != null)
                {
                    GameObject rootPrefab = PrefabUtility.GetCorrespondingObjectFromSource(instance.gameObject);
                    string rootPath = AssetDatabase.GetAssetPath(rootPrefab);
                    PrefabUtility.UnpackPrefabInstanceAndReturnNewOutermostRoots(root, PrefabUnpackMode.OutermostRoot);
                    try
                    {
                        PrefabUtility.ApplyPrefabInstance(instance.gameObject, InteractionMode.AutomatedAction);
                    }
                    catch { }
                    finally
                    {
                        PrefabUtility.SaveAsPrefabAssetAndConnect(root, rootPath, InteractionMode.AutomatedAction);
                    }
                }
                else
                {
                    PrefabUtility.ApplyPrefabInstance(instance.gameObject, InteractionMode.AutomatedAction);
                }
            }
        }
    }

    static void GenerateLightmapInfo(GameObject root, List<RendererInfo> rendererInfos, List<Texture2D> lightmapsColor, List<Texture2D> lightmapsDir)
    {
        var renderers = root.GetComponentsInChildren<MeshRenderer>();
        foreach (MeshRenderer renderer in renderers)
        {
            if (renderer.lightmapIndex != -1)
            {
                RendererInfo info = new RendererInfo();
                info.renderer = renderer;
                if (renderer.lightmapScaleOffset != Vector4.zero)
                {
                    info.lightmapOffsetScale = renderer.lightmapScaleOffset;
                    Texture2D lightmapColor = LightmapSettings.lightmaps[renderer.lightmapIndex].lightmapColor;
                    Texture2D lightmapDir = LightmapSettings.lightmaps[renderer.lightmapIndex].lightmapDir;

                    info.lightmapIndex = lightmapsColor.IndexOf(lightmapColor);
                    if (info.lightmapIndex == -1)
                    {
                        info.lightmapIndex = lightmapsColor.Count;
                        lightmapsColor.Add(lightmapColor);
                        lightmapsDir.Add(lightmapDir);
                    }

                    rendererInfos.Add(info);
                }
            }
        }

        var Terrainrenderers = root.GetComponentsInChildren<Terrain>();
        foreach (var terrain in Terrainrenderers)
        {
            if (terrain.lightmapIndex != -1)
            {
                RendererInfo info = new RendererInfo();
                info.terrain = terrain;
                if (terrain.lightmapScaleOffset != Vector4.zero)
                {
                    info.lightmapOffsetScale = terrain.lightmapScaleOffset;
                    Texture2D lightmapColor = LightmapSettings.lightmaps[terrain.lightmapIndex].lightmapColor;
                    Texture2D lightmapDir = LightmapSettings.lightmaps[terrain.lightmapIndex].lightmapDir;

                    info.lightmapIndex = lightmapsColor.IndexOf(lightmapColor);
                    if (info.lightmapIndex == -1)
                    {
                        info.lightmapIndex = lightmapsColor.Count;
                        lightmapsColor.Add(lightmapColor);
                        lightmapsDir.Add(lightmapDir);
                    }

                    rendererInfos.Add(info);
                }
            }
        }
    }
#endif
} 

具体的我也没去往深入的研究为什么,如果有大佬研究了可以写在评论区,这边我就直接说我的解决方案,在烘焙前的Lightmapping Settings里有个Directional Mode的设置,默认选择的时Directional,表示有漫反射的,Non-Directional是关闭漫反射的烘焙,我们只需要选择Non-Directional后烘焙就行,但是呢这样烘焙出来的光照贴图会缺少一张lightmap-dir的图片,导致效果不好。 

unity烘焙光照贴图,unity教程,unity,贴图,游戏引擎

unity烘焙光照贴图,unity教程,unity,贴图,游戏引擎

 

要怎么保证效果好旋转后又不会出现问题,后面再说,先来说下我碰到的过的第二个问题,因为这个的解决方法和第二个问题的解决方法一致。

2、第二个问题呢我直接描述下,因为现在写笔记时暂时没碰到因此就没有图片看出现问题的效果了。出现的问题是烘培好预制体后放到新的工程或者新的场景中时,所有文件都正常的,但是在场景中不管是运行状态还是没运行状态预制体的贴图都变成黑白的了。

具体原因我也没有深入的查找,如果有大佬知道欢迎在评论区或者私信告知,谢谢!

我这里也直接说解决方案,我们直接托烘焙好的预制体虽然会把光照贴图设置上去,但是在Lighting Setting中下图这个位置,是没有LightingDataAsset文件的,我们只需要在这个场景中(可以不放任何东西烘焙一个空的贴图生成一个LightingDataAsset文件即可)然后在把烘焙好的预制体放到场景中,就不会出现黑白的情况了。 

unity烘焙光照贴图,unity教程,unity,贴图,游戏引擎

由于在最终的Scene会烘焙一个空的光照贴图生成一个LightingDataAsset文件,就让我产生了一个想法,在第一个问题中我们需要把Directional Mode设置成Non-Directional来避免第一个问题,那么我们是不是可以在最终Scene上烘焙的时候这么设置,然后烘焙预制体的时候还是选择Directional来正常设置,这样如果能成功不就能提高了预制体的烘焙效果,又能避免旋转后出现问题了吗。

然后我就开始了尝试,先给空的场景设置Non-Directional后用PrefabLightmapsData脚本中提供的烘焙按钮给空场景烘焙了个贴图和LightingDataAsset

unity烘焙光照贴图,unity教程,unity,贴图,游戏引擎

 

unity烘焙光照贴图,unity教程,unity,贴图,游戏引擎

然后再将之前设置Directional烘焙出来的预制体放入场景中,再把X旋转90度后我们可以看到做出红框中的光照贴图也不再变黑了。

unity烘焙光照贴图,unity教程,unity,贴图,游戏引擎

 好了本篇笔记就到这边结束了,如果有问题,请在评论区留言讨论.文章来源地址https://www.toymoban.com/news/detail-697598.html

到了这里,关于Unity中对预制体烘焙光照贴图,在其他Scene中使用或者动态生成带光照贴图的预制体的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Unity引擎光照烘焙

    一、先将系统中的光源去掉,会发现场景还是亮的。将天空环境光去掉(Windows- Rendering-Lighting) 将Environment Lighting, Environment Reflections设置为0.    二、创建一个简单的点光源 模拟大方块照出的光可以将光源拖到方块前面的位置。  其中有三个光源,PointLight是模拟大方块照亮

    2024年02月16日
    浏览(23)
  • Unity光照相关知识和实践 (烘焙光照,环境光设置,全局光照)

    本文将会通过一个简单的场景搭建,介绍如何使用烘焙光照以及相关的注意事项。另外还介绍了Unity内全局光照(GI)的知识和GI实际在游戏内的表现效果。 Unity关于光照相关的参考文档地址:https://docs.unity.cn/cn/current/Manual/LightingOverview.html 下面是一些基本的概念 直接光照指的

    2024年02月15日
    浏览(21)
  • 第二十二章 Unity 光照贴图

    光照贴图过程将预先计算场景中静态物体表面的亮度,并将结果存储在称为“光照贴图”的纹理中供以后使用。光照贴图可以包含直接光照和间接光照,以及阴影效果。但是,烘焙到光照贴图中的数据无法在运行时更改,这就是为什么移动静态物体后,阴影不会跟随移动。接

    2024年02月04日
    浏览(28)
  • Unity光照贴图的切换,实现黑夜和白天效果

    有这么一个需求,不能使用实时光来进行动态控制光照开关,但是又要实现白天和黑夜的效果,我的场景中有大概十几个点光源和平行光 实现步骤: 一、 模型原模原样复制到另一个场景中(因为贴图只能存在于当前的场景文件夹) 二、 在不同的场景中调试白天和黑夜的效

    2024年02月10日
    浏览(30)
  • Unity 获取文件夹下的预制体名称(可改成其他材质)

    其实获取并不难 可以说想起来API就能想起来 但是很多不常用API就会使人容易遗忘  废话就不多说了 首先命名空间必不可少的 接下来看主要代码的部分吧    我拿的我的Resources下的player文件夹下举个例子吧 这就完事了     你还想往下看看? 那就看看我的路径和演示效果吧

    2024年02月04日
    浏览(41)
  • 3dmax通过烘焙合并一个模型的多个贴图流程

    合并多个模型也是可以的,文件是自动保存的TGA格式,后期PS可以批处理保存JPEG。 1、3dmax中文件打开模型 2、转为可编辑多边形  3、设置环境光 4、 渲染到纹理(0)    

    2024年02月16日
    浏览(35)
  • wayland(xdg_wm_base) + egl + opengles 使用 Assimp 加载带光照信息的材质文件Mtl 实现光照贴图的最简实例(十七)

    `本文主要介绍opengles 如何使用 第三方库Assimp(基于C++) 加载一个最简单的带光照信息以及纹理 的3d 立方体model,3d 立方体 model 信息存储在 cube.obj 中,光照信息以及纹理图片信息存储在cube.Mtl 材质文件中,主要是介绍如何使用Assimp 解析Mtl 文件。 软硬件环境: 硬件:PC 软件

    2024年04月14日
    浏览(25)
  • 第二十二章 光照贴图

    光照贴图过程将预先计算场景中静态物体表面的亮度,并将结果存储在称为“光照贴图”的纹理中供以后使用。光照贴图可以包含直接光照和间接光照,以及阴影效果。但是,烘焙到光照贴图中的数据无法在运行时更改,这就是为什么移动静态物体后,阴影不会跟随移动。接

    2024年02月02日
    浏览(32)
  • 【Unity】 预制体Prefab使用说明

    在 Unity 中,Prefab 是一个可以预先制作并重复使用的 GameObject 或组件集合,Prefab 中的 GameObject 可以有子对象和其他组件。与场景中直接创建 GameObject 不同,Prefab 可以在多个场景或项目中重复使用,并且可以轻松地进行修改和更新。Prefab 可以节省开发时间,并 提高游戏的可维

    2024年02月16日
    浏览(43)
  • 使用Unity生成UI预制体 (Unity3D)

    在Unity中,预制体(Prefab)是一种非常有用的工具,用于生成可重复使用的UI元素。预制体使得UI的创建和管理变得更加简单和高效。在本文中,我们将详细介绍如何使用Unity生成UI预制体,并提供相应的源代码示例。 步骤1:创建UI元素 首先,我们需要创建UI元素,例如按钮、

    2024年02月05日
    浏览(39)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包