diff options
Diffstat (limited to '')
-rw-r--r-- | VRCSDK3Worlds/Assets/Bakery/ftLightmaps.cs | 936 | ||||
-rw-r--r-- | VRCSDK3Worlds/Assets/Bakery/ftLightmaps.cs.meta | 12 |
2 files changed, 948 insertions, 0 deletions
diff --git a/VRCSDK3Worlds/Assets/Bakery/ftLightmaps.cs b/VRCSDK3Worlds/Assets/Bakery/ftLightmaps.cs new file mode 100644 index 00000000..3d3f9ee0 --- /dev/null +++ b/VRCSDK3Worlds/Assets/Bakery/ftLightmaps.cs @@ -0,0 +1,936 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +// Disable 'obsolete' warnings +#pragma warning disable 0618 + +#if UNITY_EDITOR +using UnityEditor; +using UnityEditor.SceneManagement; +using System.Reflection; +using System.Runtime.CompilerServices; +using System.IO; +#endif + +using UnityEngine.SceneManagement; + +#if UNITY_EDITOR +[InitializeOnLoad] +#endif +public class ftLightmaps { + + struct LightmapAdditionalData + { + public Texture2D rnm0, rnm1, rnm2; + public int mode; + }; + + static List<int> lightmapRefCount; + static List<LightmapAdditionalData> globalMapsAdditional; + static int directionalMode; // -1 undefined, 0 off, 1 on + //static List<ftLightmapsStorage> loadedStorages; + +#if UNITY_EDITOR + public static bool mustReloadRenderSettings = false; + static ftGlobalStorage gstorage; + static ftLocalStorage lstorage; + static BakeryProjectSettings pstorage; + static bool editorUpdateCalled = false; + + public static string _bakeryRuntimePath = ""; + public static string _bakeryEditorPath = ""; + public static string GetRuntimePath() + { + if (_bakeryRuntimePath.Length == 0) + { + // Try default path + // (start with AssetDatabase assuming it's faster than GetFiles) + var a = AssetDatabase.LoadAssetAtPath("Assets/Bakery/ftDefaultAreaLightMat.mat", typeof(Texture2D)) as Texture2D; + if (a == null) + { + // Find elsewhere + var assetGUIDs = AssetDatabase.FindAssets("ftDefaultAreaLightMat", null); + if (assetGUIDs.Length == 0) + { + // No extra data present - find the script at least + var res = Directory.GetFiles(Application.dataPath, "ftLightmaps.cs", SearchOption.AllDirectories); + if (res.Length == 0) + { + Debug.LogError("Can't locate Bakery folder"); + return ""; + } + return "Assets" + res[0].Replace("ftLightmaps.cs", "").Replace("\\", "/").Replace(Application.dataPath, ""); + } + if (assetGUIDs.Length > 1) + { + Debug.LogError("ftDefaultAreaLightMat was found in more than one folder. Do you have multiple installations of Bakery?"); + } + var guid = assetGUIDs[0]; + _bakeryRuntimePath = System.IO.Path.GetDirectoryName(AssetDatabase.GUIDToAssetPath(guid)) + "/"; + return _bakeryRuntimePath; + } + _bakeryRuntimePath = "Assets/Bakery/"; + } + return _bakeryRuntimePath; + } + + public static string GetEditorPath() + { + if (_bakeryEditorPath.Length == 0) + { + // Try default path + var a = AssetDatabase.LoadAssetAtPath("Assets/Editor/x64/Bakery/NormalsFittingTexture_dds", typeof(Object)); + if (a == null) + { + // Find elsewhere + var assetGUIDs = AssetDatabase.FindAssets("NormalsFittingTexture_dds", null); + if (assetGUIDs.Length == 0) + { + // No extra data present - find ftModelPostProcessor at least (minimum required editor script) + var res = Directory.GetFiles(Application.dataPath, "ftModelPostProcessor.cs", SearchOption.AllDirectories); + if (res.Length == 0) + { + Debug.LogError("Can't locate Bakery folder"); + return ""; + } + return "Assets" + res[0].Replace("ftModelPostProcessor.cs", "").Replace("\\", "/").Replace(Application.dataPath, ""); + } + if (assetGUIDs.Length > 1) + { + Debug.LogError("NormalsFittingTexture_dds was found in more than one folder. Do you have multiple installations of Bakery?"); + } + var guid = assetGUIDs[0]; + _bakeryEditorPath = System.IO.Path.GetDirectoryName(AssetDatabase.GUIDToAssetPath(guid)) + "/"; + return _bakeryEditorPath; + } + _bakeryEditorPath = "Assets/Editor/x64/Bakery/"; + } + return _bakeryEditorPath; + } + + public static string GetProjectSettingsPath() + { + return "Assets/Settings/"; + } + + public static ftGlobalStorage GetGlobalStorage() + { + if (gstorage != null) return gstorage; + var bakeryRuntimePath = GetRuntimePath(); + gstorage = AssetDatabase.LoadAssetAtPath(bakeryRuntimePath + "ftGlobalStorage.asset", typeof(ftGlobalStorage)) as ftGlobalStorage; + if (gstorage == null && editorUpdateCalled) // if editorUpdateCalled==false, it may be not imported yet + { + var gstorageDefault = AssetDatabase.LoadAssetAtPath(bakeryRuntimePath + "ftDefaultGlobalStorage.asset", typeof(ftGlobalStorage)) as ftGlobalStorage; + + if (gstorageDefault != null) + { + if (AssetDatabase.CopyAsset(bakeryRuntimePath + "ftDefaultGlobalStorage.asset", bakeryRuntimePath + "ftGlobalStorage.asset")) + { + AssetDatabase.Refresh(); + gstorage = AssetDatabase.LoadAssetAtPath(bakeryRuntimePath + "ftGlobalStorage.asset", typeof(ftGlobalStorage)) as ftGlobalStorage; + } + } + + if (gstorage == null) + { + Debug.Log("Created Bakery GlobalStorage"); + gstorage = ScriptableObject.CreateInstance<ftGlobalStorage>(); + AssetDatabase.CreateAsset(gstorage, bakeryRuntimePath + "ftGlobalStorage.asset"); + AssetDatabase.SaveAssets(); + } + else + { + Debug.Log("Created Bakery GlobalStorage from DefaultGlobalStorage"); + } + } + + if (gstorage != null) + { + if (gstorage.modifiedMeshList.Count > 0) + { + gstorage.ConvertFromLegacy(); + } + } + + return gstorage; + } + + static ftLocalStorage GetLocalStorage() + { + if (lstorage != null) return lstorage; + var bakeryRuntimePath = GetRuntimePath(); + lstorage = AssetDatabase.LoadAssetAtPath(bakeryRuntimePath + "ftLocalStorage.asset", typeof(ftLocalStorage)) as ftLocalStorage; + if (lstorage == null) + { + Debug.Log("Created Bakery LocalStorage"); + lstorage = ScriptableObject.CreateInstance<ftLocalStorage>(); + AssetDatabase.CreateAsset(lstorage, bakeryRuntimePath + "ftLocalStorage.asset"); + AssetDatabase.SaveAssets(); + } + return lstorage; + } + + public static BakeryProjectSettings GetProjectSettings() + { + if (pstorage != null) return pstorage; + var path = GetProjectSettingsPath(); + if (!Directory.Exists(path)) Directory.CreateDirectory(path); + pstorage = AssetDatabase.LoadAssetAtPath(path + "BakeryProjectSettings.asset", typeof(BakeryProjectSettings)) as BakeryProjectSettings; + if (pstorage == null) + { + Debug.Log("Created Bakery ProjectSettings"); + pstorage = ScriptableObject.CreateInstance<BakeryProjectSettings>(); + AssetDatabase.CreateAsset(pstorage, path + "BakeryProjectSettings.asset"); + AssetDatabase.SaveAssets(); + } + return pstorage; + } + + static void CreateGlobalStorageAsset() + { + if (gstorage == null) gstorage = GetGlobalStorage(); + if (lstorage == null) lstorage = GetLocalStorage(); + + if (Application.isPlaying) return; + + var listToProccess = gstorage.modifiedAssetPathList; + var listToProcessHash = gstorage.modifiedAssetPaddingHash; + var listProcessed = lstorage.modifiedAssetPathList; + var listProcessedHash = lstorage.modifiedAssetPaddingHash; + for(int i=0; i<listToProccess.Count; i++) + { + int localID = listProcessed.IndexOf(listToProccess[i]); + if (localID >= 0) + { + if (listToProcessHash.Count > i) + { + int globalPaddingHash = listToProcessHash[i]; + if (listProcessedHash.Count > localID) + { + int localPaddingHash = listProcessedHash[localID]; + if (globalPaddingHash == localPaddingHash) + { + continue; + } + } + } + else + { + // Hash is not initialized = legacy + continue; + } + } + +#if UNITY_2017_1_OR_NEWER + var importer = AssetImporter.GetAtPath(listToProccess[i]) as ModelImporter; + if (importer != null) + { + var props = importer.extraUserProperties; + int propID = -1; + for(int p=0; p<props.Length; p++) + { + if (props[p].Substring(0,7) == "#BAKERY") + { + propID = p; + break; + } + } + if (propID >= 0) continue; // should be fine without additional reimport - metadata is always loaded with model + } +#endif + + var asset = AssetDatabase.LoadAssetAtPath(listToProccess[i], typeof(GameObject)) as GameObject; + if (asset == null) continue; + if (asset.tag == "BakeryProcessed") continue; // legacy + //if (asset.tag != "BakeryProcessed") AssetDatabase.ImportAsset(list[i], ImportAssetOptions.ForceUpdate); + Debug.Log("Reimporting to adjust UVs: " + listToProccess[i]); + AssetDatabase.ImportAsset(listToProccess[i], ImportAssetOptions.ForceUpdate); + } + } + + /*public static bool IsModelProcessed(string path) + { + if (lstorage == null) lstorage = GetLocalStorage(); + var listProcessed = lstorage.modifiedAssetPathList; + return listProcessed.Contains(path); + }*/ + + public static void MarkModelProcessed(string path, bool enabled) + { + if (lstorage == null) lstorage = GetLocalStorage(); + if (gstorage == null) gstorage = GetGlobalStorage(); + if (enabled) + { + int gid = gstorage.modifiedAssetPathList.IndexOf(path); + if (gid < 0) return; + int hash = gstorage.CalculatePaddingHash(gid); + while(gstorage.modifiedAssetPaddingHash.Count <= gid) gstorage.modifiedAssetPaddingHash.Add(0); + gstorage.modifiedAssetPaddingHash[gid] = hash; + + int id = lstorage.modifiedAssetPathList.IndexOf(path); + if (id < 0) + { + lstorage.modifiedAssetPathList.Add(path); + id = lstorage.modifiedAssetPathList.Count - 1; + } + while(lstorage.modifiedAssetPaddingHash.Count <= id) lstorage.modifiedAssetPaddingHash.Add(0); + lstorage.modifiedAssetPaddingHash[id] = hash; + EditorUtility.SetDirty(gstorage); + EditorSceneManager.MarkAllScenesDirty(); + } + else + { + int id = lstorage.modifiedAssetPathList.IndexOf(path); + if (id >= 0) + { + lstorage.modifiedAssetPathList.RemoveAt(id); + if (lstorage.modifiedAssetPaddingHash.Count > id) lstorage.modifiedAssetPaddingHash.RemoveAt(id); + } + } + EditorUtility.SetDirty(lstorage); + } + +#endif + + static ftLightmaps() { + +#if UNITY_EDITOR + EditorSceneManager.sceneOpening -= OnSceneOpening; // Andrew fix + EditorSceneManager.sceneOpening += OnSceneOpening; + + EditorApplication.update -= FirstUpdate; // Andrew fix + EditorApplication.update += FirstUpdate; + + EditorApplication.hierarchyWindowChanged -= OnSceneChangedEditor; + EditorApplication.hierarchyWindowChanged += OnSceneChangedEditor; +#endif + + SceneManager.activeSceneChanged -= OnSceneChangedPlay; + SceneManager.activeSceneChanged += OnSceneChangedPlay; + } + +#if UNITY_EDITOR + static void FirstUpdate() + { + editorUpdateCalled = true; + CreateGlobalStorageAsset(); + GetProjectSettings(); + EditorApplication.update -= FirstUpdate; + } +#endif + + static void SetDirectionalMode() + { + if (directionalMode >= 0) LightmapSettings.lightmapsMode = directionalMode==1 ? LightmapsMode.CombinedDirectional : LightmapsMode.NonDirectional; + } + + static void OnSceneChangedPlay(Scene prev, Scene next) { + //if (Lightmapping.lightingDataAsset == null) { + SetDirectionalMode(); + //} + } + +#if UNITY_EDITOR + static void OnSceneChangedEditor() { + // Unity can modify directional mode on scene change, have to force the correct one + // activeSceneChangedInEditMode isn't always available + //if (Lightmapping.lightingDataAsset == null) { + SetDirectionalMode(); + //} + } + + // using Opening instead of Opened because it's called before lightmap data is loaded and proper directional mode is set + //static void OnSceneOpened(Scene scene, OpenSceneMode mode) { + static void OnSceneOpening(string path, OpenSceneMode mode) { + //Refresh(); + //if (scene.name == "_tempScene") return; + if (Path.GetFileNameWithoutExtension(path) == "_tempScene") return; + mustReloadRenderSettings = true; + directionalMode = -1; + /*if (!finalInitDone) + { + CreateGlobalStorageAsset(); + finalInitDone = true; + }*/ + } +#endif + + public static void RefreshFull() { + var activeScene = SceneManager.GetActiveScene(); + var sceneCount = SceneManager.sceneCount; + + for(int i=0; i<sceneCount; i++) + { + var scene = SceneManager.GetSceneAt(i); + if (!scene.isLoaded) continue; + SceneManager.SetActiveScene(scene); + LightmapSettings.lightmaps = new LightmapData[0]; + } + + for(int i=0; i<sceneCount; i++) + { + RefreshScene(SceneManager.GetSceneAt(i), null, true); + } + SceneManager.SetActiveScene(activeScene); + } + + public static GameObject FindInScene(string nm, Scene scn) + { + var objs = scn.GetRootGameObjects(); + for(int i=0; i<objs.Length; i++) + { + if (objs[i].name == nm) return objs[i]; + var obj = objs[i].transform.Find(nm); + if (obj != null) return obj.gameObject; + } + return null; + } + +/* public static void RefreshScene(int sceneID, ref List<LightmapData> lmaps, int lmCounter) { + RefreshScene(scene); + }*/ + + static Texture2D GetEmptyDirectionTex(ftLightmapsStorage storage) + { +#if UNITY_EDITOR + if (storage.emptyDirectionTex == null) + { + var bakeryRuntimePath = GetRuntimePath(); + storage.emptyDirectionTex = AssetDatabase.LoadAssetAtPath(bakeryRuntimePath + "emptyDirection.tga", typeof(Texture2D)) as Texture2D; + } +#endif + return storage.emptyDirectionTex; + } + + 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 ? 1 : 0; + bool patchedDirection = false; + SetDirectionalMode(); + + // Set dummy directional tex for non-directional lightmaps in directional mode + if (directionalMode == 1) + { + for(int i=0; i<existingLmaps.Length; i++) + { + if (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 == 1) + { + 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 + if (storage.bakedRenderers != null && storage.bakedRenderers.Count > 0) + { + Lightmapping.giWorkflowMode = Lightmapping.GIWorkflowMode.OnDemand; + Lightmapping.realtimeGI = storage.usesRealtimeGI; + //Lightmapping.bakedGI = true; // ? only used for enlighten ? makes editor laggy ? + } +#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) + { + var r2 = r as MeshRenderer; + if (r2 == null) + { + Debug.LogError("Unity cannot use additionalVertexStreams on non-MeshRenderer"); + } + else + { + r2.additionalVertexStreams = vmesh; + r2.lightmapIndex = 0xFFFF; + var prop = new MaterialPropertyBlock(); + prop.SetFloat("bakeryLightmapMode", 1); + r2.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; + + if (r.lightmapIndex >= 0 && r.lightmapIndex < globalMapsAdditional.Count) + { + var lmap = globalMapsAdditional[r.lightmapIndex]; + 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.SetSplatMaterialPropertyBlock(prop); + } + } + } + + // Set shadowmask parameters on lights + for(int i=0; i<storage.bakedLights.Count; i++) + { +#if UNITY_2017_3_OR_NEWER + if (storage.bakedLights[i] == null) continue; + + int channel = storage.bakedLightChannels[i]; + var output = new LightBakingOutput(); + output.isBaked = true; + if (channel < 0) + { + output.lightmapBakeType = LightmapBakeType.Baked; + } + else + { + output.lightmapBakeType = LightmapBakeType.Mixed; + output.mixedLightingMode = channel > 100 ? MixedLightingMode.Subtractive : MixedLightingMode.Shadowmask; + output.occlusionMaskChannel = channel > 100 ? -1 : channel; + output.probeOcclusionLightIndex = storage.bakedLights[i].bakingOutput.probeOcclusionLightIndex; + } + storage.bakedLights[i].bakingOutput = output; +#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; + } + + 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 RefreshScene2(Scene scene, ftLightmapsStorage storage) + { + Renderer r; + int id; + for(int i=0; i<storage.bakedRenderers.Count; i++) + { + r = storage.bakedRenderers[i]; + if (r == null) continue; + + id = storage.bakedIDs[i]; + r.lightmapIndex = (id < 0 || id >= storage.idremap.Length) ? id : storage.idremap[id]; + } + + Terrain r2; + for(int i=0; i<storage.bakedRenderersTerrain.Count; i++) + { + r2 = storage.bakedRenderersTerrain[i]; + if (r2 == null) continue; + + id = storage.bakedIDsTerrain[i]; + r2.lightmapIndex = (id < 0 || id >= storage.idremap.Length) ? id : storage.idremap[id]; + } + + if (storage.anyVolumes) + { + if (storage.compressedVolumes) + { + Shader.EnableKeyword("BAKERY_COMPRESSED_VOLUME"); + } + else + { + Shader.DisableKeyword("BAKERY_COMPRESSED_VOLUME"); + } + } + } +} diff --git a/VRCSDK3Worlds/Assets/Bakery/ftLightmaps.cs.meta b/VRCSDK3Worlds/Assets/Bakery/ftLightmaps.cs.meta new file mode 100644 index 00000000..a3527461 --- /dev/null +++ b/VRCSDK3Worlds/Assets/Bakery/ftLightmaps.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 7a45445dfd5b7b44cb9545da4e5ed41c +timeCreated: 1496213851 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: |