//Source: https://github.com/Ayfel/PrefabLightmapping using UnityEngine; using UnityEditor; using System.Collections; using System.Collections.Generic; using UnityEngine.SceneManagement; [ExecuteAlways] public class PrefabLightmapData : MonoBehaviour { [System.Serializable] struct RendererInfo { public Renderer renderer; public int lightmapIndex; public Vector4 lightmapOffsetScale; } [System.Serializable] struct LightInfo { public Light light; public int lightmapBaketype; public int mixedLightingMode; } [SerializeField] RendererInfo[] m_RendererInfo; [SerializeField] Texture2D[] m_Lightmaps; [SerializeField] Texture2D[] m_LightmapsDir; [SerializeField] Texture2D[] m_ShadowMasks; [SerializeField] LightInfo[] m_LightInfo; void Awake() { Init(); } public void Init() { if (m_RendererInfo == null || m_RendererInfo.Length == 0) return; var lightmaps = LightmapSettings.lightmaps; int[] offsetsindexes = new int[m_Lightmaps.Length]; int counttotal = lightmaps.Length; List combinedLightmaps = new List(); for (int i = 0; i < m_Lightmaps.Length; i++) { bool exists = false; for (int j = 0; j < lightmaps.Length; j++) { if (m_Lightmaps[i] == lightmaps[j].lightmapColor) { exists = true; offsetsindexes[i] = j; } } if (!exists) { offsetsindexes[i] = counttotal; var newlightmapdata = new LightmapData { lightmapColor = m_Lightmaps[i], lightmapDir = m_LightmapsDir.Length == m_Lightmaps.Length ? m_LightmapsDir[i] : default(Texture2D), shadowMask = m_ShadowMasks.Length == m_Lightmaps.Length ? m_ShadowMasks[i] : default(Texture2D), }; combinedLightmaps.Add(newlightmapdata); counttotal += 1; } } var combinedLightmaps2 = new LightmapData[counttotal]; lightmaps.CopyTo(combinedLightmaps2, 0); combinedLightmaps.ToArray().CopyTo(combinedLightmaps2, lightmaps.Length); bool directional=true; foreach(Texture2D t in m_LightmapsDir) { if (t == null) { directional = false; break; } } LightmapSettings.lightmapsMode = (m_LightmapsDir.Length == m_Lightmaps.Length && directional) ? LightmapsMode.CombinedDirectional : LightmapsMode.NonDirectional; ApplyRendererInfo(m_RendererInfo, offsetsindexes, m_LightInfo); LightmapSettings.lightmaps = combinedLightmaps2; } void OnEnable() { SceneManager.sceneLoaded += OnSceneLoaded; } // called second void OnSceneLoaded(Scene scene, LoadSceneMode mode) { Init(); } // called when the game is terminated void OnDisable() { SceneManager.sceneLoaded -= OnSceneLoaded; } static void ApplyRendererInfo(RendererInfo[] infos, int[] lightmapOffsetIndex, LightInfo[] lightsInfo) { for (int i = 0; i < infos.Length; i++) { var info = infos[i]; info.renderer.lightmapIndex = lightmapOffsetIndex[info.lightmapIndex]; info.renderer.lightmapScaleOffset = info.lightmapOffsetScale; // You have to release shaders. Material[] mat = info.renderer.sharedMaterials; for (int j = 0; j < mat.Length; j++) { if (mat[j] != null && Shader.Find(mat[j].shader.name) != null) mat[j].shader = Shader.Find(mat[j].shader.name); } } for (int i = 0; i < lightsInfo.Length; i++) { LightBakingOutput bakingOutput = new LightBakingOutput(); bakingOutput.isBaked = true; bakingOutput.lightmapBakeType = (LightmapBakeType)lightsInfo[i].lightmapBaketype; bakingOutput.mixedLightingMode = (MixedLightingMode)lightsInfo[i].mixedLightingMode; lightsInfo[i].light.bakingOutput = bakingOutput; } } #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(); foreach (var instance in prefabs) { var gameObject = instance.gameObject; var rendererInfos = new List(); var lightmaps = new List(); var lightmapsDir = new List(); var shadowMasks = new List(); var lightsInfos = new List(); GenerateLightmapInfo(gameObject, rendererInfos, lightmaps, lightmapsDir, shadowMasks, lightsInfos); instance.m_RendererInfo = rendererInfos.ToArray(); instance.m_Lightmaps = lightmaps.ToArray(); instance.m_LightmapsDir = lightmapsDir.ToArray(); instance.m_LightInfo = lightsInfos.ToArray(); instance.m_ShadowMasks = shadowMasks.ToArray(); #if UNITY_2018_3_OR_NEWER var targetPrefab = PrefabUtility.GetCorrespondingObjectFromOriginalSource(instance.gameObject) as GameObject; if (targetPrefab != null) { GameObject root = PrefabUtility.GetOutermostPrefabInstanceRoot(instance.gameObject);// 根结点 //如果当前预制体是是某个嵌套预制体的一部分(IsPartOfPrefabInstance) if (root != null) { GameObject rootPrefab = PrefabUtility.GetCorrespondingObjectFromSource(instance.gameObject); string rootPath = AssetDatabase.GetAssetPath(rootPrefab); //打开根部预制体 PrefabUtility.UnpackPrefabInstanceAndReturnNewOutermostRoots(root, PrefabUnpackMode.OutermostRoot); try { //Apply各个子预制体的改变 PrefabUtility.ApplyPrefabInstance(instance.gameObject, InteractionMode.AutomatedAction); } catch { } finally { //重新更新根预制体 PrefabUtility.SaveAsPrefabAssetAndConnect(root, rootPath, InteractionMode.AutomatedAction); } } else { PrefabUtility.ApplyPrefabInstance(instance.gameObject, InteractionMode.AutomatedAction); } } #else var targetPrefab = UnityEditor.PrefabUtility.GetPrefabParent(gameObject) as GameObject; if (targetPrefab != null) { //UnityEditor.Prefab UnityEditor.PrefabUtility.ReplacePrefab(gameObject, targetPrefab); } #endif } } static void GenerateLightmapInfo(GameObject root, List rendererInfos, List lightmaps, List lightmapsDir, List shadowMasks, List lightsInfo) { var renderers = root.GetComponentsInChildren(); foreach (MeshRenderer renderer in renderers) { if (renderer.lightmapIndex != -1) { RendererInfo info = new RendererInfo(); info.renderer = renderer; if (renderer.lightmapScaleOffset != Vector4.zero) { //1ibrium's pointed out this issue : https://docs.unity3d.com/ScriptReference/Renderer-lightmapIndex.html if(renderer.lightmapIndex < 0 || renderer.lightmapIndex == 0xFFFE) continue; info.lightmapOffsetScale = renderer.lightmapScaleOffset; Texture2D lightmap = LightmapSettings.lightmaps[renderer.lightmapIndex].lightmapColor; Texture2D lightmapDir = LightmapSettings.lightmaps[renderer.lightmapIndex].lightmapDir; Texture2D shadowMask = LightmapSettings.lightmaps[renderer.lightmapIndex].shadowMask; info.lightmapIndex = lightmaps.IndexOf(lightmap); if (info.lightmapIndex == -1) { info.lightmapIndex = lightmaps.Count; lightmaps.Add(lightmap); lightmapsDir.Add(lightmapDir); shadowMasks.Add(shadowMask); } rendererInfos.Add(info); } } } var lights = root.GetComponentsInChildren(true); foreach (Light l in lights) { LightInfo lightInfo = new LightInfo(); lightInfo.light = l; lightInfo.lightmapBaketype = (int)l.lightmapBakeType; #if UNITY_2020_1_OR_NEWER lightInfo.mixedLightingMode = (int)UnityEditor.Lightmapping.lightingSettings.mixedBakeMode; #elif UNITY_2018_1_OR_NEWER lightInfo.mixedLightingMode = (int)UnityEditor.LightmapEditorSettings.mixedBakeMode; #else lightInfo.mixedLightingMode = (int)l.bakingOutput.lightmapBakeType; #endif lightsInfo.Add(lightInfo); } } #endif }