unity5 导出unity场景导出max 之后在安卓设备上光照贴图丢失怎么回事??

程序写累了,就来玩玩酷跑小游戏吧,嘿嘿。
雨松MOMO送你一首歌曲,嘿嘿。
Unity3D研究院之Unity5.x运行时动态更新烘培贴图(八十七)
Unity3D研究院之Unity5.x运行时动态更新烘培贴图(八十七)
围观27749次
编辑日期: 字体:
前段时间我研究过这个问题,但是没有解决只好作罢。今天刚好有人又问我这个问题,我得空查了一下还是找到了解决办法。另外也感谢问我的人,解答问题的同时也是我学习的过程。
运行时更新烘培贴图分两种情况
1、场景的物件没有发生变化(也就是说没有运行时加载在场景上的Prefab)此时可以直接更换烘培贴图。
1234567891011121314151617181920212223242526
using UnityEngine;using System.Collections;&public class NewBehaviourScript : MonoBehaviour {& //烘培烘培贴图1 public Texture2D greenLightMap; //烘培贴图2 public Texture2D redLightMap; void OnGUI() {
if(GUILayout.Button("green"))
LightmapData data = new LightmapData();
data.lightmapFar = greenLightMap;
LightmapSettings.lightmaps = new LightmapData[1]{data};
if(GUILayout.Button("red"))
LightmapData data = new LightmapData();
data.lightmapFar = redLightMap;
LightmapSettings.lightmaps = new LightmapData[1]{data};
2.场景的烘培贴图已经更新,但是有些物件prefab想运行时加载进来。如果直接Instance的话 这个Prefab是没有烘培信息的。(灰颜色的)
解决这个问题我查到了 一篇大大的文章,它带了例子大家可以下载下来。
代码在这里,把如下代码挂在GameObject上。当场景烘培结束后,把他保存成prefab,运行的时候直接加载进来就行了。
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258
#if UNITY_EDITORusing UnityEditor;using System.IO;#endifusing UnityEngine;using System.Collections.Generic;[DisallowMultipleComponent,ExecuteInEditMode] public class PrefabLightmapData : MonoBehaviour{&&&&[System.Serializable]&&&&struct RendererInfo&&&&{&&&&&&&&public Renderer renderer;&&&&&&&&public int lightmapIndex;&&&&&&&&public Vector4 lightmapOffsetScale;&&&&} &&&&[SerializeField]&&&&RendererInfo[] m_RendererInfo;&&&&[SerializeField]&&&&Texture2D[] m_Lightmaps;&&&&[SerializeField]&&&&Texture2D[] m_Lightmaps2; &&&&const string LIGHTMAP_RESOURCE_PATH = "Assets/Resources/Lightmaps/"; &&&&[System.Serializable]&&&&struct Texture2D_Remap&&&&{&&&&&&&&public int originalLightmapIndex;&&&&&&&&public Texture2D originalLightmap;&&&&&&&&public Texture2D lightmap0;&&&&&&&&public Texture2D lightmap1;&&&&} &&&&static List&Texture2D_Remap& sceneLightmaps = new List&Texture2D_Remap&(); &&&&void Awake()&&&&{&&&&&&&&ApplyLightmaps(m_RendererInfo, m_Lightmaps, m_Lightmaps2);&&&&} &&&&static void ApplyLightmaps(RendererInfo[] rendererInfo, Texture2D[] lightmaps, Texture2D[] lightmaps2)&&&&{&&&&&&&&bool existsAlready = false;&&&&&&&&int counter = 0;&&&&&&&&int[] lightmapArrayOffsetIndex; &&&&&&&&if (rendererInfo == null || rendererInfo.Length == 0)&&&&&&&&&&&&return; &&&&&&&&var settingslightmaps = LightmapSettings.lightmaps;&&&&&&&&var combinedLightmaps = new List&LightmapData&();&&&&&&&&lightmapArrayOffsetIndex = new int[lightmaps.Length]; &&&&&&&&for (int i = 0; i & lightmaps.Length; i++)&&&&&&&&{&&&&&&&&&&&&existsAlready = false;&&&&&&&&&&&&for (int j = 0; j & settingslightmaps.Length; j++)&&&&&&&&&&&&{&&&&&&&&&&&&&&&&if (lightmaps[i] == settingslightmaps[j].lightmapFar)&&&&&&&&&&&&&&&&{&&&&&&&&&&&&&&&&&&&&lightmapArrayOffsetIndex[i] = j;&&&&&&&&&&&&&&&&&&&&existsAlready = true;&&&&&&&&&&&&&&&&}&&&&&&&&&&&&} &&&&&&&&&&&&if (!existsAlready)&&&&&&&&&&&&{&&&&&&&&&&&&&&&&lightmapArrayOffsetIndex[i] = counter + settingslightmaps.Length;&&&&&&&&&&&&&&&&var newLightmapData = new LightmapData();&&&&&&&&&&&&&&&&newLightmapData.lightmapFar = lightmaps[i];&&&&&&&&&&&&&&&&newLightmapData.lightmapNear = lightmaps2[i];&&&&&&&&&&&&&&&&combinedLightmaps.Add(newLightmapData);&&&&&&&&&&&&&&&&++counter;&&&&&&&&&&&&}&&&&&&&&} &&&&&&&&var combinedLightmaps2 = new LightmapData[settingslightmaps.Length + counter];&&&&&&&&settingslightmaps.CopyTo(combinedLightmaps2, 0); &&&&&&&&if (counter & 0)&&&&&&&&{&&&&&&&&&&&&for (int i = 0; i & combinedLightmaps.Count; i++)&&&&&&&&&&&&{&&&&&&&&&&&&&&&&combinedLightmaps2[i + settingslightmaps.Length] = new LightmapData();&&&&&&&&&&&&&&&&combinedLightmaps2[i + settingslightmaps.Length].lightmapFar = combinedLightmaps[i].lightmapFar;&&&&&&&&&&&&&&&&combinedLightmaps2[i + settingslightmaps.Length].lightmapNear = combinedLightmaps[i].lightmapNear;&&&&&&&&&&&&}&&&&&&&&} &&&&&&&&ApplyRendererInfo(rendererInfo, lightmapArrayOffsetIndex); &&&&&&&&LightmapSettings.lightmaps = combinedLightmaps2;&&&&} &&&&static void ApplyRendererInfo(RendererInfo[] infos, int[] arrayOffsetIndex)&&&&{&&&&&&&&for (int i = 0; i & infos.Length; i++)&&&&&&&&{&&&&&&&&&&&&var info = infos[i];&&&&&&&&&&&&info.renderer.lightmapIndex = arrayOffsetIndex[info.lightmapIndex];&&&&&&&&&&&&info.renderer.lightmapScaleOffset = info.lightmapOffsetScale;&&&&&&&&}&&&&} #if UNITY_EDITOR&&&&[MenuItem("Assets/Update Scene with Prefab Lightmaps")]&&&&static void UpdateLightmaps()&&&&{&&&&&&&&PrefabLightmapData[] prefabs = FindObjectsOfType&PrefabLightmapData&(); &&&&&&&&foreach (var instance in prefabs)&&&&&&&&{&&&&&&&&&&&&ApplyLightmaps(instance.m_RendererInfo, instance.m_Lightmaps, instance.m_Lightmaps2);&&&&&&&&} &&&&&&&&Debug.Log("Prefab lightmaps updated");&&&&} &&&&[MenuItem("Assets/Bake Prefab Lightmaps")]&&&&static void GenerateLightmapInfo()&&&&{&&&&&&&&Debug.ClearDeveloperConsole(); &&&&&&&&if (Lightmapping.giWorkflowMode != Lightmapping.GIWorkflowMode.OnDemand)&&&&&&&&{&&&&&&&&&&&&Debug.LogError("ExtractLightmapData requires that you have baked you lightmaps and Auto mode is disabled.");&&&&&&&&&&&&return;&&&&&&&&} &&&&&&&&Lightmapping.Bake();&
string lightMapPath = System.IO.Path.Combine(Directory.GetCurrentDirectory(),LIGHTMAP_RESOURCE_PATH);&
if(!Directory.Exists(lightMapPath))
Directory.CreateDirectory(lightMapPath);&&&&&&&&&sceneLightmaps = new List&Texture2D_Remap&(); &&&&&&&&//var scene = UnityEngine.SceneManagement.SceneManager.GetActiveScene();
var sceneName =Path.GetFileNameWithoutExtension(EditorApplication.currentScene) ;
var resourcePath = LIGHTMAP_RESOURCE_PATH + sceneName;
var scenePath = System.IO.Path.GetDirectoryName(EditorApplication.currentScene) + "/" + sceneName + "/";
&&&&&&&&PrefabLightmapData[] prefabs = FindObjectsOfType&PrefabLightmapData&(); &&&&&&&&foreach (var instance in prefabs)&&&&&&&&{&&&&&&&&&&&&var gameObject = instance.gameObject;&&&&&&&&&&&&var rendererInfos = new List&RendererInfo&();&&&&&&&&&&&&var lightmaps = new List&Texture2D&();&&&&&&&&&&&&var lightmaps2 = new List&Texture2D&(); &&&&&&&&&&&&GenerateLightmapInfo(scenePath, resourcePath, gameObject, rendererInfos, lightmaps, lightmaps2); &&&&&&&&&&&&instance.m_RendererInfo = rendererInfos.ToArray();&&&&&&&&&&&&instance.m_Lightmaps = lightmaps.ToArray();&&&&&&&&&&&&instance.m_Lightmaps2 = lightmaps2.ToArray(); &&&&&&&&&&&&var targetPrefab = PrefabUtility.GetPrefabParent(gameObject) as GameObject;&&&&&&&&&&&&if (targetPrefab != null)&&&&&&&&&&&&{&&&&&&&&&&&&&&&&//Prefab&&&&&&&&&&&&&&&&PrefabUtility.ReplacePrefab(gameObject, targetPrefab);&&&&&&&&&&&&} &&&&&&&&&&&&ApplyLightmaps(instance.m_RendererInfo, instance.m_Lightmaps, instance.m_Lightmaps2);&&&&&&&&} &&&&&&&&Debug.Log("Update to prefab lightmaps finished");&&&&} &&&&static void GenerateLightmapInfo(string scenePath, string resourcePath, GameObject root, List&RendererInfo& rendererInfos, List&Texture2D& lightmaps, List&Texture2D& lightmaps2)&&&&{&&&&&&&&var renderers = root.GetComponentsInChildren&MeshRenderer&();&&&&&&&&foreach (MeshRenderer renderer in renderers)&&&&&&&&{&&&&&&&&&&&&if (renderer.lightmapIndex != -1)&&&&&&&&&&&&{&&&&&&&&&&&&&&&&RendererInfo info = new RendererInfo();&&&&&&&&&&&&&&&&info.renderer = renderer;&&&&&&&&&&&&&&&&info.lightmapOffsetScale = renderer.lightmapScaleOffset; &&&&&&&&&&&&&&&&Texture2D lightmap = LightmapSettings.lightmaps[renderer.lightmapIndex].lightmapFar;&&&&&&&&&&&&&&&&Texture2D lightmap2 = LightmapSettings.lightmaps[renderer.lightmapIndex].lightmapNear;&&&&&&&&&&&&&&&&int sceneLightmapIndex = AddLightmap(scenePath, resourcePath, renderer.lightmapIndex, lightmap, lightmap2); &&&&&&&&&&&&&&&&info.lightmapIndex = lightmaps.IndexOf(sceneLightmaps[sceneLightmapIndex].lightmap0);&&&&&&&&&&&&&&&&if (info.lightmapIndex == -1)&&&&&&&&&&&&&&&&{&&&&&&&&&&&&&&&&&&&&info.lightmapIndex = lightmaps.Count;&&&&&&&&&&&&&&&&&&&&lightmaps.Add(sceneLightmaps[sceneLightmapIndex].lightmap0);&&&&&&&&&&&&&&&&&&&&lightmaps2.Add(sceneLightmaps[sceneLightmapIndex].lightmap1);&&&&&&&&&&&&&&&&} &&&&&&&&&&&&&&&&rendererInfos.Add(info);&&&&&&&&&&&&}&&&&&&&&}&&&&} &&&&static int AddLightmap(string scenePath, string resourcePath, int originalLightmapIndex, Texture2D lightmap, Texture2D lightmap2)&&&&{&&&&&&&&int newIndex = -1; &&&&&&&&for (int i = 0; i & sceneLightmaps.Count; i++)&&&&&&&&{&&&&&&&&&&&&if (sceneLightmaps[i].originalLightmapIndex == originalLightmapIndex)&&&&&&&&&&&&{&&&&&&&&&&&&&&&&return i;&&&&&&&&&&&&}&&&&&&&&} &&&&&&&&if (newIndex == -1)&&&&&&&&{&&&&&&&&&&&&var lightmap_Remap = new Texture2D_Remap();&&&&&&&&&&&&lightmap_Remap.originalLightmapIndex = originalLightmapIndex;&&&&&&&&&&&&lightmap_Remap.originalLightmap = lightmap; &&&&&&&&&&&&var filename = scenePath + "Lightmap-" + originalLightmapIndex; &&&&&&&&&&&&lightmap_Remap.lightmap0 = GetLightmapAsset(filename + "_comp_light.exr", resourcePath + "_light", originalLightmapIndex, lightmap);&&&&&&&&&&&&if (lightmap2 != null)&&&&&&&&&&&&{&&&&&&&&&&&&&&&&lightmap_Remap.lightmap1 = GetLightmapAsset(filename + "_comp_dir.exr", resourcePath + "_dir", originalLightmapIndex, lightmap2);&&&&&&&&&&&&} &&&&&&&&&&&&sceneLightmaps.Add(lightmap_Remap);&&&&&&&&&&&&newIndex = sceneLightmaps.Count - 1;&&&&&&&&} &&&&&&&&return newIndex;&&&&} &&&&static Texture2D GetLightmapAsset(string filename, string resourcePath, int originalLightmapIndex, Texture2D lightmap)&&&&{&&&&&&&&AssetDatabase.ImportAsset(filename, ImportAssetOptions.ForceUpdate);&&&&&&&&var importer = AssetImporter.GetAtPath(filename) as TextureImporter;&&&&&&&&importer.isReadable = true;&&&&&&&&AssetDatabase.ImportAsset(filename, ImportAssetOptions.ForceUpdate); &&&&&&&&var assetLightmap = AssetDatabase.LoadAssetAtPath&Texture2D&(filename);&&&&&&&&&var assetPath = resourcePath + "-" + originalLightmapIndex + ".asset";&&&&&&&&var newLightmap = Instantiate&Texture2D&(assetLightmap); &&&&&&&&AssetDatabase.CreateAsset(newLightmap, assetPath); &&&&&&&&newLightmap = AssetDatabase.LoadAssetAtPath&Texture2D&(assetPath); &&&&&&&&importer.isReadable = false;&&&&&&&&AssetDatabase.ImportAsset(filename, ImportAssetOptions.ForceUpdate); &&&&&&&&return newLightmap;&&&&}#endif }
点击 Assets/Bake Prefab Lightmaps 进行烘培, 这样它的脚本里会把index 和 offset保存在prefab里。它还会保存上当前烘培场景的Lightmap,如果运行时想更换的话,你可以加一些自己的逻辑进行切换。
最后欢迎大家测试,欢迎大家提出宝贵意见,我们一起把unity这个坑填了!
本文固定链接:
转载请注明:
雨松MOMO提醒您:亲,如果您觉得本文不错,快快将这篇文章分享出去吧 。另外请点击网站顶部彩色广告或者捐赠支持本站发展,谢谢!
作者:雨松MOMO
专注移动互联网,Unity3D游戏开发
如果您愿意花10块钱请我喝一杯咖啡的话,请用手机扫描二维码即可通过支付宝直接向我捐款哦。
您可能还会对这些文章感兴趣!unity打包(2)
场景中对预设体进行烘焙贴图后,然后删掉场景中的预设体,接着再通过代码实例化这个预设体或者直接拖一个预设体进入一个场景,都会发现场景光照信息丢失
光照信息丢失的主要原因是:
解决这个问题的办法如下:
先准备一个场景,如下:
上面的红色物体全部勾选为静态(static),蓝色物体作为参照不勾选静态
对lighting进行参数设置
经过上面准备工作做好后,开始烘焙
此时 ,我们删掉场景中的Plane预设体,然后再重新向场景中拖入该Plane的预设体,你会发现,没有光照信息,场景很暗
但是此时运行场景,你会发现光照信息又有啦
using UnityE
using System.C
using System.Collections.G
public class PrefabLightmapData : MonoBehaviour
[System.Serializable]
struct RendererInfo
public int
public Vector4
lightmapOffsetS
[SerializeField]
RendererInfo[]
m_RendererI
[SerializeField]
Texture2D[]
void Awake ()
if (m_RendererInfo == null || m_RendererInfo.Length == 0)
var lightmaps = LightmapSettings.
var combinedLightmaps = new LightmapData[lightmaps.Length + m_Lightmaps.Length];
lightmaps.CopyTo(combinedLightmaps, 0);
for (int i = 0; i & m_Lightmaps.Li++)
combinedLightmaps[i+lightmaps.Length] = new LightmapData();
combinedLightmaps[i+lightmaps.Length].lightmapFar = m_Lightmaps[i];
ApplyRendererInfo(m_RendererInfo, lightmaps.Length);
LightmapSettings.lightmaps = combinedL
static void ApplyRendererInfo (RendererInfo[] infos, int lightmapOffsetIndex)
for (int i=0;i&infos.Li++)
var info = infos[i];
info.renderer.lightmapIndex = info.lightmapIndex + lightmapOffsetI
info.renderer.lightmapScaleOffset = info.lightmapOffsetS
#if UNITY_EDITOR
[UnityEditor.MenuItem("Assets/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.");
UnityEditor.Lightmapping.Bake();
PrefabLightmapData[] prefabs = FindObjectsOfType&PrefabLightmapData&();
foreach (var instance in prefabs)
var gameObject = instance.gameO
var rendererInfos = new List&RendererInfo&();
var lightmaps = new List&Texture2D&();
GenerateLightmapInfo(gameObject, rendererInfos, lightmaps);
instance.m_RendererInfo = rendererInfos.ToArray();
instance.m_Lightmaps = lightmaps.ToArray();
var targetPrefab = UnityEditor.PrefabUtility.GetPrefabParent(gameObject) as GameO
if (targetPrefab != null)
UnityEditor.PrefabUtility.ReplacePrefab(gameObject, targetPrefab);
static void GenerateLightmapInfo (GameObject root, List&RendererInfo& rendererInfos, List&Texture2D& lightmaps)
var renderers = root.GetComponentsInChildren&MeshRenderer&();
foreach (MeshRenderer renderer in renderers)
if (renderer.lightmapIndex != -1)
RendererInfo info = new RendererInfo();
info.renderer =
info.lightmapOffsetScale = renderer.lightmapScaleO
Texture2D lightmap = LightmapSettings.lightmaps[renderer.lightmapIndex].lightmapF
info.lightmapIndex = lightmaps.IndexOf(lightmap);
if (info.lightmapIndex == -1)
info.lightmapIndex = lightmaps.C
lightmaps.Add(lightmap);
rendererInfos.Add(info);
注意Directional Mode这个参数要设置成Non-Directional,否则运行场景会是黑的,得不到预期的烘焙效果
FR:海涛高软(QQ技术交流群:)
&&相关文章推荐
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:351808次
积分:9447
积分:9447
排名:第1899名
原创:583篇
评论:77条
(17)(33)(30)(20)(21)(14)(31)(70)(40)(62)(62)(58)(44)(58)(23)Unity中光照贴图一二坑及解决办法
我的图书馆
Unity中光照贴图一二坑及解决办法
Lightmap(光照贴图)是Unity里很常用的一个功能,毕竟移动设备上实时光照不靠谱,要出效果还是得烘焙。但是在使用中发现了几坑的地方,通过自己写了个两个脚本就轻松搞定,这里分享下。
坑1: 异步加载场景
这个其实还是挺常见的坑:在编辑器里烘焙+播放场景都没问题,但是当从别的场景利用 异步加载 方式切换之后,就发现场景里的效果一团糟。下图是我使用 Application.LoadLevelAdditiveAsync 切换后的效果:
如果是同步的加载场景倒是没有这个问题,但是实际游戏一般也不会让玩家卡住等待一段时间。这个问题在官方论坛和issue tracker上都有人提及,产生的原因是切换场景之后无法自动切换该场景使用的lightmap数据,具体可以参考 UnityEngine.LightmapSettings 相关API。
解决办法也很简单,我实现了一个小脚本,挂在场景中;当场景载入完成,这个物体会在 Start() 中自动刷新当前的光照贴图设置。为了美术方便,脚本能够在每次场景烘焙完之后自动保存新的光照贴图设置,这样就避免了手动操作。
using UnityE
[ExecuteInEditMode]
public class SerializedLightmapSetting : MonoBehaviour
[HideInInspector]
public Texture2D []lightmapFar, lightmapN
[HideInInspector]
public LightmapsM
#if UNITY_EDITOR
public void OnEnable()
//Debug.Log("[SerializedLightmapSetting] hook");
pleted += LoadL
public void OnDisable()
//Debug.Log("[SerializedLightmapSetting] unhook");
pleted -= LoadL
public void Start ()
if(Application.isPlaying)
LightmapSettings.lightmapsMode =
int l1 = (lightmapFar == null) ? 0 : lightmapFar.L
int l2 = (lightmapNear == null) ? 0 : lightmapNear.L
int l = (l1 & l2) ? l2 : l1;
LightmapData[] lightmaps =
if (l & 0)
lightmaps = new LightmapData[l];
for (int i = 0; i & i++)
lightmaps[i] = new LightmapData();
if (i & l1)
lightmaps[i].lightmapFar = lightmapFar[i];
if (i & l2)
lightmaps[i].lightmapNear = lightmapNear[i];
LightmapSettings.lightmaps =
Destroy(this);
#if UNITY_EDITOR
public void LoadLightmaps()
mode = LightmapSettings.lightmapsM
lightmapFar =
lightmapNear =
if (LightmapSettings.lightmaps != null && LightmapSettings.lightmaps.Length & 0)
int l = LightmapSettings.lightmaps.L
lightmapFar = new Texture2D[l];
lightmapNear = new Texture2D[l];
for (int i = 0; i & i++)
lightmapFar[i] = LightmapSettings.lightmaps[i].lightmapF
lightmapNear[i] = LightmapSettings.lightmaps[i].lightmapN
MeshLightmapSetting[] savers = GameObject.FindObjectsOfType&MeshLightmapSetting&();
foreach(MeshLightmapSetting s in savers)
s.SaveSettings();
ps. 这里额外提一个坑的地方:一开始我想避免使用 MonoBehavior 这种比较笨重的东西来保存数据,然后参考了Unity官方博客里的 ScriptableObject 。结果尝试了一下午发现博客中的代码压根不起作用,感觉就是从头就写错了...
ps2. 编辑器提供的API还是挺方便的~最早版本的脚本每次烘焙完之后需要美术手动保存光照贴图设置,总是会忘,现在改成自动的就好多了。
坑2: Prefab化物体
在前面代码中有几行涉及到了 MeshLightmapSetting ,这个其实就是设计了第二个问题:利用 Instantiate 实例化的prefab的光照贴图也是一团糟,只有始终在场景里的物体才是正常的。
这个问题的本质原因是,prefab物体的光照贴图信息其实是保存在场景文件里,而不是对应的prefab中;这样以后当场景中有一个prefab的多个实例时,引擎能找到对应的光照贴图位置。但是实际项目中,为了提高场景的加载速度,我们的物体基本全是在代码里加载的,避免了加载场景时就同时加载了一堆prefab,所以就导致光照贴图全跪。
找到原因之后,就比较好解决了——既然引擎不保存,我可以手动保存一份就行了:
using UnityE
[ExecuteInEditMode]
[RequireComponent(typeof(Renderer))]
public class MeshLightmapSetting : MonoBehaviour {
[HideInInspector]
public int lightmapI
[HideInInspector]
public Vector4 lightmapScaleO
public void SaveSettings()
Renderer renderer = GetComponent&Renderer&();
lightmapIndex = renderer.lightmapI
lightmapScaleOffset = renderer.lightmapScaleO
public void LoadSettings()
Renderer renderer = GetComponent&Renderer&();
renderer.lightmapIndex = lightmapI
renderer.lightmapScaleOffset = lightmapScaleO
void Start () {
LoadSettings();
if(Application.isPlaying)
Destroy(this);
其实从这两点出发,可以更加灵活的使用光照贴图:
美术在不同光照条件下烘焙的lightmap保存起来,然后在运行时利用第一个脚本的思路切换,就实现了天气系统;
通过设置模型renderer的属性,可以使得不同物体复用(当然你得真正理解清楚光照贴图);
之后有机会的话,我会再整理下利用prefab加速场景加载的话题,目前单个场景从未优化的14s左右降到4s左右~
TA的最新馆藏
喜欢该文的人也喜欢Unity5.x场景优化之动态设置光照贴图lightmap
Unity5.x场景优化之动态设置光照贴图lightmap
编辑日期: 字体:
在很多情况下,我们为了提高渲染效率,一般都会让美术同学在制作场景时,设置场景相关节点的lightmap static属性,提前给整个场景烘培出静态的光照贴图lightmap,烘培的数据保存在场景目录下的LightmapSnapshot文件中,主要包括的数据有:
lightmaps:烘培出的光照贴图数组;
gameobject uid:被烘培的gameobject的唯一标识;
renderer的lightmapIndex:被烘培的gameobject的renderer组件所指向的光照贴图数组的索引;
renderer的lightmapScaleOffset:被烘培的gameobject的renderer组件所指向的光照贴图用于采样的区域坐标和宽高;
这个文件目前没有相关api读写,如果你想烘培完场景之后,把场景里面的gameobjet抽出来做成prefab,等切换完场景之后再用于动态加载是不可行的,因为抽出来的prefab在Instantiate之后将会是一个新的gameobject,uid自然和LightmapSnapshot文件里面记录的不一样,导致找不到对应的光照数据而造成模型没光照变暗或渲染错乱。
还有一种比较常见的需求是,在游戏运行时,通过更换光照贴图数据,营造场景在不同时间或季节的光照氛围,例如白天和黑夜等。
so,就算场景烘培完之后,我们还是要“动”它。
做法大概是,既然LightmapSnapshot文件我们不能动,那就把上面提到的光照数据保存到我们可以控制的文件里面,例如prefab。
首先,给场景根节点挂一个自定义组件,用于保存烘培出的光照贴图数组和烘培模式:
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273
using UnityEngine;using System.Collections;&[ExecuteInEditMode]public class SceneLightMapSetting : MonoBehaviour {&&&&public Texture2D []lightmapFar, lightmapNear;&&&&public LightmapsMode mode;&&&&&public void SaveSettings()&&&&{&&&&&&&&mode = LightmapSettings.lightmapsMode;&&&&&&&&lightmapFar = null;&&&&&&&&lightmapNear = null;&&&&&&&&if (LightmapSettings.lightmaps != null && LightmapSettings.lightmaps.Length & 0)&&&&&&&&{&&&&&&&&&&&&int l = LightmapSettings.lightmaps.Length;&&&&&&&&&&&&lightmapFar = new Texture2D[l];&&&&&&&&&&&&lightmapNear = new Texture2D[l];&&&&&&&&&&&&for (int i = 0; i & l; i++)&&&&&&&&&&&&{&&&&&&&&&&&&&&&&lightmapFar[i] = LightmapSettings.lightmaps[i].lightmapFar;&&&&&&&&&&&&&&&&lightmapNear[i] = LightmapSettings.lightmaps[i].lightmapNear;&&&&&&&&&&&&}&&&&&&&&}&&&&&&&&RendererLightMapSetting[] savers = Transform.FindObjectsOfType&RendererLightMapSetting&();&&&&&&&&foreach(RendererLightMapSetting s in savers)&&&&&&&&{&&&&&&&&&&&&s.SaveSettings();&&&&&&&&}&& }&&&&&public void LoadSettings()&&&&{&&&&&&&&LightmapSettings.lightmapsMode = mode;&&&&&&&&int l1 = (lightmapFar == null) ? 0 : lightmapFar.Length;&&&&&&&&int l2 = (lightmapNear == null) ? 0 : lightmapNear.Length;&&&&&&&&int l = (l1 & l2) ? l2 : l1;&&&&&&&&LightmapData[] lightmaps = null;&&&&&&&&if (l & 0)&&&&&&&&{&&&&&&&&&&&&lightmaps = new LightmapData[l];&&&&&&&&&&&&for (int i = 0; i & l; i++)&&&&&&&&&&&&{&&&&&&&&&&&&&&&&lightmaps[i] = new LightmapData();&&&&&&&&&&&&&&&&if (i & l1)&&&&&&&&&&&&&&&&&&&&lightmaps[i].lightmapFar = lightmapFar[i];&&&&&&&&&&&&&&&&if (i & l2)&&&&&&&&&&&&&&&&&&&&lightmaps[i].lightmapNear = lightmapNear[i];&&&&&&&&&&&&}&&&&&&&&&&&&&LightmapSettings.lightmaps = lightmaps;&&&&&&&&}&&&&} &&&&void OnEnable()&&&&{#if UNITY_EDITOR&&&&&&&&UnityEditor.Lightmapping.completed += SaveSettings;#endif&&&&}&&&&void OnDisable()&&&&{#if UNITY_EDITOR&&&&&&&&UnityEditor.Lightmapping.completed -= SaveSettings;#endif&&&&}&&&&&void Awake () {&&&&&&&&if(Application.isPlaying){&&&&&&&&&&&&LoadSettings();&&&&&&&&}&&&&}}
再给场景里面被烘培的gameobject挂一组件,用于保存光照贴图数组的索引和光照贴图的区域坐标和宽高数据:
12345678910111213141516171819202122232425262728293031323334353637383940414243444546
using UnityEngine;using System.Collections;&[ExecuteInEditMode]public class RendererLightMapSetting : MonoBehaviour {&&&&public int lightmapIndex;&&&&public Vector4 lightmapScaleOffset;&&&&&public void SaveSettings()&&&&{&&&&&&&&if(!IsLightMapGo(gameObject)){&&&&&&&&&&&&return;&&&&&&&&}&&&&&&&&Renderer renderer = GetComponent&Renderer&();&&&&&&&&lightmapIndex = renderer.lightmapIndex;&&&&&&&&lightmapScaleOffset = renderer.lightmapScaleOffset;&&&&}&&&&&public void LoadSettings()&&&&{&&&&&&&&if(!IsLightMapGo(gameObject)){&&&&&&&&&&&&return;&&&&&&&&}&&&&&&&&&Renderer renderer = GetComponent&Renderer&();&&&&&&&&renderer.lightmapIndex = lightmapIndex;&&&&&&&&renderer.lightmapScaleOffset = lightmapScaleOffset;&&&&}&&&&&public static bool IsLightMapGo(GameObject go){&&&&&&&&if(go == null){&&&&&&&&&&&&return false;&&&&&&&&}&&&&&&&&Renderer renderer = go.GetComponent&Renderer&();&&&&&&&&if(renderer == null){&&&&&&&&&&&&return false;&&&&&&&&}&&&&&&&&return true;&&&&}&&&&&void Awake () {&&&&&&&&if (Application.isPlaying) {&&&&&&&&&&&&LoadSettings ();&&&&&&&&}&&&&}}
如果手动挂上面两个脚本的话,繁琐且容易出错,so,写工具接口,用工具扫场景挂脚本:
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576
using UnityEngine;using UnityEditor;using System.IO;using System.Text;using System.Linq;using System.Collections;using System.Collections.Generic;using System;&public class SceneTools{&&&&static string[] _sNeedAssetType = new string[1]{&&&&&&&&".unity",&&&&};&&&&&[MenuItem("场景相关/1. 保存场景光照贴图信息", false, 111)]&&&&public static void SaveSceneMapLightSetting()&&&&{&&&&&&&&UnityEngine.Object[] selObjs = Selection.GetFiltered (typeof(UnityEngine.Object), SelectionMode.DeepAssets);&&&&&&&&if (selObjs == null || selObjs.Length == 0) {&&&&&&&&&&&&Debug.LogError ("请到\"Scenes\" 目录下选中需要保存场景光照贴图信息的场景!");&&&&&&&&&&&&return;&&&&&&&&} &&&&&&&&string assetPath;&&&&&&&&UnityEngine.Object assetObj = null;&&&&&&&&GameObject gameObj = null;&&&&&&&&SceneLightMapSetting slms = null;&&&&&&&&RendererLightMapSetting rlms = null;&&&&&&&&bool needSave = false;&&&&&&&&for (int i = 0; i & selObjs.Length; ++i) {&&&&&&&&&&&&needSave = false;&&&&&&&&&&&&assetPath = AssetDatabase.GetAssetPath (selObjs [i]);&&&&&&&&&&&&foreach (string extName in _sNeedAssetType) {&&&&&&&&&&&&&&&&if (assetPath.EndsWith (extName)) {&&&&&&&&&&&&&&&&&&&&needSave = true;&&&&&&&&&&&&&&&&&&&&break;&&&&&&&&&&&&&&&&}&&&&&&&&&&&&}&&&&&&&&&&&&if (!needSave)&&&&&&&&&&&&&&&&continue; &&&&&&&&&&&&assetObj = AssetDatabase.LoadAssetAtPath (assetPath, typeof(UnityEngine.Object)) as UnityEngine.Object;&&&&&&&&&&&&EditorApplication.OpenScene (assetPath); &&&&&&&&&&&&gameObj = GameObject.Find ("scene_root");&&&&&&&&&&&&if (gameObj == null) {&&&&&&&&&&&&&&&&Debug.LogError ("不合法的场景:场景没有scene_root根节点!!");&&&&&&&&&&&&&&&&continue;&&&&&&&&&&&&}&&&&&&&&&&&&&slms = gameObj.GetComponent&SceneLightMapSetting&();&&&&&&&&&&&&if(slms == null){&&&&&&&&&&&&&&&&slms = gameObj.AddComponent&SceneLightMapSetting&();&&&&&&&&&&&&}&&&&&&&&&&&&&Renderer[] savers = Transform.FindObjectsOfType&Renderer&();&&&&&&&&&&&&foreach(Renderer s in savers)&&&&&&&&&&&&{&&&&&&&&&&&&&&&&if(s.lightmapIndex != -1){&&&&&&&&&&&&&&&&&&&&rlms = s.gameObject.GetComponent&RendererLightMapSetting&();&&&&&&&&&&&&&&&&&&&&if(rlms == null){&&&&&&&&&&&&&&&&&&&&&&&&rlms = s.gameObject.AddComponent&RendererLightMapSetting&();&&&&&&&&&&&&&&&&&&&&}&&&&&&&&&&&&&&&&}&&&&&&&&&&&&}&&&&&&&&&&&&&slms.SaveSettings();&&&&&&&&&&&&&EditorApplication.SaveScene();&&&&&&&&&&&&&Debug.Log(string.Format("场景{0}的光照贴图信息保存完成", assetObj.name));&&&&&&&&}&&&&&&&&EditorApplication.SaveAssets();&&&&}}
没截图从觉得少点什么,来,上图,先打开一个被烘培过的场景,场景根节点为scene_root,被烘培的gameobjet是地板、一颗小草、带logo的立方体:
然后使用工具给场景里面的相关节点挂脚本存数据:
把场景根节点scene_root拖出来做成prefab,然后删掉场景里面的scene_root,再把scene_root.prefab拖进场景里面:
此时模型是丢失了光照数据的,原因截图已说明。接着运行场景:
模型的光照又回来啦,原因截图已说明。
微信扫一扫,打赏作者吧~
本文固定链接:
转载请注明:
作者:雨Lu尧
我是一枚玩家,也是一颗游戏开发者
您可能还会对这些文章感兴趣!

我要回帖

更多关于 unity场景导出max 的文章

 

随机推荐