From a631f90707037bee86ff0f61b62e1c18e94cb70e Mon Sep 17 00:00:00 2001 From: Asval Date: Sun, 11 May 2025 03:59:58 +0200 Subject: [PATCH] faster --- FModel/Views/Snooper/AssetPool.cs | 196 ++++++++++-------- FModel/Views/Snooper/Models/Section.cs | 4 +- FModel/Views/Snooper/Models/UModel.cs | 58 ++++-- FModel/Views/Snooper/Renderer.cs | 2 +- FModel/Views/Snooper/Shading/Material.cs | 52 ++--- .../Views/Snooper/Textures/AbstractTexture.cs | 2 +- 6 files changed, 162 insertions(+), 152 deletions(-) diff --git a/FModel/Views/Snooper/AssetPool.cs b/FModel/Views/Snooper/AssetPool.cs index 123c06be..69fecf15 100644 --- a/FModel/Views/Snooper/AssetPool.cs +++ b/FModel/Views/Snooper/AssetPool.cs @@ -4,7 +4,6 @@ using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Threading; -using System.Threading.Tasks; using CUE4Parse_Conversion.Meshes; using CUE4Parse_Conversion.Textures; using CUE4Parse.UE4.Assets.Exports; @@ -30,8 +29,8 @@ public class AssetPool public FGuid SelectedModel { get; private set; } + private readonly object _lock = new (); public readonly ConcurrentBag Queue; - public readonly Dictionary Models; public readonly Dictionary Textures; @@ -40,7 +39,6 @@ public class AssetPool private AssetPool() { Queue = []; - Models = []; Textures = []; @@ -49,22 +47,20 @@ public class AssetPool public void OnTick() { - var current = 0; while (Queue.TryTake(out var asset)) { asset.Setup(); switch (asset) { case UModel uModel: - Models[asset.Guid] = uModel; + Models.Add(asset.Guid, uModel); break; case ITexture texture: - Textures[asset.Guid] = texture; + Textures.Add(asset.Guid, texture); break; } - current++; - if (current >= 1) break; + break; // debug } foreach (var model in Models.Values) @@ -78,13 +74,18 @@ public class AssetPool ThreadPool.QueueUserWorkItem(_ => { var guid = staticMesh.LightingGuid; - if (TryGetModel(guid, out var model)) + lock (_lock) { - model.AddInstance(Transform.Identity); - } - else if (staticMesh.TryConvert(out var mesh)) - { - Queue.Add(new StaticModel(staticMesh, mesh) { Guid = guid }); + if (TryGetModel(guid, out var model)) + { + model.AddInstance(Transform.Identity); + } + else if (staticMesh.TryConvert(out var mesh)) + { + model = new StaticModel(staticMesh, mesh) { Guid = guid }; + model.ScanMaterials(); + Queue.Add(model); + } } }); } @@ -93,9 +94,14 @@ public class AssetPool ThreadPool.QueueUserWorkItem(_ => { var guid = new FGuid((uint) skeletalMesh.GetFullName().GetHashCode()); - if (!Models.ContainsKey(guid) && skeletalMesh.TryConvert(out var mesh)) + lock (_lock) { - Queue.Add(new SkeletalModel(skeletalMesh, mesh) { Guid = guid }); + if (!TryGetModel(guid, out var _) && skeletalMesh.TryConvert(out var mesh)) + { + var model = new SkeletalModel(skeletalMesh, mesh) { Guid = guid }; + model.ScanMaterials(); + Queue.Add(model); + } } }); } @@ -104,9 +110,14 @@ public class AssetPool ThreadPool.QueueUserWorkItem(_ => { var guid = skeleton.Guid; - if (!Models.ContainsKey(guid) && skeleton.TryConvert(out var _, out var box)) + lock (_lock) { - Queue.Add(new SkeletalModel(skeleton, box) { Guid = guid }); + if (!TryGetModel(guid, out var _) && skeleton.TryConvert(out var _, out var box)) + { + var model = new SkeletalModel(skeleton, box) { Guid = guid }; + model.ScanMaterials(); + Queue.Add(model); + } } }); } @@ -115,25 +126,24 @@ public class AssetPool ThreadPool.QueueUserWorkItem(_ => { var guid = texture.LightingGuid; - if (TryGet(guid, out var _)) + lock (_lock) { - // do something here?? - } - else if (texture.Format != EPixelFormat.PF_BC6H) // BC6H is not supported by Decode thus randomly crashes the app - { - var bitmap = texture switch + if (!TryGetBitmap(guid, out var _) && texture.Format != EPixelFormat.PF_BC6H) // BC6H is not supported by Decode thus randomly crashes the app { - UTexture2D texture2D => texture2D.Decode(UserSettings.Default.PreviewMaxTextureSize, UserSettings.Default.CurrentDir.TexturePlatform), - UTexture2DArray texture2DArray => texture2DArray.DecodeTextureArray(UserSettings.Default.CurrentDir.TexturePlatform)?.FirstOrDefault(), - _ => texture.Decode(UserSettings.Default.CurrentDir.TexturePlatform) - }; + var bitmap = texture switch + { + UTexture2D texture2D => texture2D.Decode(UserSettings.Default.PreviewMaxTextureSize, UserSettings.Default.CurrentDir.TexturePlatform), + UTexture2DArray texture2DArray => texture2DArray.DecodeTextureArray(UserSettings.Default.CurrentDir.TexturePlatform)?.FirstOrDefault(), + _ => texture.Decode(UserSettings.Default.CurrentDir.TexturePlatform) + }; - if (bitmap is not null) - { - var t = new BitmapTexture(bitmap.ToSkBitmap(), texture); - if (fix) t.FixChannels(_project); + if (bitmap is not null) + { + var t = new BitmapTexture(bitmap.ToSkBitmap(), texture); + if (fix) t.FixChannels(_project); - Queue.Add(t); + Queue.Add(t); + } } } }); @@ -145,66 +155,71 @@ public class AssetPool { var bSpline = staticMeshComponent is USplineMeshComponent; var guid = staticMesh.LightingGuid; - if (TryGetModel(guid, out var model)) + lock (_lock) { - model.AddInstance(transform); - if (bSpline && model is SplineModel splineModel) - splineModel.AddComponent((USplineMeshComponent)staticMeshComponent); - } - else if (staticMesh.TryConvert(out var mesh)) - { - model = bSpline ? new SplineModel(staticMesh, mesh, (USplineMeshComponent)staticMeshComponent, transform) : new StaticModel(staticMesh, mesh, transform); - model.Guid = guid; - - if (actor.TryGetAllValues(out FPackageIndex[] textureData, "TextureData")) + if (TryGetModel(guid, out var model)) { - var material = model.Materials.FirstOrDefault(); - if (material is { IsUsed: true }) + model.AddInstance(transform); + if (bSpline && model is SplineModel splineModel) + splineModel.AddComponent((USplineMeshComponent)staticMeshComponent); + } + else if (staticMesh.TryConvert(out var mesh)) + { + model = bSpline ? new SplineModel(staticMesh, mesh, (USplineMeshComponent)staticMeshComponent, transform) : new StaticModel(staticMesh, mesh, transform); + model.IsTwoSided = actor.GetOrDefault("bMirrored", staticMeshComponent.GetOrDefault("bDisallowMeshPaintPerInstance", model.IsTwoSided)); + model.Guid = guid; + + if (actor.TryGetAllValues(out FPackageIndex[] textureData, "TextureData")) { - for (int j = 0; j < textureData.Length; j++) + var material = model.Materials.FirstOrDefault(); + if (material is { IsUsed: true }) { - if (textureData[j]?.Load() is not { } textureDataIdx) - continue; + for (int j = 0; j < textureData.Length; j++) + { + if (textureData[j]?.Load() is not { } textureDataIdx) + continue; - if (textureDataIdx.TryGetValue(out FPackageIndex overrideMaterial, "OverrideMaterial") && - overrideMaterial.TryLoad(out var oMaterial) && oMaterial is UMaterialInterface oUnrealMaterial) - material.SwapMaterial(oUnrealMaterial); + if (textureDataIdx.TryGetValue(out FPackageIndex overrideMaterial, "OverrideMaterial") && + overrideMaterial.TryLoad(out var oMaterial) && oMaterial is UMaterialInterface oUnrealMaterial) + material.SwapMaterial(oUnrealMaterial); - WorldTextureData(material, textureDataIdx, "Diffuse", j switch - { - 0 => "Diffuse", - > 0 => $"Diffuse_Texture_{j + 1}", - _ => CMaterialParams2.FallbackDiffuse - }); - WorldTextureData(material, textureDataIdx, "Normal", j switch - { - 0 => "Normals", - > 0 => $"Normals_Texture_{j + 1}", - _ => CMaterialParams2.FallbackNormals - }); - WorldTextureData(material, textureDataIdx, "Specular", j switch - { - 0 => "SpecularMasks", - > 0 => $"SpecularMasks_{j + 1}", - _ => CMaterialParams2.FallbackNormals - }); + WorldTextureData(material, textureDataIdx, "Diffuse", j switch + { + 0 => "Diffuse", + > 0 => $"Diffuse_Texture_{j + 1}", + _ => CMaterialParams2.FallbackDiffuse + }); + WorldTextureData(material, textureDataIdx, "Normal", j switch + { + 0 => "Normals", + > 0 => $"Normals_Texture_{j + 1}", + _ => CMaterialParams2.FallbackNormals + }); + WorldTextureData(material, textureDataIdx, "Specular", j switch + { + 0 => "SpecularMasks", + > 0 => $"SpecularMasks_{j + 1}", + _ => CMaterialParams2.FallbackNormals + }); + } } } - } - if (staticMeshComponent.TryGetValue(out FPackageIndex[] overrideMaterials, "OverrideMaterials")) - { - for (var j = 0; j < overrideMaterials.Length && j < model.Sections.Length; j++) + if (staticMeshComponent.TryGetValue(out FPackageIndex[] overrideMaterials, "OverrideMaterials")) { - var matIndex = model.Sections[j].MaterialIndex; - if (matIndex < 0 || matIndex >= model.Materials.Length || matIndex >= overrideMaterials.Length || - overrideMaterials[matIndex].Load() is not UMaterialInterface unrealMaterial) continue; + for (var j = 0; j < overrideMaterials.Length && j < model.Sections.Length; j++) + { + var matIndex = model.Sections[j].MaterialIndex; + if (matIndex < 0 || matIndex >= model.Materials.Length || matIndex >= overrideMaterials.Length || + overrideMaterials[matIndex].Load() is not UMaterialInterface unrealMaterial) continue; - model.Materials[matIndex].SwapMaterial(unrealMaterial); + model.Materials[matIndex].SwapMaterial(unrealMaterial); + } } - } - Queue.Add(model); + model.ScanMaterials(); + Queue.Add(model); + } } }); @@ -215,8 +230,17 @@ public class AssetPool } } - public bool TryGet(FGuid guid, [MaybeNullWhen(true)] out T asset) + private bool TryGet(FGuid guid, [MaybeNullWhen(true)] out T asset) { + foreach (var a in Queue) + { + if (a.Guid == guid && a is T value) + { + asset = value; + return true; + } + } + if (Models.TryGetValue(guid, out var m) && m is T model) { asset = model; @@ -229,21 +253,13 @@ public class AssetPool return true; } - foreach (var a in Queue) - { - if (a.Guid == guid && a is T value) - { - asset = value; - return true; - } - } - asset = default; return false; } public bool TryGetModel([MaybeNullWhen(false)] out UModel model) => TryGet(SelectedModel, out model); public bool TryGetModel(FGuid guid, [MaybeNullWhen(false)] out UModel model) => TryGet(guid, out model); public bool TryGetTexture(FGuid guid, [MaybeNullWhen(false)] out ITexture texture) => TryGet(guid, out texture); + public bool TryGetBitmap(FGuid guid, [MaybeNullWhen(false)] out BitmapTexture texture) => TryGet(guid, out texture); public void SelectModel(FGuid guid) { diff --git a/FModel/Views/Snooper/Models/Section.cs b/FModel/Views/Snooper/Models/Section.cs index 57e1f70d..be765837 100644 --- a/FModel/Views/Snooper/Models/Section.cs +++ b/FModel/Views/Snooper/Models/Section.cs @@ -23,11 +23,9 @@ public class Section Color = Constants.COLOR_PALETTE[MaterialIndex % Constants.PALETTE_LENGTH]; } - public void ValidateMaterial(Material material, int uvCount) + public void ValidateSection(Material material) { material.IsUsed = true; Show = !material.Parameters.IsNull && !material.Parameters.IsTranslucent; - - material.Validate(uvCount); } } diff --git a/FModel/Views/Snooper/Models/UModel.cs b/FModel/Views/Snooper/Models/UModel.cs index 530f9917..08e0b10f 100644 --- a/FModel/Views/Snooper/Models/UModel.cs +++ b/FModel/Views/Snooper/Models/UModel.cs @@ -87,23 +87,18 @@ public abstract class UModel : IRenderableModel UvCount = 1; Box = new FBox(new FVector(-2f), new FVector(2f)); - Sockets = new List(); - Collisions = new List(); - Transforms = new List(); + Sockets = []; + Collisions = []; + Transforms = []; } - protected UModel(UObject export) + protected UModel(UObject export) : this() { _export = export; Path = _export.GetPathName(); Name = Path.SubstringAfterLast('/').SubstringBefore('.'); Type = export.ExportType; - UvCount = 1; - Box = new FBox(new FVector(-2f), new FVector(2f)); - Sockets = new List(); - Collisions = new List(); - Transforms = new List(); Attachments = new Attachment(Name); _vertexAttributes[(int) EAttribute.Index].Enabled = @@ -180,12 +175,21 @@ public abstract class UModel : IRenderableModel { var section = lod.Sections.Value[s]; Sections[s] = new Section(section.MaterialIndex, section.NumFaces * 3, section.FirstIndex); - if (section.IsValid) Sections[s].ValidateMaterial(Materials[section.MaterialIndex], UvCount); + if (section.IsValid) Sections[s].ValidateSection(Materials[section.MaterialIndex]); } AddInstance(transform ?? Transform.Identity); } + public void ScanMaterials() + { + foreach (var material in Materials) + { + if (!material.IsUsed) continue; + material.Validate(UvCount); + } + } + public virtual void Setup() { Handle = GL.CreateProgram(); @@ -208,8 +212,6 @@ public abstract class UModel : IRenderableModel offset += attribute.Size; } - SetupInstances(); // instanced models transform - // setup all used materials for use in different UV channels for (var i = 0; i < Materials.Length; i++) { @@ -335,14 +337,16 @@ public abstract class UModel : IRenderableModel shader.SetUniform("uScaleDown", Constants.SCALE_DOWN_RATIO); } + public void AddInstance(Transform transform) + { + SelectedInstance = TransformsCount; + Transforms.Add(transform); + } + public void Update() { - MatrixVbo.Bind(); - for (int instance = 0; instance < TransformsCount; instance++) - { - MatrixVbo.Update(instance, Transforms[instance].Matrix); - } - MatrixVbo.Unbind(); + if (MatrixVbo?.Size != TransformsCount) SetupInstances(); + else UpdateInstances(); var worldMatrix = GetTransform().Matrix; foreach (var socket in Sockets) @@ -365,21 +369,29 @@ public abstract class UModel : IRenderableModel } } - public void AddInstance(Transform transform) + private void UpdateInstances() { - SelectedInstance = TransformsCount; - Transforms.Add(transform); + MatrixVbo.Bind(); + for (int instance = 0; instance < TransformsCount; instance++) + { + MatrixVbo.Update(instance, Transforms[instance].Matrix); + } + MatrixVbo.Unbind(); } - public void SetupInstances() + private void SetupInstances() { + Vao.Bind(); + Vbo.Bind(); + Ebo.Bind(); + MatrixVbo = new BufferObject(TransformsCount, BufferTarget.ArrayBuffer); for (int instance = 0; instance < TransformsCount; instance++) { Transforms[instance].Save(); MatrixVbo.Update(instance, Transforms[instance].Matrix); } - Vao.BindInstancing(); // VertexAttributePointer + Vao.BindInstancing(); } public Transform GetTransform() => Transforms[SelectedInstance]; diff --git a/FModel/Views/Snooper/Renderer.cs b/FModel/Views/Snooper/Renderer.cs index 725e88dd..03d2f5c1 100644 --- a/FModel/Views/Snooper/Renderer.cs +++ b/FModel/Views/Snooper/Renderer.cs @@ -193,7 +193,7 @@ public class Renderer : IDisposable } case USkeletalMesh sk: { - guid = Guid.NewGuid(); + guid = FGuid.Random(); if (!Options.Models.ContainsKey(guid) && sk.TryConvert(out var mesh)) { addedModel = new SkeletalModel(sk, mesh, t); diff --git a/FModel/Views/Snooper/Shading/Material.cs b/FModel/Views/Snooper/Shading/Material.cs index 83765af3..aa6992fa 100644 --- a/FModel/Views/Snooper/Shading/Material.cs +++ b/FModel/Views/Snooper/Shading/Material.cs @@ -78,8 +78,8 @@ public class Material : IDisposable Diffuse = [new LinearColorTexture(FLinearColor.Gray).Guid]; Normals = [new LinearColorTexture(new FLinearColor(0.5f, 0.5f, 1f, 1f)).Guid]; SpecularMasks = []; - Emissive = new FGuid[1]; - DiffuseColor = FillColors(1, CMaterialParams2.DiffuseColors, Vector4.One); + Emissive = []; + DiffuseColor = FillColors(1,CMaterialParams2.DiffuseColors, Vector4.One); EmissiveColor = [Vector4.One]; } else @@ -91,8 +91,8 @@ public class Material : IDisposable Emissive = FillTextures(uvCount, true, CMaterialParams2.Emissive, CMaterialParams2.FallbackEmissive); // colors - DiffuseColor = FillColors(uvCount, CMaterialParams2.DiffuseColors, Vector4.One); - EmissiveColor = FillColors(uvCount, CMaterialParams2.EmissiveColors, Vector4.One); + DiffuseColor = FillColors(Diffuse.Length, CMaterialParams2.DiffuseColors, Vector4.One); + EmissiveColor = FillColors(Emissive.Length,CMaterialParams2.EmissiveColors, Vector4.One); { // ambient occlusion + color boost if (Parameters.TryGetTexture2d(out var original, "M", "AEM", "AO") && !original.Name.Equals("T_BlackMask")) @@ -135,7 +135,7 @@ public class Material : IDisposable { foreach (var specMask in SpecularMasks) { - if (AssetPool.Get().TryGet(specMask, out var bitmap)) + if (AssetPool.Get().TryGetBitmap(specMask, out var bitmap)) { bitmap.SwizzleMask = [ @@ -154,22 +154,6 @@ public class Material : IDisposable public void Setup(bool broken) { _handle = GL.CreateProgram(); - - // if (broken) - // { - // for (var i = 0; i < 1; i++) - // { - // Diffuse[i].Setup(); - // Normals[i].Setup(); - // } - // } - // else - // { - // foreach (var diffuse in Diffuse) diffuse.Setup(); - // foreach (var normal in Normals) normal.Setup(); - // foreach (var specMask in SpecularMasks) specMask.Setup(); - // foreach (var emissive in Emissive) emissive.Setup(); - // } } /// number of item in the array @@ -236,7 +220,7 @@ public class Material : IDisposable for (var i = 0; i < Diffuse.Length; i++) { shader.SetUniform($"uParameters.Diffuse[{i}].Color", DiffuseColor[i]); - if (AssetPool.Get().TryGetTexture(Diffuse[i], out bitmap)) + if (Diffuse[i].IsValid() && AssetPool.Get().TryGetTexture(Diffuse[i], out bitmap)) { shader.SetUniform($"uParameters.Diffuse[{i}].Sampler", unit); bitmap?.Bind(TextureUnit.Texture0 + unit++); @@ -245,7 +229,7 @@ public class Material : IDisposable for (var i = 0; i < Normals.Length; i++) { - if (AssetPool.Get().TryGetTexture(Normals[i], out bitmap)) + if (Normals[i].IsValid() && AssetPool.Get().TryGetTexture(Normals[i], out bitmap)) { shader.SetUniform($"uParameters.Normals[{i}].Sampler", unit); bitmap?.Bind(TextureUnit.Texture0 + unit++); @@ -254,24 +238,24 @@ public class Material : IDisposable for (var i = 0; i < SpecularMasks.Length; i++) { - if (AssetPool.Get().TryGetTexture(SpecularMasks[i], out bitmap)) + if (SpecularMasks[i].IsValid() && AssetPool.Get().TryGetTexture(SpecularMasks[i], out bitmap)) { shader.SetUniform($"uParameters.SpecularMasks[{i}].Sampler", unit); bitmap?.Bind(TextureUnit.Texture0 + unit++); } } - for (var i = 0; i < Emissive.Length; i++) - { - if (AssetPool.Get().TryGetTexture(Emissive[i], out bitmap)) - { - shader.SetUniform($"uParameters.Emissive[{i}].Color", EmissiveColor[i]); - shader.SetUniform($"uParameters.Emissive[{i}].Sampler", unit); - bitmap?.Bind(TextureUnit.Texture0 + unit++); - } - } + // for (var i = 0; i < Emissive.Length; i++) + // { + // if (Emissive[i].IsValid() && AssetPool.Get().TryGetTexture(Emissive[i], out bitmap)) + // { + // shader.SetUniform($"uParameters.Emissive[{i}].Color", EmissiveColor[i]); + // shader.SetUniform($"uParameters.Emissive[{i}].Sampler", unit); + // bitmap?.Bind(TextureUnit.Texture0 + unit++); + // } + // } - if (HasAo && AssetPool.Get().TryGetTexture(Ao.Texture, out bitmap)) + if (Ao.Texture.IsValid() && AssetPool.Get().TryGetTexture(Ao.Texture, out bitmap)) { bitmap?.Bind(TextureUnit.Texture31); shader.SetUniform("uParameters.Ao.Sampler", 31); diff --git a/FModel/Views/Snooper/Textures/AbstractTexture.cs b/FModel/Views/Snooper/Textures/AbstractTexture.cs index 8df50fe1..31102399 100644 --- a/FModel/Views/Snooper/Textures/AbstractTexture.cs +++ b/FModel/Views/Snooper/Textures/AbstractTexture.cs @@ -26,7 +26,7 @@ public abstract class AbstractTexture : ITexture _ => TextureTarget.Texture2D }; - Guid = new FGuid(); + Guid = FGuid.Random(); } public virtual void Setup()