ArabDesert/Assets/Bakery/ftLightmaps.cs

965 lines
35 KiB
C#
Raw Normal View History

2024-05-25 09:10:35 +03:00
#define USE_TERRAINS
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(Material)) as Material;
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 GetProjectSettingsPathOld()
{
return "Assets/Settings/";
}
public static string GetProjectSettingsPathNew()
{
var path = GetRuntimePath();
for(int i=path.Length-2; i>=0; i--)
{
char c = path[i];
if (c == '/' || c == '\\')
{
path = path.Substring(0, i);
break;
}
}
return path + "/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 = GetProjectSettingsPathOld();
if (!Directory.Exists(path))
{
path = GetProjectSettingsPathNew();
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;
}
}
#if USE_TERRAINS
// 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);
}
}
}
#endif
// 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];
}
#if USE_TERRAINS
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];
}
#endif
if (storage.anyVolumes)
{
if (storage.compressedVolumes)
{
Shader.EnableKeyword("BAKERY_COMPRESSED_VOLUME");
}
else
{
Shader.DisableKeyword("BAKERY_COMPRESSED_VOLUME");
}
}
}
}