From 5805529ba844b0df98c9e7cf1a929e2f427a27e9 Mon Sep 17 00:00:00 2001 From: Ari Vuollet Date: Sun, 3 Jul 2022 22:07:36 +0300 Subject: [PATCH] gi stuff, static batching toggle --- Content/Common/PlayerPrefab.prefab | 3 + Content/Materials/SimpleMapMaterial.flax | Bin 36376 -> 36538 bytes .../EngineSettings/GraphicsSettings.json | 10 +- Source/Game/Console/EngineSubsystem.cs | 90 ++++++++++++ Source/Game/Level/LevelScript.cs | 7 + Source/Game/Level/Q3MapImporter.cs | 137 ++++++++++++++---- Source/Game/Player/PlayerActor.cs | 3 +- Source/Game/Utility/AssetManager.cs | 3 + 8 files changed, 220 insertions(+), 33 deletions(-) diff --git a/Content/Common/PlayerPrefab.prefab b/Content/Common/PlayerPrefab.prefab index b266742..2a8ec6f 100644 --- a/Content/Common/PlayerPrefab.prefab +++ b/Content/Common/PlayerPrefab.prefab @@ -107,6 +107,7 @@ "ID": "56eddcef4698702bd3cb0b8a1fb3396f", "TypeName": "FlaxEngine.EmptyActor", "ParentID": "a50f3639419a8306036ecfab7115e772", + "IsActive": false, "Name": "ViewModelHolder", "Transform": { "Translation": { @@ -215,6 +216,7 @@ "ID": "12cd95b64f5145dcae7b28b7404ef512", "TypeName": "FlaxEngine.StaticModel", "ParentID": "a50f3639419a8306036ecfab7115e772", + "IsActive": false, "Name": "PlayerModel", "Transform": { "Scale": { @@ -225,6 +227,7 @@ }, "StaticFlags": 0, "Model": "b43f0f8f4aaba3f3156896a5a22ba493", + "DrawModes": 31, "Buffer": { "Entries": [ { diff --git a/Content/Materials/SimpleMapMaterial.flax b/Content/Materials/SimpleMapMaterial.flax index 6406c3d039b8d36fda2ef053562f30b9bcb17fdf..2e848ab321fa94f67188dc1a34f905a120b0d477 100644 GIT binary patch delta 4115 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 OBpm~8lk+>GNB#@XL>NE- delta 3992 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 lightEnts = new List(); private Actor worldSpawnActor = null; + private bool staticBatching_ = false; [Range(0.1f, 4f)] public float BrightnessMultiplier @@ -97,6 +101,20 @@ namespace Game set { indirectLightMultiplier_ = value; resetLights = true; } } + public bool StaticBatching + { + get => staticBatching_; + set + { + if (staticBatching_ == value) + return; + staticBatching_ = value; + + FlaxEngine.Debug.Log("StaticBatching changed, reloading map"); + LoadMap(true); + } + } + private static void QuickHull(Float3[] points, out Float3[] outVertices) { @@ -345,6 +363,21 @@ namespace Game } } + private static bool IsMapDirty(Actor worldSpawnActor, string mapPath) + { +#if FLAX_EDITOR + LevelScript levelScript = worldSpawnActor.GetScript(); + + if (levelScript.MapName != mapPath) + return true; + + DateTime timestamp = File.GetLastWriteTime(mapPath); + if (timestamp != levelScript.MapTimestamp) + return true; +#endif + return false; + } + private void LoadMap(bool forceLoad) { Stopwatch sw = Stopwatch.StartNew(); @@ -354,26 +387,14 @@ namespace Game //Console.Print("Map parsing time: " + sw.Elapsed.TotalMilliseconds + "ms"); worldSpawnActor = Actor.FindActor("WorldSpawn"); - LevelScript levelScript = worldSpawnActor?.GetScript(); if (worldSpawnActor != null) { -#if FLAX_EDITOR - DateTime timestamp = File.GetLastWriteTime(mapPath); - if (timestamp != levelScript.MapTimestamp) - { - FlaxEngine.Debug.Log($"Map dirty, reloading. {timestamp.ToString()} != {levelScript.MapTimestamp.ToString()}"); - forceLoad = true; - levelScript.MapTimestamp = timestamp; - } -#endif - if (forceLoad) - worldSpawnActor.DestroyChildren(); - else - { - //FlaxEngine.Debug.Log("Map already loaded in the scene"); - resetLights = false; + if (!forceLoad && !IsMapDirty(worldSpawnActor, mapPath)) return; - } + + FlaxEngine.Debug.Log($"Map dirty, reloading."); + worldSpawnActor.DestroyChildren(); + resetLights = false; } //else // FlaxEngine.Debug.Log("No WorldSpawn, loading map"); @@ -388,24 +409,25 @@ namespace Game ConcurrentBag sdfModels = new ConcurrentBag(); bool oneMesh = false; - bool useStaticBatching = false; + bool useStaticBatching = StaticBatching; bool convexMesh = true; if (worldSpawnActor == null) { worldSpawnActor = Actor.AddChild(); worldSpawnActor.Name = "WorldSpawn"; - - levelScript = worldSpawnActor.AddScript(); -#if FLAX_EDITOR - levelScript.MapTimestamp = File.GetLastWriteTime(mapPath); -#endif worldSpawnActor.HideFlags &= ~HideFlags.DontSave; //worldSpawnActor.HideFlags |= HideFlags.DontSave; //worldSpawnActor.HideFlags |= HideFlags.DontSelect; } - else - levelScript = worldSpawnActor.GetScript(); + + LevelScript levelScript = + worldSpawnActor.GetScript() ?? worldSpawnActor.AddScript(); + +#if FLAX_EDITOR + levelScript.MapTimestamp = File.GetLastWriteTime(mapPath); + levelScript.MapName = mapPath; +#endif if (!oneMesh) { @@ -1041,6 +1063,45 @@ namespace Game //Debug.Log($"generate:{generateSdf}, GI:{Graphics.PostProcessSettings.GlobalIllumination.Mode != GlobalIlluminationMode.None}, {sdfModels.Count}"); if (generateSdf /*&& Graphics.PostProcessSettings.GlobalIllumination.Mode != GlobalIlluminationMode.None*/ && sdfModels.Count > 1) { + int modelIndex = 0; + + // TODO: read sdf data from texture and dump it to file, and reuse it when generating sdf data + using var sha1 = new SHA1Managed(); + string mapHash = sha1.ComputeHash(Encoding.UTF8.GetBytes(levelScript.MapName + levelScript.MapTimestamp.Ticks.ToString())).ToString(); + + foreach (var model in sdfModels.ToList()) + { + string sdfDataPath = Path.Combine(AssetManager.CachePath, "MapSdfData", + $"{mapHash}_brush{modelIndex+1}"); + + /*if (File.Exists(sdfDataPath)) + { + sdfModels.TryTake(out var model_); + + T RawDeserialize(byte[] rawData, int position) + { + int rawsize = Marshal.SizeOf(typeof(T)); + if (rawsize > rawData.Length - position) + throw new ArgumentException("Not enough data to fill struct. Array length from position: " + + (rawData.Length - position) + ", Struct length: " + rawsize); + IntPtr buffer = Marshal.AllocHGlobal(rawsize); + Marshal.Copy(rawData, position, buffer, rawsize); + T retobj = (T)Marshal.PtrToStructure(buffer, typeof(T)); + Marshal.FreeHGlobal(buffer); + return retobj; + } + + + + ModelBase.SDFData sdfData = new ModelBase.SDFData(); + sdfData.Texture + + model.SetSDF(sdfData); + }*/ + modelIndex++; + } + + var task = Task.Run(() => { Stopwatch sw = Stopwatch.StartNew(); @@ -1048,14 +1109,34 @@ namespace Game ParallelOptions opts = new ParallelOptions(); FlaxEngine.Debug.Log("processorcount: " + Environment.ProcessorCount); + float backfacesThreshold = 0.15f; if (useStaticBatching) - opts.MaxDegreeOfParallelism = 2;//Environment.ProcessorCount / 2; - Parallel.ForEach(sdfModels, opts, model => + { + opts.MaxDegreeOfParallelism = 2; //Environment.ProcessorCount / 2; + //backfacesThreshold = 1f; + } + + Parallel.ForEach(sdfModels, opts, (model, _, index) => { if (model.WaitForLoaded()) throw new Exception("model was not loaded"); - model.GenerateSDF(0.9f, 6, true, 0.15f); + model.GenerateSDF(0.9f, 6, true, backfacesThreshold); + + /*byte[] RawSerialize(object anything) + { + int rawSize = Marshal.SizeOf(anything); + IntPtr buffer = Marshal.AllocHGlobal(rawSize); + Marshal.StructureToPtr(anything, buffer, false); + byte[] rawDatas = new byte[rawSize]; + Marshal.Copy(buffer, rawDatas, 0, rawSize); + Marshal.FreeHGlobal(buffer); + return rawDatas; + } + + string sdfDataPath = Path.Combine(AssetManager.CachePath, "MapSdfData", + $"{mapHash}_brush{modelIndex+1}");*/ + }); FlaxEngine.Debug.Log($"Generated level SDF in {sw.Elapsed.TotalMilliseconds}ms"); diff --git a/Source/Game/Player/PlayerActor.cs b/Source/Game/Player/PlayerActor.cs index b55e91b..9bf5954 100644 --- a/Source/Game/Player/PlayerActor.cs +++ b/Source/Game/Player/PlayerActor.cs @@ -63,7 +63,8 @@ namespace Game if (playerId == NetworkManager.LocalPlayerClientId) { FindActor("CameraHolder").IsActive = true; - FindActor("ViewModelHolder").IsActive = true; + //FindActor("ViewModelHolder").IsActive = true; + FindActor("PlayerModel").IsActive = false; } } diff --git a/Source/Game/Utility/AssetManager.cs b/Source/Game/Utility/AssetManager.cs index d924979..a79dac0 100644 --- a/Source/Game/Utility/AssetManager.cs +++ b/Source/Game/Utility/AssetManager.cs @@ -11,6 +11,9 @@ namespace Game public static string DemoPath { get; private set; } = Path.Combine(Directory.GetCurrentDirectory(), "Demos"); + public static string CachePath { get; private set; } = + Path.Combine(Directory.GetCurrentDirectory(), "Cache"); + public static GameplayGlobals Globals { get; private set; } public static Config Config { get; private set; }