下一篇: Lightmap之Terrain和Lightmap切割
接上一篇,LightMap之动态切换LightMap模拟白天夜晚 ,介绍了最基本的动态切换。现在问题来了,当场景比较大的时候,我们通常不是一次性把所有的物件都加载,哪怕这个物件是静态的,比如场景中不动的建筑。如果我们仅仅是烘焙后场景物件保存成prefab,那么我们在加载后,prefab是没有烘焙信息的。最后出现的效果如下,显然不是预期。Cube 1 和 Plane 1是之前烘焙完后保存的prafab。
好在有解决方案:在每个需要烘焙的场景物件上挂一个脚本,当场景烘培结束后,把每个物件的烘焙信息记录在脚本上,然后把整个物件连同脚本一起保存成prefab。运行时直接把prefab加载就完成了。下图就是正确的预期结果。

那这个脚本上记录什么东西呢?有两个很重要的数据就是index和offsetScale,这些信息都能从MeshRenderer中取到
lightmapIndex 和 lightmapScaleOffset。除了这两者之外,还有具体的Lightmap烘焙贴图,lightmaps 和lightmaps2。因为这些是带在场景信息中的,因此需要单独拉出来保存。就是Lightmap-0_comp_light和Lightmap-0_comp_dir,再下面的小图是把他们保存到Resource中的截图。相当于index和offsetScale记录的是物件在具体的Lightmap烘焙贴图的信息。换句话说,Lightmap烘焙贴图是整个场景的,每个物件的烘焙信息肯定在这之中,至于在这中的位置就是index和offsetScale记录的。


当然,保存这些信息需要脚本的支持。完整代码下载 两个核心的函数如下:
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].lightmapColor;
Texture2D lightmap2 = LightmapSettings.lightmaps[renderer.lightmapIndex].lightmapDir;
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);
lightmap_Remap.lightmap1 = GetLightmapAsset(filename + "_comp_dir.png", resourcePath + "_dir", originalLightmapIndex, lightmap2);
}
sceneLightmaps.Add(lightmap_Remap);
newIndex = sceneLightmaps.Count - 1;
}
return newIndex;
}