平时在项目开发过程中,要加载游戏对象时,经常使用加载一个prefab来代替加载整个场景。做法是:把场景里的所有对象都放置到一个根GameObject上,然后将这个GameObject保存成为一个Prefab。然后再在代码中加载这个prefab来达到生成切换场景的作用。
但是,如果如果场景中的物体是经过烘焙了的,那保存的prefab会丢失LightingMap信息。此时,我们把场景中的物体保存成prefab后,再进行加载,加载出来的画面表现与原来场景里的画面差距很大。因为物体身上的光照信息都丢失了。
因此,此时我们要做的是:在烘焙的时候,使用一个脚本保存住所有烘焙物体的光照图信息。具体做法的传送门如下:
http://blog.csdn.net/jbl20078/article/details/76682690
如果上面就解决问题了,那就图样图森破了。
因为美术在制作场景图效果的时候往往是在一个新建的场景烘焙的,而我们最终在程序里真正要使用的场景往往是在另外一个场景。当我们把处理过的prefab加载到新场景的时候,有可能会出现效果依然和美术制作的场景效果差距甚远。
(敲黑板)这是因为我们实际在运行中的场景有可能从来就没有进行烘焙操作过,因此我们在加载这些具有烘焙信息的prefab时会出现错误。此时,我们只要对当前运行的场景任意的进行一次烘焙操作(随便烘焙个阿猫阿狗就可以了),然后此时再将
prefab加载到场景中,就会发现效果完美无瑕。
最后,附上保存烘焙光照图信息的完整代码(此时我所用的Unity版本为2017.3.0):
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[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;
void Awake()
{
if (m_RendererInfo == null || m_RendererInfo.Length == 0)
return;
var lightmaps = LightmapSettings.lightmaps;
var combinedLightmaps = new LightmapData[lightmaps.Length + m_Lightmaps.Length];
lightmaps.CopyTo(combinedLightmaps, 0);
for (int i = 0; i < m_Lightmaps.Length; i++)
{
//combinedLightmaps[i + lightmaps.Length] = new LightmapData();
//combinedLightmaps[i + lightmaps.Length].lightmapFar = m_Lightmaps[i];
combinedLightmaps[i + lightmaps.Length] = new LightmapData();
combinedLightmaps[i + lightmaps.Length].lightmapColor = m_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];
info.renderer.lightmapIndex = info.lightmapIndex + lightmapOffsetIndex;
info.renderer.lightmapScaleOffset = info.lightmapOffsetScale;
}
}
#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.");
return;
}
UnityEditor.Lightmapping.Bake();
PrefabLightmapData[] prefabs = FindObjectsOfType<PrefabLightmapData>();
foreach (var instance in prefabs)
{
var gameObject = instance.gameObject;
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 GameObject;
if (targetPrefab != null)
{
//UnityEditor.Prefab
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 = renderer;
info.lightmapOffsetScale = renderer.lightmapScaleOffset;
Texture2D lightmap = LightmapSettings.lightmaps[renderer.lightmapIndex].lightmapColor;
info.lightmapIndex = lightmaps.IndexOf(lightmap);
if (info.lightmapIndex == -1)
{
info.lightmapIndex = lightmaps.Count;
lightmaps.Add(lightmap);
}
rendererInfos.Add(info);
}
}
}
#endif
}