[BetterShadowClone] Reworked vert finding for exclusions to not nuke game for 20s

This commit is contained in:
NotAKidoS 2024-02-03 05:40:11 -06:00
parent 0d82606308
commit df45fb50d9
4 changed files with 64 additions and 44 deletions

View file

@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using ABI_RC.Core;
using ABI.CCK.Components;
using UnityEngine;
@ -44,8 +45,13 @@ public static class ShadowCloneHelper
private static void ProcessRenderers(IEnumerable<Renderer> renderers, Transform root, Transform headBone)
{
Stopwatch sw = Stopwatch.StartNew();
IReadOnlyDictionary<Transform, FPRExclusion> exclusions = CollectTransformToExclusionMap(root, headBone);
// log current time
ShadowCloneMod.Logger.Msg($"CollectTransformToExclusionMap in {sw.ElapsedMilliseconds}ms");
foreach (Renderer renderer in renderers)
{
ConfigureRenderer(renderer);
@ -59,6 +65,11 @@ public static class ShadowCloneHelper
ITransformHider hider = TransformHiderManager.CreateTransformHider(renderer, exclusions);
if (hider != null) TransformHiderManager.Instance.AddTransformHider(hider);
}
sw.Stop();
// log current time
ShadowCloneMod.Logger.Msg($"ProcessRenderers in {sw.ElapsedMilliseconds}ms");
}
#endregion

View file

@ -10,6 +10,8 @@ public class FPRExclusion : MonoBehaviour
{
public Transform target;
internal readonly List<int> affectedVertexIndices = new();
internal readonly List<Transform> affectedChildren = new();
internal readonly List<IFPRExclusionTask> relatedTasks = new();

View file

@ -16,9 +16,6 @@ public class MeshTransformHider : ITransformHider, IFPRExclusionTask
private readonly MeshRenderer _mainMesh;
private bool _enabledState;
// exclusion
private readonly FPRExclusion _exclusion;
#region ITransformHider Methods
public bool IsActive { get; set; } = true; // default hide, but FPRExclusion can override
@ -37,8 +34,7 @@ public class MeshTransformHider : ITransformHider, IFPRExclusionTask
return;
}
_exclusion = exclusion;
_exclusion.relatedTasks.Add(this);
exclusion.relatedTasks.Add(this);
_mainMesh = renderer;

View file

