using UnityEngine; using UnityEngine.SceneManagement; using System; using System.Collections.Generic; using UnityEngine.Rendering; using System.Collections; #if UNITY_EDITOR using UnityEditor; #endif [ExecuteInEditMode] public class LevelLightmapData : MonoBehaviour { [System.Serializable] public class SphericalHarmonics { public float[] coefficients = new float[27]; } [System.Serializable] public class RendererInfo { public Renderer renderer; public int lightmapIndex; public Vector4 lightmapOffsetScale; } [System.Serializable] public class LightingScenarioData { public RendererInfo[] rendererInfos; public Texture2D[] lightmaps; public Texture2D[] lightmapsDir; public Texture2D[] shadowMasks; public LightmapsMode lightmapsMode; public SphericalHarmonics[] lightProbes; public bool hasRealtimeLights; } public bool latestBuildHasReltimeLights; public bool allowLoadingLightingScenes = true; [SerializeField] List lightingScenariosData; #if UNITY_EDITOR [SerializeField] public List lightingScenariosScenes; #endif [SerializeField] public String[] lightingScenesNames = new string[1]; public int currentLightingScenario = -1; public int previousLightingScenario = -1; private Coroutine m_SwitchSceneCoroutine; [SerializeField] public int lightingScenariosCount; //TODO : enable logs only when verbose enabled public bool verbose = false; private List lightProbesRuntime = new List(); public void LoadLightingScenario(int index) { if(index != currentLightingScenario) { previousLightingScenario = currentLightingScenario == -1 ? index : currentLightingScenario; currentLightingScenario = index; LightmapSettings.lightmapsMode = lightingScenariosData[index].lightmapsMode; if(allowLoadingLightingScenes) m_SwitchSceneCoroutine = StartCoroutine(SwitchSceneCoroutine(lightingScenesNames[previousLightingScenario], lightingScenesNames[currentLightingScenario])); var newLightmaps = LoadLightmaps(index); ApplyRendererInfo(lightingScenariosData[index].rendererInfos); LightmapSettings.lightmaps = newLightmaps; LoadLightProbes(currentLightingScenario); } } private void Start() { PrepareLightProbeArrays(); } private void PrepareLightProbeArrays() { for (int x = 0; x < lightingScenariosCount; x++) { lightProbesRuntime.Add(DeserializeLightProbes(x)); } } private SphericalHarmonicsL2[] DeserializeLightProbes(int index) { var sphericalHarmonicsArray = new SphericalHarmonicsL2[lightingScenariosData[index].lightProbes.Length]; for (int i = 0; i < lightingScenariosData[index].lightProbes.Length; i++) { var sphericalHarmonics = new SphericalHarmonicsL2(); // j is coefficient for (int j = 0; j < 3; j++) { //k is channel ( r g b ) for (int k = 0; k < 9; k++) { sphericalHarmonics[j, k] = lightingScenariosData[index].lightProbes[i].coefficients[j * 9 + k]; } } sphericalHarmonicsArray[i] = sphericalHarmonics; } return sphericalHarmonicsArray; } IEnumerator SwitchSceneCoroutine(string sceneToUnload, string sceneToLoad) { AsyncOperation unloadop = null; AsyncOperation loadop = null; if (sceneToUnload != null && sceneToUnload != string.Empty && sceneToUnload != sceneToLoad) { unloadop = SceneManager.UnloadSceneAsync(sceneToUnload); while (!unloadop.isDone) { yield return new WaitForEndOfFrame(); } } if(sceneToLoad != null && sceneToLoad != string.Empty && sceneToLoad != "") { loadop = SceneManager.LoadSceneAsync(sceneToLoad, LoadSceneMode.Additive); while ((!loadop.isDone || loadop == null)) { yield return new WaitForEndOfFrame(); } SceneManager.SetActiveScene(SceneManager.GetSceneByName(sceneToLoad)); } LoadLightProbes(currentLightingScenario); } LightmapData[] LoadLightmaps(int index) { if (lightingScenariosData[index].lightmaps == null || lightingScenariosData[index].lightmaps.Length == 0) { Debug.LogWarning("No lightmaps stored in scenario " + index); return null; } var newLightmaps = new LightmapData[lightingScenariosData[index].lightmaps.Length]; for (int i = 0; i < newLightmaps.Length; i++) { newLightmaps[i] = new LightmapData(); newLightmaps[i].lightmapColor = lightingScenariosData[index].lightmaps[i]; if (lightingScenariosData[index].lightmapsMode != LightmapsMode.NonDirectional) { newLightmaps[i].lightmapDir = lightingScenariosData[index].lightmapsDir[i]; } if (lightingScenariosData[index].shadowMasks.Length > 0) { newLightmaps[i].shadowMask = lightingScenariosData[index].shadowMasks[i]; } } return newLightmaps; } public void ApplyRendererInfo(RendererInfo[] infos) { try { Terrain terrain = FindObjectOfType(); int i = 0; if (terrain != null) { terrain.lightmapIndex = infos[i].lightmapIndex; terrain.lightmapScaleOffset = infos[i].lightmapOffsetScale; i++; } for (int j = i; j < infos.Length; j++) { RendererInfo info = infos[j]; //if (info.renderer == null) //continue; info.renderer.lightmapIndex = infos[j].lightmapIndex; if (!info.renderer.isPartOfStaticBatch) { info.renderer.lightmapScaleOffset = infos[j].lightmapOffsetScale; } if (info.renderer.isPartOfStaticBatch && verbose == true && Application.isEditor) { Debug.Log("Object " + info.renderer.gameObject.name + " is part of static batch, skipping lightmap offset and scale."); } } } catch (Exception e) { Debug.LogError("Error in ApplyRendererInfo:" + e.GetType().ToString()); } } public void LoadLightProbes(int index) { if (Application.isEditor && !Application.isPlaying) { PrepareLightProbeArrays(); } try { LightmapSettings.lightProbes.bakedProbes = lightProbesRuntime[index]; } catch { Debug.LogWarning("Warning, error when trying to load lightprobes for scenario " + index); } } public void StoreLightmapInfos(int index) { var newLightingScenarioData = new LightingScenarioData (); var newRendererInfos = new List(); var newLightmapsTextures = new List(); var newLightmapsTexturesDir = new List(); var newLightmapsMode = new LightmapsMode(); var newSphericalHarmonicsList = new List(); var newLightmapsShadowMasks = new List(); newLightmapsMode = LightmapSettings.lightmapsMode; GenerateLightmapInfo(gameObject, newRendererInfos, newLightmapsTextures, newLightmapsTexturesDir, newLightmapsShadowMasks, newLightmapsMode); newLightingScenarioData.lightmapsMode = newLightmapsMode; newLightingScenarioData.lightmaps = newLightmapsTextures.ToArray(); if (newLightmapsMode != LightmapsMode.NonDirectional) { newLightingScenarioData.lightmapsDir = newLightmapsTexturesDir.ToArray(); } //Mixed or realtime support newLightingScenarioData.hasRealtimeLights = latestBuildHasReltimeLights; newLightingScenarioData.shadowMasks = newLightmapsShadowMasks.ToArray(); newLightingScenarioData.rendererInfos = newRendererInfos.ToArray(); var scene_LightProbes = new SphericalHarmonicsL2[LightmapSettings.lightProbes.bakedProbes.Length]; scene_LightProbes = LightmapSettings.lightProbes.bakedProbes; for (int i = 0; i < scene_LightProbes.Length; i++) { var SHCoeff = new SphericalHarmonics(); // j is coefficient for (int j = 0; j < 3; j++) { //k is channel ( r g b ) for (int k = 0; k < 9; k++) { SHCoeff.coefficients[j*9+k] = scene_LightProbes[i][j, k]; } } newSphericalHarmonicsList.Add(SHCoeff); } newLightingScenarioData.lightProbes = newSphericalHarmonicsList.ToArray (); if (lightingScenariosData.Count < index + 1) { lightingScenariosData.Insert(index, newLightingScenarioData); } else { lightingScenariosData[index] = newLightingScenarioData; } lightingScenariosCount = lightingScenariosData.Count; if (lightingScenesNames == null || lightingScenesNames.Length< lightingScenariosCount) { lightingScenesNames = new string[lightingScenariosCount]; } } static void GenerateLightmapInfo(GameObject root, List newRendererInfos, List newLightmapsLight, List newLightmapsDir, List newLightmapsShadow, LightmapsMode newLightmapsMode) { Terrain terrain = FindObjectOfType(); if (terrain != null && terrain.lightmapIndex != -1 && terrain.lightmapIndex != 65534) { RendererInfo terrainRendererInfo = new RendererInfo(); terrainRendererInfo.lightmapOffsetScale = terrain.lightmapScaleOffset; Texture2D lightmaplight = LightmapSettings.lightmaps[terrain.lightmapIndex].lightmapColor; terrainRendererInfo.lightmapIndex = newLightmapsLight.IndexOf(lightmaplight); if (terrainRendererInfo.lightmapIndex == -1) { terrainRendererInfo.lightmapIndex = newLightmapsLight.Count; newLightmapsLight.Add(lightmaplight); } if (newLightmapsMode != LightmapsMode.NonDirectional) { Texture2D lightmapdir = LightmapSettings.lightmaps[terrain.lightmapIndex].lightmapDir; terrainRendererInfo.lightmapIndex = newLightmapsDir.IndexOf(lightmapdir); if (terrainRendererInfo.lightmapIndex == -1) { terrainRendererInfo.lightmapIndex = newLightmapsDir.Count; newLightmapsDir.Add(lightmapdir); } } if (LightmapSettings.lightmaps[terrain.lightmapIndex].shadowMask != null) { Texture2D lightmapShadow = LightmapSettings.lightmaps[terrain.lightmapIndex].shadowMask; terrainRendererInfo.lightmapIndex = newLightmapsShadow.IndexOf(lightmapShadow); if (terrainRendererInfo.lightmapIndex == -1) { terrainRendererInfo.lightmapIndex = newLightmapsShadow.Count; newLightmapsShadow.Add(lightmapShadow); } } newRendererInfos.Add(terrainRendererInfo); if (Application.isEditor) Debug.Log("Terrain lightmap stored in" + terrainRendererInfo.lightmapIndex.ToString()); } var renderers = FindObjectsOfType(typeof(Renderer)); if (Application.isEditor) Debug.Log("stored info for " + renderers.Length + " meshrenderers"); foreach (Renderer renderer in renderers) { if (renderer.lightmapIndex != -1 && renderer.lightmapIndex != 65534) { RendererInfo info = new RendererInfo(); info.renderer = renderer; info.lightmapOffsetScale = renderer.lightmapScaleOffset; Texture2D lightmaplight = LightmapSettings.lightmaps[renderer.lightmapIndex].lightmapColor; info.lightmapIndex = newLightmapsLight.IndexOf(lightmaplight); if (info.lightmapIndex == -1) { info.lightmapIndex = newLightmapsLight.Count; newLightmapsLight.Add(lightmaplight); } if (newLightmapsMode != LightmapsMode.NonDirectional) { Texture2D lightmapdir = LightmapSettings.lightmaps[renderer.lightmapIndex].lightmapDir; info.lightmapIndex = newLightmapsDir.IndexOf(lightmapdir); if (info.lightmapIndex == -1) { info.lightmapIndex = newLightmapsDir.Count; newLightmapsDir.Add(lightmapdir); } } if (LightmapSettings.lightmaps[renderer.lightmapIndex].shadowMask != null) { Texture2D lightmapShadow = LightmapSettings.lightmaps[renderer.lightmapIndex].shadowMask; info.lightmapIndex = newLightmapsShadow.IndexOf(lightmapShadow); if (info.lightmapIndex == -1) { info.lightmapIndex = newLightmapsShadow.Count; newLightmapsShadow.Add(lightmapShadow); } } newRendererInfos.Add(info); } } } }