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 6406c3d..2e848ab 100644 Binary files a/Content/Materials/SimpleMapMaterial.flax and b/Content/Materials/SimpleMapMaterial.flax differ diff --git a/Content/Settings/EngineSettings/GraphicsSettings.json b/Content/Settings/EngineSettings/GraphicsSettings.json index 4fe9a14..2780e34 100644 --- a/Content/Settings/EngineSettings/GraphicsSettings.json +++ b/Content/Settings/EngineSettings/GraphicsSettings.json @@ -6,7 +6,7 @@ "UseVSync": false, "AAQuality": 3, "SSRQuality": 3, - "SSAOQuality": 3, + "SSAOQuality": 0, "VolumetricFogQuality": 3, "ShadowsQuality": 3, "ShadowMapsQuality": 3, @@ -15,6 +15,7 @@ "GlobalSDFQuality": 2, "GenerateSDFOnModelImport": true, "GIQuality": 2, + "GIProbesSpacing": 300.0, "GlobalSurfaceAtlasResolution": 2048, "PostProcessSettings": { "AO": { @@ -27,11 +28,12 @@ "FadeDistance": 500.0 }, "GI": { - "OverrideFlags": 27, + "OverrideFlags": 63, "Mode": 1, "Intensity": 1.0, - "TemporalResponse": 0.9, - "Distance": 7000.0, + "BounceIntensity": 2.0, + "TemporalResponse": 1.0, + "Distance": 20000.0, "FallbackIrradiance": { "R": 1.0, "G": 0.0, diff --git a/Source/Game/Console/EngineSubsystem.cs b/Source/Game/Console/EngineSubsystem.cs index 0f324f9..e0c8be2 100644 --- a/Source/Game/Console/EngineSubsystem.cs +++ b/Source/Game/Console/EngineSubsystem.cs @@ -282,6 +282,96 @@ namespace Game } } + [ConsoleVariable("r_gi_bounce")] + public static string GlobalIlluminationBounce + { + get + { + return Graphics.PostProcessSettings.GlobalIllumination.BounceIntensity.ToString(); + } + set + { + if (float.TryParse(value, out float valueFloat)) + { + valueFloat = Mathf.Clamp(valueFloat, 0.0f, 999.0f); + + PostProcessSettings postProcessSettings = Graphics.PostProcessSettings; + + GlobalIlluminationSettings giSettings = postProcessSettings.GlobalIllumination; + giSettings.BounceIntensity = valueFloat; + postProcessSettings.GlobalIllumination = giSettings; + + Graphics.PostProcessSettings = postProcessSettings; + } + } + } + + [ConsoleVariable("r_gi_spacing")] + public static string GlobalIlluminationProbeSpacing + { + get + { + return Graphics.GIProbesSpacing.ToString(); + } + set + { + if (float.TryParse(value, out float valueFloat)) + { + valueFloat = Mathf.Clamp(valueFloat, 0.0f, 999.0f); + + Graphics.GIProbesSpacing = valueFloat; + } + } + } + + [ConsoleVariable("r_gi_time")] + public static string GlobalIlluminationTime + { + get + { + return Graphics.PostProcessSettings.GlobalIllumination.TemporalResponse.ToString(); + } + set + { + if (float.TryParse(value, out float valueFloat)) + { + valueFloat = Mathf.Clamp(valueFloat, 0.0f, 10.0f); + + PostProcessSettings postProcessSettings = Graphics.PostProcessSettings; + + GlobalIlluminationSettings giSettings = postProcessSettings.GlobalIllumination; + giSettings.TemporalResponse = valueFloat; + postProcessSettings.GlobalIllumination = giSettings; + + Graphics.PostProcessSettings = postProcessSettings; + } + } + } + + [ConsoleVariable("r_gi_distance")] + public static string GlobalIlluminationDistance + { + get + { + return Graphics.PostProcessSettings.GlobalIllumination.Distance.ToString(); + } + set + { + if (float.TryParse(value, out float valueFloat)) + { + valueFloat = Mathf.Clamp(valueFloat, 0.0f, 10000000.0f); + + PostProcessSettings postProcessSettings = Graphics.PostProcessSettings; + + GlobalIlluminationSettings giSettings = postProcessSettings.GlobalIllumination; + giSettings.Distance = valueFloat; + postProcessSettings.GlobalIllumination = giSettings; + + Graphics.PostProcessSettings = postProcessSettings; + } + } + } + [ConsoleVariable("r_shadows")] public static string SceneShadows { diff --git a/Source/Game/Level/LevelScript.cs b/Source/Game/Level/LevelScript.cs index c75837d..dc6ad8f 100644 --- a/Source/Game/Level/LevelScript.cs +++ b/Source/Game/Level/LevelScript.cs @@ -7,6 +7,13 @@ namespace Game [ExecuteInEditMode] public class LevelScript : Script { + public string MapName; + public DateTime MapTimestamp; + } + + public class LevelScript2 : Script + { + public string MapName; public DateTime MapTimestamp; } } \ No newline at end of file diff --git a/Source/Game/Level/Q3MapImporter.cs b/Source/Game/Level/Q3MapImporter.cs index a87e092..20ba284 100644 --- a/Source/Game/Level/Q3MapImporter.cs +++ b/Source/Game/Level/Q3MapImporter.cs @@ -4,6 +4,9 @@ using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; +using System.Runtime.InteropServices; +using System.Security.Cryptography; +using System.Text; using System.Threading; using System.Threading.Tasks; using FlaxEditor; @@ -61,6 +64,7 @@ namespace Game private float indirectLightMultiplier_ = 1.0f; private List 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; }