@ -1,4 +1,5 @@
using System;
using System.Diagnostics;
using UnityEngine;
using UnityEngine.Rendering;
@ -38,6 +39,8 @@ public class SkinnedTransformHider : ITransformHider
public SkinnedTransformHider(SkinnedMeshRenderer renderer, IReadOnlyDictionary<Transform, FPRExclusion> exclusions)
{
Stopwatch sw = Stopwatch.StartNew();
_mainMesh = renderer;
if (_mainMesh == null
@ -52,36 +55,35 @@ public class SkinnedTransformHider : ITransformHider
_rootBone = _mainMesh.rootBone;
_rootBone ??= _mainMesh.transform; // fallback to transform if no root bone
// subtask creation
// log current time
ShadowCloneMod.Logger.Msg($"SkinnedTransformHider part 1 in {sw.ElapsedMilliseconds}ms");
var bones = renderer.bones;
List<FPRExclusion> fprExclusions = new();
SubTask.FindExclusionVertList(renderer, exclusions);
foreach (Transform bone in bones)
foreach (var exclusion in exclusions)
{
if (bone == null)
continue; // thanks AdvancedSafety for preventing null ref for so long...
FPRExclusion fprExclusion = exclusion.Value;
if (fprExclusion.affectedVertexIndices.Count == 0)
continue; // no affected verts
if (!exclusions.TryGetValue(bone, out FPRExclusion exclusion))
continue;
fprExclusions.Add(exclusion);
}
List<int> exclusionVerts;
foreach (FPRExclusion exclusion in fprExclusions)
{
exclusionVerts = SubTask.FindExclusionVertList(renderer, exclusion);
if (exclusionVerts.Count == 0)
continue;
SubTask subTask = new(this, exclusion, exclusionVerts);
SubTask subTask = new(this, fprExclusion, fprExclusion.affectedVertexIndices);
_subTasks.Add(subTask);
exclusion.relatedTasks.Add(subTask);
fprExclusion.relatedTasks.Add(subTask);
fprExclusion.affectedVertexIndices.Clear(); // clear list for next SkinnedTransformHider
}
// log current time
ShadowCloneMod.Logger.Msg($"SkinnedTransformHider part 3 in {sw.ElapsedMilliseconds}ms");
if (_subTasks.Count == 0)
{
Dispose(); // had the bones, but not the weights :?
ShadowCloneMod.Logger.Warning("SkinnedTransformHider No valid exclusions found!");
}
sw.Stop();
ShadowCloneMod.Logger.Msg($"SkinnedTransformHider created in {sw.ElapsedMilliseconds}ms");
}
public bool Process()
@ -177,13 +179,10 @@ public class SkinnedTransformHider : ITransformHider
private readonly ComputeBuffer _computeBuffer;
private readonly int _threadGroups;
private readonly FPRExclusion _exclusion;
public SubTask(SkinnedTransformHider parent, FPRExclusion exclusion, List<int> exclusionVerts)
{
_parent = parent;
_exclusion = exclusion;
_shrinkBone = _exclusion.target;
_shrinkBone = exclusion.target;
_vertexCount = exclusionVerts.Count;
_computeBuffer = new ComputeBuffer(_vertexCount, sizeof(int));
@ -211,28 +210,40 @@ public class SkinnedTransformHider : ITransformHider
#region Private Methods
public static List<int> FindExclusionVertList(SkinnedMeshRenderer renderer, FPRExclusion exclusion)
public static void FindExclusionVertList(SkinnedMeshRenderer renderer, IReadOnlyDictionary<Transform, FPRExclusion> exclusions)
{
var boneWeights = renderer.sharedMesh.boneWeights;
var bones = exclusion.affectedChildren;
HashSet<int> weights = new();
for (int i = 0; i < renderer.bones.Length; i++)
if (bones.Contains(renderer.bones[i])) weights.Add(i);
{
// if bone == any key in exclusions, add to weights
if (!exclusions.TryGetValue(renderer.bones[i], out FPRExclusion _))
continue;
weights.Add(i);
}
List<int> headVertices = new();
for (int i = 0; i < boneWeights.Length; i++)
{
BoneWeight weight = boneWeights[i];
Transform bone = null;
const float minWeightThreshold = 0.2f;
if (weights.Contains(weight.boneIndex0) && weight.weight0 > minWeightThreshold
|| weights.Contains(weight.boneIndex1) && weight.weight1 > minWeightThreshold
|| weights.Contains(weight.boneIndex2) && weight.weight2 > minWeightThreshold
|| weights.Contains(weight.boneIndex3) && weight.weight3 > minWeightThreshold)
headVertices.Add(i);
}
if (weights.Contains(weight.boneIndex0) && weight.weight0 > minWeightThreshold)
bone = renderer.bones[weight.boneIndex0];
else if (weights.Contains(weight.boneIndex1) && weight.weight1 > minWeightThreshold)
bone = renderer.bones[weight.boneIndex1];
else if (weights.Contains(weight.boneIndex2) && weight.weight2 > minWeightThreshold)
bone = renderer.bones[weight.boneIndex2];
else if (weights.Contains(weight.boneIndex3) && weight.weight3 > minWeightThreshold)
bone = renderer.bones[weight.boneIndex3];
return headVertices;
if (bone == null) continue; // no bone found
// add vertex to exclusion list
exclusions[bone].affectedVertexIndices.Add(i);
}
}
#endregion