This commit is contained in:
Asval 2025-05-11 03:59:58 +02:00
parent 8303cc6cf1
commit a631f90707
6 changed files with 162 additions and 152 deletions

View File

@ -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<IDelayedSetup> Queue;
public readonly Dictionary<FGuid, UModel> Models;
public readonly Dictionary<FGuid, ITexture> 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<BitmapTexture>(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<T>(FGuid guid, [MaybeNullWhen(true)] out T asset)
private bool TryGet<T>(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)
{

View File

@ -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);
}
}

View File

@ -87,23 +87,18 @@ public abstract class UModel : IRenderableModel
UvCount = 1;
Box = new FBox(new FVector(-2f), new FVector(2f));
Sockets = new List<Socket>();
Collisions = new List<Collision>();
Transforms = new List<Transform>();
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<Socket>();
Collisions = new List<Collision>();
Transforms = new List<Transform>();
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<Matrix4x4>(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];

View File

@ -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);

View File

@ -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<BitmapTexture>(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();
// }
}
/// <param name="uvCount">number of item in the array</param>
@ -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);

View File

@ -26,7 +26,7 @@ public abstract class AbstractTexture : ITexture
_ => TextureTarget.Texture2D
};
Guid = new FGuid();
Guid = FGuid.Random();
}
public virtual void Setup()