unity版本为2021.8
预制体不能携带光照贴图信息,只能我们自己准备了
多方查找加自己摸索终于找到了适合新版本的解决方案,直接贴代码
将这个脚本挂到预制体的最上级
using System.Collections;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
[System.Serializable]
public struct RendererInfo
{
public Renderer renderer;//网格物体 网格和地形的光照信息是分开的
public Terrain terrain;//地形
public int lightmapIndex;
public Vector4 lightmapScaleScaleOffset;
}
//记录光照贴图的信息
public class PrefabLightmapData : MonoBehaviour
{
public RendererInfo[] m_RendererInfo;
public Texture2D[] m_Lightmaps_light;//颜色贴图
public Texture2D[] m_Lightmaps_dir;//方向贴图
public Texture2D[] m_Lightmaps_shadowmask;//阴影贴图
private void Awake()
{
RebuildLight();
}
public void RebuildLight()
{
if (m_RendererInfo == null || m_RendererInfo.Length == 0) return;
LightmapData[] lightmapDataArray = new LightmapData[m_Lightmaps_light.Length];
for (int i = 0; i < m_Lightmaps_light.Length; i++)
{
LightmapData lightmapData = new LightmapData();
if (i < m_Lightmaps_light.Length) lightmapData.lightmapColor = m_Lightmaps_light[i];
if (i < m_Lightmaps_dir.Length) lightmapData.lightmapDir = m_Lightmaps_dir[i];
if (i < m_Lightmaps_shadowmask.Length) lightmapData.shadowMask = m_Lightmaps_shadowmask[i];
lightmapDataArray[i] = lightmapData;
}
//为预制体的物体应用光照贴图
ApplyRendererInfo(m_RendererInfo);
LightmapSettings.lightmaps = lightmapDataArray;//将光照贴图应用到Untiy
}
//应用光照贴图信息到重建的预制体
private void ApplyRendererInfo(RendererInfo[] rendererInfoArray)
{
for (int i = 0; i < rendererInfoArray.Length; i++)
{
RendererInfo rendererInfo = rendererInfoArray[i];
if (rendererInfo.renderer != null)
{
rendererInfo.renderer.lightmapIndex = rendererInfo.lightmapIndex;
rendererInfo.renderer.lightmapScaleOffset = rendererInfo.lightmapScaleScaleOffset;
}
else if (rendererInfo.terrain != null)
{
rendererInfo.terrain.lightmapIndex = rendererInfo.lightmapIndex;
rendererInfo.terrain.lightmapScaleOffset = rendererInfo.lightmapScaleScaleOffset;
}
}
}
}
//自定义inspector面板
[CustomEditor(typeof(PrefabLightmapData))]
public class PrefabLightmapData_Inspector : Editor
{
//重写OnInspectorGUI类(刷新Inspector面板)
public override void OnInspectorGUI()
{
//继承基类方法
base.OnInspectorGUI();
PrefabLightmapData myScript = (PrefabLightmapData)target;
//绘制Button
Rect rect = new Rect(0, 0,100,50);
if (GUILayout.Button("重新构建烘焙光照"))
{
myScript.RebuildLight();
}
}
}
在使用下方的脚本完成烘焙后,脚本将自动记录所有模型和地形的烘焙信息,并在运行后自动重建光照贴图,如果我们需要在不运行时查看光照贴图效果,可以手动点击“重新构建烘焙光照”的按钮
重写烘焙,烘焙完成后自动准备重建光照贴图所需要的信息
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public static class BackeLightMap
{
[UnityEditor.MenuItem("Tools/光照/烘焙光照贴图")]
private 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 = Object.FindObjectsOfType<PrefabLightmapData>();
foreach (var prefabInScene in prefabs)
{
GameObject scenePrefab = prefabInScene.gameObject;
List<RendererInfo> rendererInfos = new List<RendererInfo>();//重建光照贴图时需要的信息
List<Texture2D> lightmaps_light = new List<Texture2D>();//所有的光照贴图
List<Texture2D> lightmaps_dir = new List<Texture2D>();//所有的光照贴图
List<Texture2D> lightmaps_shadowmask = new List<Texture2D>();//所有的光照贴图
GenerateLightmapInfo(scenePrefab, rendererInfos, lightmaps_light, lightmaps_dir, lightmaps_shadowmask);//获取当前物体的光照贴图信息和光照贴图
//为光照贴图信息和光照贴图赋值
prefabInScene.m_RendererInfo = rendererInfos.ToArray();
prefabInScene.m_Lightmaps_light = lightmaps_light.ToArray();
prefabInScene.m_Lightmaps_dir = lightmaps_dir.ToArray();
prefabInScene.m_Lightmaps_shadowmask = lightmaps_shadowmask.ToArray();
//替换掉已经保存的预制体
GameObject sourcePrefab = UnityEditor.PrefabUtility.GetPrefabParent(prefabInScene) as GameObject;
//GameObject sourcePrefab = UnityEditor.PrefabUtility.GetCorrespondingObjectFromSource(scenePrefab);
if (sourcePrefab != null)
{
UnityEditor.PrefabUtility.ReplacePrefab(scenePrefab, sourcePrefab);
}
}
}
//点击按钮生成光照贴图信息
private static void GenerateLightmapInfo(GameObject root, List<RendererInfo> rendererInfoList, List<Texture2D> lightmaps_light, List<Texture2D> lightmaps_dir, List<Texture2D> lightmaps_shadowmask)
{
//找到这个物体的所有网格
MeshRenderer[] renderers = root.GetComponentsInChildren<MeshRenderer>();
//遍历网格
foreach (MeshRenderer meshRenderer in renderers)
{
if (meshRenderer.lightmapIndex != -1)
{
//收集光照贴图信息
RendererInfo rendererInfo = new RendererInfo();
rendererInfo.renderer = meshRenderer;
rendererInfo.lightmapIndex = meshRenderer.lightmapIndex;
rendererInfo.lightmapScaleScaleOffset = meshRenderer.lightmapScaleOffset;
//收集光照贴图
//颜色贴图
Texture2D lightmap_light = LightmapSettings.lightmaps[meshRenderer.lightmapIndex].lightmapColor;
AddLightMapToCheach(lightmaps_light, lightmap_light);
//方向贴图
Texture2D lightmap_dir = LightmapSettings.lightmaps[meshRenderer.lightmapIndex].lightmapDir;
AddLightMapToCheach(lightmaps_dir, lightmap_dir);
//shadowmask
Texture2D lightmap_shadowmask = LightmapSettings.lightmaps[meshRenderer.lightmapIndex].shadowMask;
AddLightMapToCheach(lightmaps_shadowmask,lightmap_shadowmask);
//光照信息
rendererInfoList.Add(rendererInfo);
}
}
//找到这个物体的所有网格
Terrain[] terrains = root.GetComponentsInChildren<Terrain>();
//遍历网格
foreach (Terrain terrain in terrains)
{
if (terrain.lightmapIndex != -1)
{
//收集光照贴图信息
RendererInfo rendererInfo = new RendererInfo();
rendererInfo.terrain = terrain;
rendererInfo.lightmapIndex = terrain.lightmapIndex;
rendererInfo.lightmapScaleScaleOffset = terrain.lightmapScaleOffset;
//收集光照贴图
//颜色贴图
Texture2D lightmap_light = LightmapSettings.lightmaps[terrain.lightmapIndex].lightmapColor;
AddLightMapToCheach(lightmaps_light, lightmap_light);
//方向贴图
Texture2D lightmap_dir = LightmapSettings.lightmaps[terrain.lightmapIndex].lightmapDir;
AddLightMapToCheach(lightmaps_dir, lightmap_dir);
//shadowmask
Texture2D lightmap_shadowmask = LightmapSettings.lightmaps[terrain.lightmapIndex].shadowMask;
AddLightMapToCheach(lightmaps_shadowmask, lightmap_shadowmask);
//光照信息
rendererInfoList.Add(rendererInfo);
}
}
}
//将一个光照贴图添加进缓存
private static void AddLightMapToCheach(List<Texture2D> list,Texture2D texture)
{
if (texture == null) return;
int index = list.IndexOf(texture);//查找已有的集合里有没有这个元素,如果没有,返回-1
if (index == -1)
{
list.Add(texture);
}
}
}
工具栏里会出现烘焙按钮,点击烘焙光照贴图,不要再用Unity自己的烘焙了,为场景中所有挂载了PrefabLightmapData 的预制体烘焙光照
使用方法,先给预制体挂脚本,然后点Tools里的烘焙光照,然后删掉场景的预制体,然后拖一个新的预制体出来,然后运行场景即可