dark maps, light tweaks, onemesh fixes
This commit is contained in:
4858
Assets/Maps/aerowalk_dark.map
Normal file
4858
Assets/Maps/aerowalk_dark.map
Normal file
File diff suppressed because it is too large
Load Diff
4703
Assets/Maps/aerowalk_dark_onelight.map
Normal file
4703
Assets/Maps/aerowalk_dark_onelight.map
Normal file
File diff suppressed because it is too large
Load Diff
@@ -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++;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user