public static void UnloadScene(ftLightmapsStorage storage) { if (lightmapRefCount == null) { return; } if (storage.idremap == null) { return; } //int idx = loadedStorages.IndexOf(storage); //if (idx >= 0) loadedStorages.RemoveAt(idx); LightmapData[] existingLmaps = null; List <LightmapAdditionalData> existingLmapsAdditional = null; //bool rebuild = false; for (int i = 0; i < storage.idremap.Length; i++) { int currentID = storage.idremap[i]; // just never unload the 1st lightmap to prevent Unity from losing LM encoding settings // remapping all IDs at runtime would introduce a perf hiccup if (currentID == 0) { continue; } if (lightmapRefCount.Count <= currentID) { continue; } lightmapRefCount[currentID]--; //Debug.LogError("rem: "+currentID+" "+lightmapRefCount[currentID]); if (lightmapRefCount[currentID] == 0) { if (existingLmaps == null) { existingLmaps = LightmapSettings.lightmaps; } if (existingLmaps.Length > currentID) { existingLmaps[currentID].lightmapColor = null; existingLmaps[currentID].lightmapDir = null; existingLmaps[currentID].shadowMask = null; if (existingLmapsAdditional == null) { existingLmapsAdditional = globalMapsAdditional; } if (existingLmapsAdditional != null && existingLmapsAdditional.Count > currentID) { var emptyEntry = new LightmapAdditionalData(); existingLmapsAdditional[currentID] = emptyEntry; } } //if (currentID == 0) rebuild = true; } } /* * // If the first lightmap was unloaded, we need to rebuild the lightmap array * // because Unity uses 1st lightmap to determine encoding * if (rebuild) * { * int newLength = 0; * for(int i=0; i<existingLmaps.Length; i++) * { * if (existingLmaps[i].lightmapColor != null) newLength++; * } * var existingLmaps2 = new LightmapData[newLength]; * int ctr = 0; * for(int i=0; i<existingLmaps.Length; i++) * { * if (existingLmaps[i].lightmapColor != null) * { * existingLmaps2[ctr] = existingLmaps[i]; * ctr++; * } * } * existingLmaps = existingLmaps2; * * for(int i=0; i<) * } */ if (existingLmaps != null) { LightmapSettings.lightmaps = existingLmaps; } }
public static void RefreshScene(Scene scene, ftLightmapsStorage storage = null, bool updateNonBaked = false) { var sceneCount = SceneManager.sceneCount; if (globalMapsAdditional == null) { globalMapsAdditional = new List <LightmapAdditionalData>(); } var lmaps = new List <LightmapData>(); var lmapsAdditional = new List <LightmapAdditionalData>(); var existingLmaps = LightmapSettings.lightmaps; var existingLmapsAdditional = globalMapsAdditional; // Acquire storage if (storage == null) { if (!scene.isLoaded) { //Debug.LogError("dbg: Scene not loaded"); return; } SceneManager.SetActiveScene(scene); var go = FindInScene("!ftraceLightmaps", scene); if (go == null) { //Debug.LogError("dbg: no storage"); return; } storage = go.GetComponent <ftLightmapsStorage>(); if (storage == null) { //Debug.LogError("dbg: no storage 2"); return; } } if (storage.idremap == null || storage.idremap.Length != storage.maps.Count) { storage.idremap = new int[storage.maps.Count]; } // Decide which global engine lightmapping mode to use // TODO: allow mixing different modes directionalMode = storage.dirMaps.Count != 0; bool patchedDirection = false; LightmapSettings.lightmapsMode = directionalMode ? LightmapsMode.CombinedDirectional : LightmapsMode.NonDirectional; // Set dummy directional tex for non-directional lightmaps in directional mode if (directionalMode) { for (int i = 0; i < existingLmaps.Length; i++) { if (directionalMode && existingLmaps[i].lightmapDir == null) { var lm = existingLmaps[i]; lm.lightmapDir = GetEmptyDirectionTex(storage); existingLmaps[i] = lm; patchedDirection = true; } } } // Detect if changes to lightmap array are necessary bool sameArray = false; if (existingLmaps.Length == storage.maps.Count) { sameArray = true; for (int i = 0; i < storage.maps.Count; i++) { if (existingLmaps[i].lightmapColor != storage.maps[i]) { sameArray = false; break; } if (storage.rnmMaps0.Count > i && (existingLmapsAdditional.Count <= i || existingLmapsAdditional[i].rnm0 != storage.rnmMaps0[i])) { sameArray = false; break; } } } if (!sameArray) // create new lightmap array { if (sceneCount >= 1) { // first add old for (int i = 0; i < existingLmaps.Length; i++) { // skip empty lightmaps (can be created by 5.6 ldata asset or vertex color) // ... unless there are valid lightmaps around them bool lightmapIsEmpty = existingLmaps[i] == null || (existingLmaps[i].lightmapColor == null && existingLmaps[i].shadowMask == null); bool lightmapCanBeSkipped = lightmapIsEmpty && (i == 0 || i == existingLmaps.Length - 1); if (!lightmapCanBeSkipped) { lmaps.Add(existingLmaps[i]); if (existingLmapsAdditional.Count > i) { lmapsAdditional.Add(existingLmapsAdditional[i]); } } } } for (int i = 0; i < storage.maps.Count; i++) { var texlm = storage.maps[i]; Texture2D texmask = null; Texture2D texdir = null; Texture2D texrnm0 = null; Texture2D texrnm1 = null; Texture2D texrnm2 = null; int mapMode = 0; if (storage.masks.Count > i) { texmask = storage.masks[i]; } if (storage.dirMaps.Count > i) { texdir = storage.dirMaps[i]; } if (storage.rnmMaps0.Count > i) { texrnm0 = storage.rnmMaps0[i]; texrnm1 = storage.rnmMaps1[i]; texrnm2 = storage.rnmMaps2[i]; mapMode = storage.mapsMode[i]; } bool found = false; int firstEmpty = -1; for (int j = 0; j < lmaps.Count; j++) { if (lmaps[j].lightmapColor == texlm && lmaps[j].shadowMask == texmask) { // lightmap already added - reuse storage.idremap[i] = j; found = true; //Debug.LogError("reused "+j); // additional maps array could be flushed due to script recompilation - recover if (texrnm0 != null && (lmapsAdditional.Count <= j || lmapsAdditional[j].rnm0 == null)) { while (lmapsAdditional.Count <= j) { lmapsAdditional.Add(new LightmapAdditionalData()); } var l = new LightmapAdditionalData(); l.rnm0 = texrnm0; l.rnm1 = texrnm1; l.rnm2 = texrnm2; l.mode = mapMode; lmapsAdditional[j] = l; } break; } else if (firstEmpty < 0 && lmaps[j].lightmapColor == null && lmaps[j].shadowMask == null) { // free (deleted) entry in existing lightmap list - possibly reuse storage.idremap[i] = j; firstEmpty = j; } } if (!found) { LightmapData lm; if (firstEmpty >= 0) { lm = lmaps[firstEmpty]; } else { lm = new LightmapData(); } lm.lightmapColor = texlm; if (storage.masks.Count > i) { lm.shadowMask = texmask; } if (storage.dirMaps.Count > i && texdir != null) { lm.lightmapDir = texdir; } else if (directionalMode) { lm.lightmapDir = GetEmptyDirectionTex(storage); } if (firstEmpty < 0) { lmaps.Add(lm); storage.idremap[i] = lmaps.Count - 1; } else { lmaps[firstEmpty] = lm; } if (storage.rnmMaps0.Count > i) { var l = new LightmapAdditionalData(); l.rnm0 = texrnm0; l.rnm1 = texrnm1; l.rnm2 = texrnm2; l.mode = mapMode; if (firstEmpty < 0) { //Debug.LogError("added "+(lmaps.Count-1)); while (lmapsAdditional.Count < lmaps.Count - 1) { lmapsAdditional.Add(new LightmapAdditionalData()); } lmapsAdditional.Add(l); } else { //Debug.LogError("set " + firstEmpty); while (lmapsAdditional.Count < firstEmpty + 1) { lmapsAdditional.Add(new LightmapAdditionalData()); } lmapsAdditional[firstEmpty] = l; } } } } } else // reuse existing lightmap array, only remap IDs { for (int i = 0; i < storage.maps.Count; i++) { storage.idremap[i] = i; //Debug.LogError("full reuse"); /*if (storage.rnmMaps0.Count > i) * { * var l = new LightmapAdditionalData(); * l.rnm0 = storage.rnmMaps0[i]; * l.rnm1 = storage.rnmMaps1[i]; * l.rnm2 = storage.rnmMaps2[i]; * l.mode = storage.mapsMode[i]; * lmapsAdditional.Add(l); * }*/ } } #if UNITY_EDITOR // Set editor lighting mode Lightmapping.giWorkflowMode = Lightmapping.GIWorkflowMode.OnDemand; Lightmapping.realtimeGI = storage.usesRealtimeGI; Lightmapping.bakedGI = true; #endif // Replace the lightmap array if needed if (sameArray && patchedDirection) { LightmapSettings.lightmaps = existingLmaps; } if (!sameArray) { LightmapSettings.lightmaps = lmaps.ToArray(); globalMapsAdditional = lmapsAdditional; } /* * // Debug * var lms = LightmapSettings.lightmaps; * for(int i=0; i<lms.Length; i++) * { * var name1 = ((lms[i]==null || lms[i].lightmapColor==null) ? "-" : lms[i].lightmapColor.name); * var name2 = (globalMapsAdditional.Count > i ?(globalMapsAdditional[i].rnm0==null?"x":globalMapsAdditional[i].rnm0.name) : "-"); * Debug.LogError(i+" "+name1+" "+name2); * } */ // Attempt to update skybox probe if (RenderSettings.ambientMode == UnityEngine.Rendering.AmbientMode.Skybox)// && Lightmapping.lightingDataAsset == null) { var probe = RenderSettings.ambientProbe; int isEmpty = -1; for (int i = 0; i < 3; i++) { for (int j = 0; j < 9; j++) { // default bugged probes are [almost] black or 1302? float a = Mathf.Abs(probe[i, j]); if (a > 1000.0f || a < 0.000001f) { isEmpty = 1; break; } if (probe[i, j] != 0) { isEmpty = 0; break; } } if (isEmpty >= 0) { break; } } if (isEmpty != 0) { DynamicGI.UpdateEnvironment(); } } // Set lightmap data on mesh renderers var emptyVec4 = new Vector4(1, 1, 0, 0); for (int i = 0; i < storage.bakedRenderers.Count; i++) { var r = storage.bakedRenderers[i]; if (r == null) { continue; } //if (r.isPartOfStaticBatch) continue; var id = storage.bakedIDs[i]; Mesh vmesh = null; if (i < storage.bakedVertexColorMesh.Count) { vmesh = storage.bakedVertexColorMesh[i]; } if (vmesh != null) { r.additionalVertexStreams = vmesh; r.lightmapIndex = 0xFFFF; var prop = new MaterialPropertyBlock(); prop.SetFloat("bakeryLightmapMode", 1); r.SetPropertyBlock(prop); continue; } int globalID = (id < 0 || id >= storage.idremap.Length) ? id : storage.idremap[id]; r.lightmapIndex = globalID; if (!r.isPartOfStaticBatch) { // scaleOffset is baked on static batches already var scaleOffset = id < 0 ? emptyVec4 : storage.bakedScaleOffset[i]; r.lightmapScaleOffset = scaleOffset; } if (r.lightmapIndex >= 0 && globalID < globalMapsAdditional.Count) { var lmap = globalMapsAdditional[globalID]; if (lmap.rnm0 != null) { var prop = new MaterialPropertyBlock(); prop.SetTexture("_RNM0", lmap.rnm0); prop.SetTexture("_RNM1", lmap.rnm1); prop.SetTexture("_RNM2", lmap.rnm2); prop.SetFloat("bakeryLightmapMode", lmap.mode); r.SetPropertyBlock(prop); } } } // Set lightmap data on definitely-not-baked mesh renderers (can be possibly avoided) if (updateNonBaked) { for (int i = 0; i < storage.nonBakedRenderers.Count; i++) { var r = storage.nonBakedRenderers[i]; if (r == null) { continue; } if (r.isPartOfStaticBatch) { continue; } r.lightmapIndex = 0xFFFE; } } // Set lightmap data on terrains for (int i = 0; i < storage.bakedRenderersTerrain.Count; i++) { var r = storage.bakedRenderersTerrain[i]; if (r == null) { continue; } var id = storage.bakedIDsTerrain[i]; r.lightmapIndex = (id < 0 || id >= storage.idremap.Length) ? id : storage.idremap[id]; var scaleOffset = id < 0 ? emptyVec4 : storage.bakedScaleOffsetTerrain[i]; r.lightmapScaleOffset = scaleOffset; } // Set shadowmask parameters on lights for (int i = 0; i < storage.bakedLights.Count; i++) { #if UNITY_2017_3_OR_NEWER var output = new LightBakingOutput(); output.isBaked = true; output.lightmapBakeType = LightmapBakeType.Mixed; output.mixedLightingMode = MixedLightingMode.Shadowmask; output.occlusionMaskChannel = storage.bakedLightChannels[i]; output.probeOcclusionLightIndex = storage.bakedLights[i].bakingOutput.probeOcclusionLightIndex; storage.bakedLights[i].bakingOutput = output; //#else //var light = storage.bakedLights[i]; #endif } // Increment lightmap refcounts if (lightmapRefCount == null) { lightmapRefCount = new List <int>(); } for (int i = 0; i < storage.idremap.Length; i++) { int currentID = storage.idremap[i]; while (lightmapRefCount.Count <= currentID) { lightmapRefCount.Add(0); } if (lightmapRefCount[currentID] < 0) { lightmapRefCount[currentID] = 0; } lightmapRefCount[currentID]++; } //if (loadedStorages == null) loadedStorages = new List<ftLightmapsStorage>(); //if (loadedStorages.Contains(storage)) loadedStorages.Add(storage); //return appendOffset; }