dark maps, light tweaks, onemesh fixes

This commit is contained in:
2022-06-09 20:42:03 +03:00
parent 5d12548cbc
commit 17296d3749
3 changed files with 9742 additions and 42 deletions

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,8 +1,11 @@
using System; using System;
using System.Collections.Concurrent;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using FlaxEngine; using FlaxEngine;
using FlaxEngine.Assertions; using FlaxEngine.Assertions;
using Console = Game.Console; using Console = Game.Console;
@@ -40,10 +43,48 @@ namespace Game
//private string mapPath = @"C:\dev\GoakeFlax\Assets\Maps\problematic.map"; //private string mapPath = @"C:\dev\GoakeFlax\Assets\Maps\problematic.map";
public bool importLights = false; public bool importLights = false;
private bool generateSdf = true;
private Model model; private Model model;
private MaterialBase missingMaterial; private MaterialBase missingMaterial;
private bool dirtyLights = false;
private float brightnessMultiplier_ = 0.82f;
private float lightRadiusMultiplier_ = 9.45f;
private float fallOffExponent_ = 2.0f;
private float saturationMultiplier_ = 1.0f;
private List<MapEntity> lightEnts = new List<MapEntity>();
[Range(0.1f, 4f)]
public float BrightnessMultiplier
{
get => brightnessMultiplier_;
set { brightnessMultiplier_ = value; dirtyLights = true; }
}
[Range(0.1f, 40f)]
public float LightRadiusMultiplier
{
get => lightRadiusMultiplier_;
set { lightRadiusMultiplier_ = value; dirtyLights = true; }
}
[Range(2f, 8f)]
public float FallOffExponent
{
get => fallOffExponent_;
set { fallOffExponent_ = value; dirtyLights = true; }
}
[Range(0.01f, 1f)]
public float SaturationMultiplier
{
get => saturationMultiplier_;
set { saturationMultiplier_ = value; dirtyLights = true; }
}
private static void QuickHull(Vector3[] points, out Vector3[] outVertices) private static void QuickHull(Vector3[] points, out Vector3[] outVertices)
{ {
var verts = new List<Vector3>(); var verts = new List<Vector3>();
@@ -211,6 +252,8 @@ namespace Game
Debug.Log("OnDeserialized: " + Editor.IsPlayMode); Debug.Log("OnDeserialized: " + Editor.IsPlayMode);
} }
#endif #endif
private ConcurrentBag<Model> sdfModels = new ConcurrentBag<Model>();
private Task task;
public override void OnStart() public override void OnStart()
{ {
#if false #if false
@@ -245,6 +288,50 @@ namespace Game
//Debug.Log("LoadMap"); //Debug.Log("LoadMap");
LoadMap(false); LoadMap(false);
if (generateSdf && Graphics.EnableGlobalSDF && sdfModels.Count > 1)
{
task = Task.Run(() =>
{
Stopwatch sw = Stopwatch.StartNew();
Console.Print($"Generating level SDF ({sdfModels.Count} models)...");
Parallel.ForEach(sdfModels, new ParallelOptions() { MaxDegreeOfParallelism = 1 }, model =>
{
if (model.WaitForLoaded())
throw new Exception("model was not loaded");
model.GenerateSDF();
});
Console.Print($"Generated level SDF in {sw.Elapsed.TotalMilliseconds}ms");
});
}
}
public override void OnUpdate()
{
if (dirtyLights)
{
Actor worldSpawnActor = Actor.GetChild("WorldSpawn");
foreach (var light in worldSpawnActor.GetChildren<Light>())
Destroy(light);
int lightIndex = 0;
foreach (MapEntity entity in root.entities.Where(x => x.properties.ContainsKey("classname")))
switch (entity.properties["classname"])
{
case "light":
if (importLights)
ParseLight(entity, worldSpawnActor, ref lightIndex);
break;
//case "info_player_deathmatch":
// ParsePlayerSpawn(entity, worldSpawnActor, ref playerSpawnIndex);
// break;
}
dirtyLights = false;
}
} }
private void LoadMap(bool forceLoad) private void LoadMap(bool forceLoad)
@@ -280,6 +367,14 @@ namespace Game
bool oneMesh = false; bool oneMesh = false;
bool convexMesh = true; bool convexMesh = true;
if (worldSpawnActor == null)
{
worldSpawnActor = Actor.AddChild<Actor>();
worldSpawnActor.Name = "WorldSpawn";
worldSpawnActor.HideFlags |= HideFlags.DontSave;
//worldSpawnActor.HideFlags |= HideFlags.DontSelect;
}
if (!oneMesh) if (!oneMesh)
{ {
var materials = new Dictionary<string, MaterialBase>(); var materials = new Dictionary<string, MaterialBase>();
@@ -291,14 +386,6 @@ namespace Game
materials.Add(m.name, m.asset); materials.Add(m.name, m.asset);
} }
if (worldSpawnActor == null)
{
worldSpawnActor = Actor.AddChild<Actor>();
worldSpawnActor.Name = "WorldSpawn";
worldSpawnActor.HideFlags |= HideFlags.DontSave;
//worldSpawnActor.HideFlags |= HideFlags.DontSelect;
}
var brushGeometries = new List<BrushGeometry>(root.entities[0].brushes.Count); var brushGeometries = new List<BrushGeometry>(root.entities[0].brushes.Count);
// pass 1: triangulation // pass 1: triangulation
@@ -492,13 +579,16 @@ namespace Game
geom.model.MaterialSlots[i].Material = geom.meshes[i].material; geom.model.MaterialSlots[i].Material = geom.meshes[i].material;
} }
//Not supported yet, should be done here
//geom.model.GenerateSDF();
brushIndex++; brushIndex++;
} }
sw.Stop(); sw.Stop();
//Console.Print("Pass 2: texturing: " + sw.Elapsed.TotalMilliseconds + "ms"); //Console.Print("Pass 2: texturing: " + sw.Elapsed.TotalMilliseconds + "ms");
// pass 3: collision // pass 3: static models & collision
sw.Restart(); sw.Restart();
brushIndex = 0; brushIndex = 0;
foreach (BrushGeometry geom in brushGeometries) foreach (BrushGeometry geom in brushGeometries)
@@ -515,6 +605,8 @@ namespace Game
for (uint i = 0; i < indices.Length; i++) for (uint i = 0; i < indices.Length; i++)
indices[i] = i; indices[i] = i;
bool isClipMaterial = false;
bool isMissingMaterial = false;
if (geom.meshes.Length == 1) if (geom.meshes.Length == 1)
{ {
MaterialParameter info = geom.meshes[0].material.GetParameter("IsClipMaterial"); MaterialParameter info = geom.meshes[0].material.GetParameter("IsClipMaterial");
@@ -522,10 +614,26 @@ namespace Game
{ {
var entries = childModel.Entries; var entries = childModel.Entries;
entries[0].Visible = false; entries[0].Visible = false;
entries[0].ShadowsMode = ShadowsCastingMode.None;
entries[0].ReceiveDecals = false;
childModel.Entries = entries; childModel.Entries = entries;
isClipMaterial = true;
} }
if (geom.meshes[0].material == missingMaterial)
isMissingMaterial = true;
} }
/*{
var entries = childModel.Entries;
for (int i=0; i < entries.Length; i++)
entries[i].Visible = false;
childModel.Entries = entries;
}*/
if (!isClipMaterial && !isMissingMaterial)
sdfModels.Add(geom.model);
CollisionData collisionData = Content.CreateVirtualAsset<CollisionData>(); CollisionData collisionData = Content.CreateVirtualAsset<CollisionData>();
if (collisionData.CookCollision( if (collisionData.CookCollision(
convexMesh ? CollisionDataType.ConvexMesh : CollisionDataType.TriangleMesh, geom.vertices, convexMesh ? CollisionDataType.ConvexMesh : CollisionDataType.TriangleMesh, geom.vertices,
@@ -680,10 +788,21 @@ namespace Game
model.LODs[0].Meshes[0].UpdateMesh(vertices.ToArray(), (int[])(object)triangles, normals.ToArray(), model.LODs[0].Meshes[0].UpdateMesh(vertices.ToArray(), (int[])(object)triangles, normals.ToArray(),
null, uvs.ToArray()); null, uvs.ToArray());
StaticModel childModel = Actor.AddChild<StaticModel>(); sdfModels.Add(model);
StaticModel childModel = worldSpawnActor.AddChild<StaticModel>();
childModel.Name = "MapModel"; childModel.Name = "MapModel";
childModel.Model = model; childModel.Model = model;
childModel.SetMaterial(0, missingMaterial); //childModel.SetMaterial(0, missingMaterial);
string workDir = Directory.GetCurrentDirectory();
string matBasePath = Path.Combine(workDir, "Content", "Materials");
string assetPath = Path.Combine(matBasePath, "dev/dev_128_gray" + ".flax");
var brushMaterial = Content.Load<MaterialBase>(assetPath);
if (brushMaterial != null)
childModel.SetMaterial(0, brushMaterial);
else
childModel.SetMaterial(0, missingMaterial);
CollisionData collisionData = Content.CreateVirtualAsset<CollisionData>(); CollisionData collisionData = Content.CreateVirtualAsset<CollisionData>();
if (collisionData.CookCollision(CollisionDataType.TriangleMesh, vertices.ToArray(), if (collisionData.CookCollision(CollisionDataType.TriangleMesh, vertices.ToArray(),
@@ -710,6 +829,7 @@ namespace Game
case "light": case "light":
if (importLights) if (importLights)
ParseLight(entity, worldSpawnActor, ref lightIndex); ParseLight(entity, worldSpawnActor, ref lightIndex);
lightEnts.Add(entity);
break; break;
case "info_player_deathmatch": case "info_player_deathmatch":
ParsePlayerSpawn(entity, worldSpawnActor, ref playerSpawnIndex); ParsePlayerSpawn(entity, worldSpawnActor, ref playerSpawnIndex);
@@ -722,58 +842,77 @@ namespace Game
private void ParseLight(MapEntity entity, Actor worldSpawnActor, ref int lightIndex) private void ParseLight(MapEntity entity, Actor worldSpawnActor, ref int lightIndex)
{ {
const bool lightsUseInverseSquaredFalloff = true; int preset = 3;
//Console.Print("light"); //Console.Print("light");
PointLight light = worldSpawnActor.AddChild<PointLight>(); PointLight light = worldSpawnActor.AddChild<PointLight>();
light.Name = "Light_" + lightIndex; light.Name = "Light_" + lightIndex;
light.LocalPosition = ParseOrigin(entity.properties["origin"]); light.LocalPosition = ParseOrigin(entity.properties["origin"]);
//"_color" "0.752941 0.752941 0"
//"light" "200"
if (entity.properties.TryGetValue("_color", out string colorStr)) if (entity.properties.TryGetValue("_color", out string colorStr))
light.Color = ParseColor(colorStr); light.Color = ParseColor(colorStr);
float lightamm = 200f; float lightamm = 300f;
if (entity.properties.TryGetValue("light", out string lightStr)) if (entity.properties.TryGetValue("light", out string lightStr))
lightamm = float.Parse(lightStr); lightamm = float.Parse(lightStr);
float radamm = 64f;
if (entity.properties.TryGetValue("radius", out string radStr))
radamm = float.Parse(radStr);
light.Brightness = lightamm / 128f;
light.Layer = 1; light.Layer = 1;
light.Radius = 1000f * 0.5f;
light.UseInverseSquaredFalloff = false; light.UseInverseSquaredFalloff = false;
light.FallOffExponent = 8; light.FallOffExponent = 8;
light.ShadowsDistance = 2000f * 1f; light.ShadowsDistance = 500f;
light.ShadowsDepthBias = 0.027f;//0.005f;
if (preset == 0) // most accurate?, huge radius and low performance
if (lightsUseInverseSquaredFalloff)
{ {
light.Brightness = lightamm / 93f;
light.Radius = radamm * 12.5f;
light.FallOffExponent = 3.33f;
light.ShadowsDepthBias = 0.0565f;
light.Brightness *= 0.7837f;
light.Radius *= 0.83375f;
var hsv = light.Color.ToHSV();
hsv.Y *= 0.8f;
light.Color = Color.FromHSV(hsv);
}
else if (preset == 1) //
{
light.Radius = 250f;
light.FallOffExponent = 2f;
light.Brightness = (lightamm / 128f) * 1.25f;
}
else if (preset == 2)
{
light.Radius = 200f;
light.FallOffExponent = 2f;
light.Brightness = (lightamm / 128f) * 1.6f;
}
else //if (preset == 3)
{
light.Radius = radamm * LightRadiusMultiplier;
light.FallOffExponent = FallOffExponent;
light.Brightness = (lightamm / 128f) * BrightnessMultiplier;
light.ShadowsNormalOffsetScale = 10f;
light.ShadowsFadeDistance = 100f; // for debugging
light.ShadowsDistance = 500f; light.ShadowsDistance = 500f;
light.ShadowsDepthBias = 0.027f;//0.005f;
if (true)
{
light.Radius *= 0.5f;
light.FallOffExponent = 2f;
light.Brightness *= 1.25f;
}
else
{
light.Radius *= 0.4f;
light.FallOffExponent = 2f;
light.Brightness *= 1.6f;
}
//light.Brightness *= 2500f;
//light.UseInverseSquaredFalloff = true;
}
if (true) var hsv = light.Color.ToHSV();
{ hsv.Y *= SaturationMultiplier;
// match FTEQW dynamic only light values light.Color = Color.FromHSV(hsv);
}
//Console.Print("light pos: " + light.Position); light.ShadowsDepthBias = 0.0565f;
// if low quality shadows
light.ShadowsDepthBias = 0.2492f;
}
lightIndex++; lightIndex++;
} }