diff options
| author | yum <yum.food.vr@gmail.com> | 2024-04-25 15:52:24 -0700 |
|---|---|---|
| committer | yum <yum.food.vr@gmail.com> | 2024-04-25 15:52:24 -0700 |
| commit | 6eed98ff4e57326ebf7a41f0c180635a7bcac626 (patch) | |
| tree | 67f5e269bafb49608cab8a6b22534d83fd09b58b /Third_Party/at.pimaker.ltcgi/Editor/LTCGI_Controller.cs | |
| parent | b9671b47df8b17fa3143d4b0dbdecf9b77cc7607 (diff) | |
Add LTCGI
Also begin trying to fix fallback shaders.
Diffstat (limited to 'Third_Party/at.pimaker.ltcgi/Editor/LTCGI_Controller.cs')
| -rw-r--r-- | Third_Party/at.pimaker.ltcgi/Editor/LTCGI_Controller.cs | 763 |
1 files changed, 763 insertions, 0 deletions
diff --git a/Third_Party/at.pimaker.ltcgi/Editor/LTCGI_Controller.cs b/Third_Party/at.pimaker.ltcgi/Editor/LTCGI_Controller.cs new file mode 100644 index 0000000..7d10357 --- /dev/null +++ b/Third_Party/at.pimaker.ltcgi/Editor/LTCGI_Controller.cs @@ -0,0 +1,763 @@ +// Uncomment for debug messages +//#define DEBUG_LOG + +#if UNITY_EDITOR +using System; +using System.Collections.Generic; +using System.Linq; +using System.IO; +using UnityEditor; +using UnityEngine; +using UnityEditor.SceneManagement; + +#if UDONSHARP +using UdonSharp; +using UdonSharpEditor; +#endif +#endif + +namespace pi.LTCGI +{ + #if UNITY_EDITOR + [ExecuteInEditMode] + [System.Serializable] + public partial class LTCGI_Controller : MonoBehaviour + { + internal const int MAX_SOURCES = 16; + + [Tooltip("Intensity is set for each screen. Can be a RenderTexture for realtime updates (video players).")] + public Texture VideoTexture; + [Tooltip("Static textures are precomputed and *must* all be the same size. Make sure to click 'Precompute Static Textures' after any changes.")] + public Texture2D[] StaticTextures; + [Tooltip("Renderers that may change material during runtime. Otherwise only 'sharedMaterial's are updated for performance reasons.")] + public Renderer[] DynamicRenderers; + + [Header("Expert Settings")] + [Tooltip("Do not automatically set up the blur chain. Use this if you use AVPro to set _MainTex on the LOD1 material for example.")] + public bool CustomBlurChain = false; + + [Tooltip("Apply an intensity multiplier *before* baking the lightmap. Offset with Lightmap Multiplier below.")] + public float LightmapIntensity = 4.0f; + + [Tooltip("Multiply lightmap with this before applying to diffuse. Useful if you have multiple lights next to each other sharing a channel.")] + public Vector3 LightmapMultiplier = new Vector4(0.25f, 0.25f, 0.25f, 0.25f); + + [Header("Internal Settings")] + public Texture2D DefaultLightmap; + public CustomRenderTexture LOD1s, LOD1, LOD2s, LOD2, LOD3s, LOD3; + public Texture2D LUT1, LUT2; + + public static LTCGI_Controller Singleton; + + [NonSerialized] internal Renderer[] cachedMeshRenderers; + [NonSerialized] private Vector4[] _LTCGI_Vertices_0, _LTCGI_Vertices_1, _LTCGI_Vertices_2, _LTCGI_Vertices_3; + [NonSerialized] private Vector4[] _LTCGI_Vertices_0t, _LTCGI_Vertices_1t, _LTCGI_Vertices_2t, _LTCGI_Vertices_3t; + [NonSerialized] internal Transform[] _LTCGI_ScreenTransforms; + [NonSerialized] private Vector4[] _LTCGI_ExtraData; + [NonSerialized] private Vector4 _LTCGI_LightmapMult; + [NonSerialized] private Vector2[][] _LTCGI_UVs; + + private Texture2DArray[] _LTCGI_LOD_arrays; + + public bool HasDynamicScreens = false; + public bool HasCylinders = false; + + public void OnEnable() + { + if (PrefabUtility.IsPartOfPrefabAsset(this.gameObject)) return; + if (Singleton == null || Singleton != this) + { + if (PrefabUtility.IsPartOfPrefabInstance(this.gameObject)) + PrefabUtility.UnpackPrefabInstance(this.gameObject, PrefabUnpackMode.Completely, InteractionMode.AutomatedAction); + Singleton = this; + Undo.undoRedoPerformed += this.UpdateMaterials; + EditorApplication.playModeStateChanged += (change) => { + if (change == PlayModeStateChange.ExitingEditMode) + { + UpdateMaterials(); + } + }; + Debug.Log($"LTCGI Controller Singleton initialized (Mode: {RuntimeMode})"); + + var ctrls = GameObject.FindObjectsOfType<LTCGI_Controller>().Length; + if (ctrls > 1) + { + Debug.LogError("There must only be one LTCGI Controller per scene!"); + } + } + + MigratoryBirdsDontMigrateAsMuchAsWeDoButThisFunctionWillTakeCareOfItNonetheless(); + } + + public static void MigratoryBirdsDontMigrateAsMuchAsWeDoButThisFunctionWillTakeCareOfItNonetheless() + { + var hasChanges = false; + if (!AssetDatabase.IsValidFolder("Assets\\_pi_")) + { + AssetDatabase.CreateFolder("Assets", "_pi_"); + hasChanges = true; + } + if (!AssetDatabase.IsValidFolder("Assets\\_pi_\\_LTCGI")) + { + AssetDatabase.CreateFolder("Assets\\_pi_", "_LTCGI"); + hasChanges = true; + } + if (!AssetDatabase.IsValidFolder("Assets\\_pi_\\_LTCGI\\Shaders")) + { + AssetDatabase.CreateFolder("Assets\\_pi_\\_LTCGI", "Shaders"); + hasChanges = true; + } + if (!File.Exists("Assets\\_pi_\\_LTCGI\\Shaders\\LTCGI.cginc")) + { + File.WriteAllText("Assets\\_pi_\\_LTCGI\\Shaders\\LTCGI.cginc", "#include \"Packages\\at.pimaker.ltcgi\\Shaders\\LTCGI.cginc\""); + hasChanges = true; + } + + // god I hate this part, Unity dumb dumb + if (!AssetDatabase.IsValidFolder("Assets\\Gizmos")) + { + AssetDatabase.CreateFolder("Assets", "Gizmos"); + hasChanges = true; + } + if (!File.Exists("Assets\\Gizmos\\LTCGI_Screen_Gizmo.png")) + { + File.Copy("Packages\\at.pimaker.ltcgi\\LTCGI_Screen_Gizmo.png", "Assets\\Gizmos\\LTCGI_Screen_Gizmo.png", true); + hasChanges = true; + } + + if (hasChanges) + { + Debug.Log("LTCGI Migration took place, refreshing asset database"); + AssetDatabase.Refresh(); + } + } + + public static bool MatLTCGIenabled(Material mat) + { + if (mat == null) return false; + var tag = mat.GetTag("LTCGI", true); + if (tag == null || string.IsNullOrEmpty(tag)) return false; + if (tag == "ALWAYS") return true; + return mat.GetFloat(tag) != 0; + } + + [MenuItem("Tools/LTCGI/Force Material Update")] + public static void UpdateMaterialsMenu() => Singleton?.UpdateMaterials(); + public void UpdateMaterials() => UpdateMaterials(false); + public void UpdateMaterials(bool fast, LTCGI_Screen screen = null) + { + // don't mess with Udon emulation + if (EditorApplication.isPlaying) + return; + if (Lightmapping.isRunning) + return; + if (UnityEngine.SceneManagement.SceneManager.loadedSceneCount == 0) + return; + + #if DEBUG_LOG + Debug.Log($"LTCGI: beginning update ({(fast ? "fast" : "full")})"); + #endif + + MigratoryBirdsDontMigrateAsMuchAsWeDoButThisFunctionWillTakeCareOfItNonetheless(); + + if (_LTCGI_ExtraData == null) + fast = false; + if (_LTCGI_LightmapMult == null) + fast = false; + + if (!fast) + { + _LTCGI_Vertices_0 = new Vector4[MAX_SOURCES]; + _LTCGI_Vertices_1 = new Vector4[MAX_SOURCES]; + _LTCGI_Vertices_2 = new Vector4[MAX_SOURCES]; + _LTCGI_Vertices_3 = new Vector4[MAX_SOURCES]; + _LTCGI_Vertices_0t = new Vector4[MAX_SOURCES]; + _LTCGI_Vertices_1t = new Vector4[MAX_SOURCES]; + _LTCGI_Vertices_2t = new Vector4[MAX_SOURCES]; + _LTCGI_Vertices_3t = new Vector4[MAX_SOURCES]; + _LTCGI_ExtraData = new Vector4[MAX_SOURCES]; + _LTCGI_ScreenTransforms = new Transform[MAX_SOURCES]; + _LTCGI_UVs = new Vector2[MAX_SOURCES][]; + } + + var dynamics = false; + var cylinders = false; + + // construct data + var screens = GameObject + .FindObjectsOfType<LTCGI_Screen>() + .Where(x => x.enabled) + .OrderByDescending(x => x.Dynamic) + .ToArray(); + + if (screens.Length > MAX_SOURCES) + { + if (fast) return; + throw new Exception("Too many screens in the scene!"); + } + + for (int i = 0; i < screens.Length; i++) + { + var s = screens[i]; + if (fast && screen != null && s != screen) continue; + + _LTCGI_ScreenTransforms[i] = s.transform; + LTCGI_Emitter emitter; + if ((emitter = s as LTCGI_Emitter) != null) + { + _LTCGI_Vertices_0[i] = _LTCGI_Vertices_1[i] = _LTCGI_Vertices_2[i] = _LTCGI_Vertices_3[i] = Vector4.zero; + _LTCGI_Vertices_0[i].w = s.SingleUV.x; + _LTCGI_Vertices_1[i].w = s.SingleUV.y; + } + else if (s.Cylinder) + { + // Experimental! + _LTCGI_Vertices_0[i] = new Vector4( + s.CylinderBase.x, + s.CylinderBase.y * 2, + s.CylinderBase.z, + s.CylinderHeight * 2 + ); + _LTCGI_Vertices_1[i] = new Vector4( + s.CylinderBase.x, + s.CylinderBase.y * 2, + s.CylinderBase.z, + s.CylinderRadius + ); + _LTCGI_Vertices_2[i] = new Vector4( + s.CylinderBase.x, + s.CylinderBase.y * 2, + s.CylinderBase.z, + s.CylinderSize + ); + _LTCGI_Vertices_3[i] = new Vector4( + s.CylinderBase.x, + s.CylinderBase.y * 2, + s.CylinderBase.z, + s.CylinderAngle + ); + + cylinders = true; + } + else + { + var mf = s.GetComponent<MeshFilter>(); + if (mf.sharedMesh == null) continue; + if (!fast) + { + SetMeshImporterFormat(mf.sharedMesh, true); + } + var mesh = mf.sharedMesh; + if (mesh.vertexCount != 4 && mesh.vertexCount != 3) + { + if (fast) return; + throw new Exception($"Mesh on '{s.gameObject.name}' does not have 3 or 4 vertices ({mesh.vertexCount})"); + } + + if (mf.sharedMesh.vertexCount == 3) + { + // extend triangle to virtual quad + mesh = Instantiate(mesh); + mesh.vertices = new Vector3[] { + mesh.vertices[0], + mesh.vertices[1], + mesh.vertices[2], + mesh.vertices[2], + }; + mesh.uv = new Vector2[] { + mesh.uv[0], + mesh.uv[1], + mesh.uv[2], + mesh.uv[2], + }; + } + + var verts = mesh.vertices; + _LTCGI_Vertices_0[i] = new Vector4(verts[0].x, verts[0].y, verts[0].z, mesh.uv[0].x); + _LTCGI_Vertices_1[i] = new Vector4(verts[1].x, verts[1].y, verts[1].z, mesh.uv[0].y); + _LTCGI_Vertices_2[i] = new Vector4(verts[2].x, verts[2].y, verts[2].z, mesh.uv[3].x); + _LTCGI_Vertices_3[i] = new Vector4(verts[3].x, verts[3].y, verts[3].z, mesh.uv[3].y); + + var angle = Vector3.Dot( + new Vector3(_LTCGI_Vertices_1[i].x, _LTCGI_Vertices_1[i].y, _LTCGI_Vertices_1[i].z) - + new Vector3(_LTCGI_Vertices_0[i].x, _LTCGI_Vertices_0[i].y, _LTCGI_Vertices_0[i].z), + new Vector3(_LTCGI_Vertices_1[i].x, _LTCGI_Vertices_1[i].y, _LTCGI_Vertices_1[i].z) - + new Vector3(_LTCGI_Vertices_3[i].x, _LTCGI_Vertices_3[i].y, _LTCGI_Vertices_3[i].z) + ); + // workaround for blender imports + if (!Mathf.Approximately(angle, 0.0f)) + { + var flip = s.FlipUV ? 1 : -1; + var v0 = _LTCGI_Vertices_0[i]; + var v1 = _LTCGI_Vertices_1[i]; + var v2 = _LTCGI_Vertices_2[i]; + var v3 = _LTCGI_Vertices_3[i]; + _LTCGI_Vertices_0[i] = v0; + _LTCGI_Vertices_1[i] = v3; + _LTCGI_Vertices_2[i] = v1; + _LTCGI_Vertices_3[i] = v2; + _LTCGI_Vertices_0[i].w = mesh.uv[0].x * flip; + _LTCGI_Vertices_1[i].w = mesh.uv[0].y; + _LTCGI_Vertices_2[i].w = mesh.uv[2].x * flip; + _LTCGI_Vertices_3[i].w = mesh.uv[2].y; + + if (s.FlipUV) + { + _LTCGI_UVs[i] = new Vector2[] + { + // TODO: is this required? if so, implement it. for now, no-op. + mesh.uv[0], + mesh.uv[3], + mesh.uv[1], + mesh.uv[2], + }; + } + else + { + _LTCGI_UVs[i] = new Vector2[] + { + mesh.uv[0], + mesh.uv[3], + mesh.uv[1], + mesh.uv[2], + }; + } + } + else + { + _LTCGI_UVs[i] = new Vector2[] + { + mesh.uv[0], + mesh.uv[1], + mesh.uv[2], + mesh.uv[3], + }; + } + + if (s.ColorMode == ColorMode.SingleUV) + { + _LTCGI_Vertices_0[i].w = s.SingleUV.x; + _LTCGI_Vertices_1[i].w = s.SingleUV.y; + } + + if (mf.sharedMesh.vertexCount == 3) + { + DestroyImmediate(mesh); + } + + if (s.Dynamic) + { + dynamics = true; + } + } + + _LTCGI_Vertices_0t[i] = s.transform.TransformPoint(_LTCGI_Vertices_0[i]); + _LTCGI_Vertices_0t[i].w = _LTCGI_Vertices_0[i].w; + _LTCGI_Vertices_1t[i] = s.transform.TransformPoint(_LTCGI_Vertices_1[i]); + _LTCGI_Vertices_1t[i].w = _LTCGI_Vertices_1[i].w; + _LTCGI_Vertices_2t[i] = s.transform.TransformPoint(_LTCGI_Vertices_2[i]); + _LTCGI_Vertices_2t[i].w = _LTCGI_Vertices_2[i].w; + _LTCGI_Vertices_3t[i] = s.transform.TransformPoint(_LTCGI_Vertices_3[i]); + _LTCGI_Vertices_3t[i].w = _LTCGI_Vertices_3[i].w; + + //Debug.Log($"V0: {_LTCGI_Vertices_0[i]}"); + //Debug.Log($"V1: {_LTCGI_Vertices_1[i]}"); + //Debug.Log($"V2: {_LTCGI_Vertices_2[i]}"); + //Debug.Log($"V3: {_LTCGI_Vertices_3[i]}"); + + uint flags = 0; + if (s.DoubleSided) flags |= 1; + if (s.DiffuseFromLm) flags |= 2; + if (s.Specular) flags |= 4; + if (s.Diffuse) flags |= 8; + flags |= ((uint)s.TextureIndex & 0xf) << 4; + flags |= ((uint)s.ColorMode & 0x3) << 8; + flags |= ((uint)s.LightmapChannel & 0x3) << 10; + if (s.Cylinder) flags |= (1<<12); + flags |= ((uint)s.AudioLinkBand & 0x3) << 13; + if (s is LTCGI_Emitter) flags |= (1<<15); // TODO: can this be set based on other flags? + + var col = s.enabled && s.gameObject.activeInHierarchy ? s.Color : Color.black; + float fflags = BitConverter.ToSingle(BitConverter.GetBytes(flags), 0); + _LTCGI_ExtraData[i] = new Vector4(col.linear.r, col.linear.g, col.linear.b, fflags); + } + + if (!fast) + { + HasCylinders = cylinders; + HasDynamicScreens = dynamics; + } + + /*_LTCGI_LightmapMult = new Vector4( + 1.0f/Mathf.Max(screens.Count(s => s.LightmapChannel == 1), 1.0f), + 1.0f/Mathf.Max(screens.Count(s => s.LightmapChannel == 2), 1.0f), + 1.0f/Mathf.Max(screens.Count(s => s.LightmapChannel == 3), 1.0f), + 0.0f + );*/ + + _LTCGI_LightmapMult = (Vector4)LightmapMultiplier; + + #if DEBUG_LOG + if (!fast) + { + Debug.Log($"LTCGI: updated screens ({screens.Length}, {_LTCGI_LightmapMult})"); + } + #endif + + if (!fast || cachedMeshRenderers == null) + { + // get all affected renderers + var allRenderers = Component.FindObjectsOfType<Renderer>(); + var renderers = new List<Renderer>(); + foreach (var r in allRenderers) + { + foreach (var mat in r.sharedMaterials) + { + if (MatLTCGIenabled(mat)) + { + if (!renderers.Contains(r)) + renderers.Add(r); + break; + } + } + } + cachedMeshRenderers = renderers.ToArray(); + + #if DEBUG_LOG + Debug.Log($"LTCGI: cached renderers ({cachedMeshRenderers.Length})"); + #endif + } + + // start LOD chain + if (VideoTexture != null && !CustomBlurChain) + { + LOD1s?.material?.SetTexture("_MainTex", VideoTexture); + } + + // find precomputed static textures + if (!fast) + { + var curscene = EditorSceneManager.GetActiveScene().name; + _LTCGI_LOD_arrays = new Texture2DArray[4]; + for (int lod = 0; lod < 4; lod++) + { + try + { + _LTCGI_LOD_arrays[lod] = AssetDatabase.LoadAssetAtPath<Texture2DArray>("Assets/LTCGI-Generated/lod-" + curscene + "-" + lod + ".asset"); + if (_LTCGI_LOD_arrays[lod] == null) throw new Exception(); + } + catch + { + _LTCGI_LOD_arrays = null; + break; + } + } + } + + // write out uniforms into data texture + var staticUniformTex = WriteStaticUniform(screens, fast); + var screenCountDynamic = screens.TakeWhile(x => x.Dynamic).Count(); + + for (int i = 0; i < cachedMeshRenderers.Length; i++) + { + var r = cachedMeshRenderers[i]; + if (r == null) { + // explicitly do full update in case the renderers have become invalid + UpdateMaterials(false); + return; + } + } + + Shader.SetGlobalFloat("_Udon_LTCGI_GlobalEnable", screens.Length > 0 ? 1.0f : 0.0f); + + if (this != null && this.gameObject != null) + { + #if UDONSHARP + LTCGI_UdonAdapter adapter; + #pragma warning disable 618 + LTCGI_UdonAdapter[] adapters = this.gameObject.GetUdonSharpComponents<LTCGI_UdonAdapter>(); + #pragma warning restore 618 + #else + LTCGI_RuntimeAdapter adapter; + Component[] adapters = this.gameObject.GetComponents<LTCGI_RuntimeAdapter>(); + #endif + + if (adapters == null || adapters.Length == 0) + { + #if UDONSHARP + adapter = this.gameObject.AddUdonSharpComponent<LTCGI_UdonAdapter>(); + #else + adapter = this.gameObject.AddComponent<LTCGI_RuntimeAdapter>(); + #endif + } + else + { + #if UDONSHARP + adapter = (LTCGI_UdonAdapter)adapters[0]; + #else + adapter = (LTCGI_RuntimeAdapter)adapters[0]; + #endif + if (adapters.Length > 1) + { + for (int i = 1; i < adapters.Length; i++) + { + Debug.LogWarning("LTCGI: WARNING: Deleting extra *Adapter component on " + this.gameObject.name); + DestroyImmediate(adapters[i]); + } + } + } + + // update LTCGI_UdonAdapter proxy with new data + #pragma warning disable 618 + adapter.UpdateProxy(); + #pragma warning restore 618 + adapter._Renderers = cachedMeshRenderers.Where(cm => !IsEditorOnly(cm.gameObject)).ToArray(); + adapter._LTCGI_DefaultLightmap = DefaultLightmap; + adapter._LTCGI_Lightmaps = cachedMeshRenderers + .Select(r => { + if (_LTCGI_Lightmaps == null) return DefaultLightmap; + if (_LTCGI_LightmapData_key == null) return DefaultLightmap; + var lidx2 = Array.IndexOf(_LTCGI_LightmapData_key, r); + if (lidx2 < 0) return DefaultLightmap; + var lidx = _LTCGI_LightmapIndex_val[lidx2]; + return lidx != 0xFFFE && lidx >= 0 && lidx < _LTCGI_Lightmaps.Length ? + _LTCGI_Lightmaps[lidx] : DefaultLightmap; + }) + .ToArray(); + adapter._LTCGI_LightmapMult = _LTCGI_LightmapMult; + adapter._LTCGI_LightmapST = cachedMeshRenderers.Select(r => { + if (_LTCGI_LightmapData_key == null) return Vector4.zero; + var idx = Array.IndexOf(_LTCGI_LightmapData_key, r); + return idx < 0 ? Vector4.zero : _LTCGI_LightmapOffsets_val[idx]; + }).ToArray(); + var mask2d = cachedMeshRenderers.Select(x => GetMaskForRenderer(screens, x)).ToArray(); + // float[][] doesn't serialize in normal Unity, so linearize it + adapter._LTCGI_Mask = + Enumerable.Range(0, adapter._Renderers.Length) + .SelectMany(i => mask2d[i]) + .ToArray(); + // mask is reversed! 1 = not visible, 0 = visible + var avatarMask = screens.Select(x => x.AffectAvatars ? 0.0f : 1.0f); + adapter._LTCGI_MaskAvatars = avatarMask.ToArray(); + adapter._Screens = screens.Select(x => x?.gameObject).ToArray(); + adapter._LTCGI_LODs = new Texture[4]; + adapter._LTCGI_LODs[0] = VideoTexture; + adapter._LTCGI_LODs[1] = LOD1; + adapter._LTCGI_LODs[2] = LOD2; + adapter._LTCGI_LODs[3] = LOD3; + if (_LTCGI_LOD_arrays != null) + { + adapter._LTCGI_Static_LODs_0 = _LTCGI_LOD_arrays[0]; + adapter._LTCGI_Static_LODs_1 = _LTCGI_LOD_arrays[1]; + adapter._LTCGI_Static_LODs_2 = _LTCGI_LOD_arrays[2]; + adapter._LTCGI_Static_LODs_3 = _LTCGI_LOD_arrays[3]; + } + else + { + adapter._LTCGI_Static_LODs_0 = null; + adapter._LTCGI_Static_LODs_1 = null; + adapter._LTCGI_Static_LODs_2 = null; + adapter._LTCGI_Static_LODs_3 = null; + } + adapter._LTCGI_lut1 = LUT1; + adapter._LTCGI_lut2 = LUT2; + adapter._LTCGI_ScreenTransforms = _LTCGI_ScreenTransforms; + adapter._LTCGI_Vertices_0 = _LTCGI_Vertices_0; + adapter._LTCGI_Vertices_1 = _LTCGI_Vertices_1; + adapter._LTCGI_Vertices_2 = _LTCGI_Vertices_2; + adapter._LTCGI_Vertices_3 = _LTCGI_Vertices_3; + adapter._LTCGI_ExtraData = _LTCGI_ExtraData; + adapter._LTCGI_static_uniforms = staticUniformTex; + adapter._LTCGI_ScreenCount = screens.Length; + adapter._LTCGI_ScreenCountDynamic = screenCountDynamic; + // masked counts must include all masked screens up to the last non-masked one! + adapter._LTCGI_ScreenCountMasked = + mask2d.Select(mask => + Math.Max(adapter._LTCGI_ScreenCountDynamic, + Array.FindLastIndex(mask, m => m == 0.0f) + 1)).ToArray(); + adapter._LTCGI_ScreenCountMaskedAvatars = Array.FindLastIndex(screens, x => x.AffectAvatars) + 1; + adapter.BlurCRTInput = LOD1s; + + #pragma warning disable 618 + adapter.ApplyProxyModifications(); + #pragma warning restore 618 + + if (screens.Length > 0) + adapter._Initialize(); + + #if DEBUG_LOG + Debug.Log("LTCGI: updated UdonSharp adapter"); + #endif + } + + #if DEBUG_LOG + Debug.Log("LTCGI: writing auto-config file"); + #endif + LTCGI_ControllerEditor.RecalculateAutoConfig(this); + + #if DEBUG_LOG + Debug.Log("LTCGI: updating video player adapters"); + #endif + LTCGI_Controller.DetectAndEnableAdaptersForAvailableVideoplayers(); + + #if DEBUG_LOG + Debug.Log("LTCGI: update done!"); + #endif + } + + private static Texture2D staticUniformTemp = null; + private Texture2D WriteStaticUniform(LTCGI_Screen[] screens, bool fast, LTCGI_Screen fastScreen = null) + { + var curscene = EditorSceneManager.GetActiveScene().name; + var path = @"Assets\LTCGI-Generated\StaticUniform-" + curscene + ".exr"; + + if (staticUniformTemp == null) + { + staticUniformTemp = new Texture2D(6, MAX_SOURCES, UnityEngine.Experimental.Rendering.GraphicsFormat.R16G16B16A16_SFloat, UnityEngine.Experimental.Rendering.TextureCreationFlags.None); + fast = false; + } + + for (int i = 0; i < MAX_SOURCES; i++) + { + if (fast && fastScreen != null && i < screens.Length && screens[i] != fastScreen) + continue; + if (i >= screens.Length) + { + for (int w = 0; w < staticUniformTemp.width; w++) + { + staticUniformTemp.SetPixel(w, i, Color.black); + } + } + else + { + staticUniformTemp.SetPixel(0, i, (Color)_LTCGI_Vertices_0t[i]); + staticUniformTemp.SetPixel(1, i, (Color)_LTCGI_Vertices_1t[i]); + staticUniformTemp.SetPixel(2, i, (Color)_LTCGI_Vertices_2t[i]); + staticUniformTemp.SetPixel(3, i, (Color)_LTCGI_Vertices_3t[i]); + if (_LTCGI_UVs[i] != null && _LTCGI_UVs[i].Length == 4) + { + staticUniformTemp.SetPixel(4, i, (Color)new Vector4( + _LTCGI_UVs[i][0].x, _LTCGI_UVs[i][0].y, _LTCGI_UVs[i][1].x, _LTCGI_UVs[i][1].y)); + staticUniformTemp.SetPixel(5, i, (Color)new Vector4( + _LTCGI_UVs[i][2].x, _LTCGI_UVs[i][2].y, _LTCGI_UVs[i][3].x, _LTCGI_UVs[i][3].y)); + } + } + } + + staticUniformTemp.Apply(); + + if (fast) + { + return staticUniformTemp; + } + + if (!AssetDatabase.IsValidFolder("Assets/LTCGI-Generated")) + AssetDatabase.CreateFolder("Assets", "LTCGI-Generated"); + var exr = staticUniformTemp.EncodeToEXR(Texture2D.EXRFlags.OutputAsFloat); + + var existed = File.Exists(path); + byte[] prev = new byte[0]; + if (existed) + { + prev = File.ReadAllBytes(path); + } + + File.WriteAllBytes(path, exr); + AssetDatabase.Refresh(); + + var asset = AssetDatabase.LoadAssetAtPath<Texture2D>(path); + string assetPath = AssetDatabase.GetAssetPath(asset); + var importer = AssetImporter.GetAtPath(assetPath) as TextureImporter; + if (importer != null && (!prev.SequenceEqual(exr) || importer.npotScale != TextureImporterNPOTScale.None)) + { + importer.mipmapEnabled = false; + importer.textureCompression = TextureImporterCompression.Uncompressed; + importer.crunchedCompression = false; + importer.sRGBTexture = false; + importer.maxTextureSize = 8192; + importer.alphaSource = TextureImporterAlphaSource.FromInput; + importer.alphaIsTransparency = true; + importer.npotScale = TextureImporterNPOTScale.None; + importer.SaveAndReimport(); + } + + #if DEBUG_LOG + Debug.Log("LTCGI: updated static uniform declarations"); + #endif + + return asset; + } + + + + // Debug stuff, plz ignore... + private static (float[], float[], int) ReadLookupFile() + { + float[] ltc_1, ltc_2; + int n; + + using (var reader = new StreamReader("Packages\\at.pimaker.ltcgi\\Lookup Tables\\ltc_3.inc")) + { + n = int.Parse(reader.ReadLine().Trim()); + ltc_1 = new float[n*n*4]; + ltc_2 = new float[n*n*4]; + + var line = reader.ReadLine().Trim(); + var i = 0; + while (line != "}") + { + var s = line.Split(','); + var a = s[0] == "nan" || s[0] == "-nan" ? float.NaN : float.Parse(s[0]); + var b = s[1] == "nan" || s[1] == "-nan" ? float.NaN : float.Parse(s[1]); + var c = s[2] == "nan" || s[2] == "-nan" ? float.NaN : float.Parse(s[2]); + var d = s[3] == "nan" || s[3] == "-nan" ? float.NaN : float.Parse(s[3]); + ltc_1[i + 0] = a; + ltc_1[i + 1] = b; + ltc_1[i + 2] = c; + ltc_1[i + 3] = d; + i += 4; + line = reader.ReadLine().Trim(); + } + + /*i = 0; + line = reader.ReadLine().Trim(); + while (line != "}") + { + var s = line.Split(','); + var a = float.Parse(s[0]); + var b = float.Parse(s[1]); + var c = float.Parse(s[2]); + var d = float.Parse(s[3]); + ltc_2[i + 0] = a; + ltc_2[i + 1] = b; + ltc_2[i + 2] = c; + ltc_2[i + 3] = d; + i += 4; + line = reader.ReadLine().Trim(); + }*/ + } + + Debug.Log("LTCGI: Read texture with size " + n); + return (ltc_1, ltc_2, n); + } + + [MenuItem("Tools/LTCGI/Encode Lookup Textures into EXR")] + public static void EncodeLookups() + { + var (g_ltc_mat_f, g_ltc_mag_f, n) = ReadLookupFile(); + + var tex = new Texture2D(n, n, UnityEngine.Experimental.Rendering.GraphicsFormat.R32G32B32A32_SFloat, 0); + tex.SetPixelData(g_ltc_mat_f, 0); + System.IO.File.WriteAllBytes("Packages\\at.pimaker.ltcgi\\Lookup Tables\\ltc_mat_hdr_3.exr", tex.EncodeToEXR(Texture2D.EXRFlags.OutputAsFloat)); + + var tex2 = new Texture2D(n, n, UnityEngine.Experimental.Rendering.GraphicsFormat.R32G32B32A32_SFloat, 0); + tex2.SetPixelData(g_ltc_mag_f, 0); + System.IO.File.WriteAllBytes("Packages\\at.pimaker.ltcgi\\Lookup Tables\\ltc_mag_hdr_3.exr", tex2.EncodeToEXR(Texture2D.EXRFlags.OutputAsFloat)); + + GameObject.DestroyImmediate(tex); + GameObject.DestroyImmediate(tex2); + AssetDatabase.Refresh(); + } + } +#endif +} |
