Skip to content

Commit 7d4ab75

Browse files
committed
feat: Configure preserve border edges per bone
1 parent 322e7d3 commit 7d4ab75

12 files changed

+356
-57
lines changed

Ndmf/Editor/Meshia.MeshSimplification.Ndmf.Editor.asmdef

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@
66
"Meshia.MeshSimplification.Ndmf.Runtime",
77
"nadena.dev.ndmf",
88
"nadena.dev.ndmf.runtime",
9-
"nadena.dev.modular-avatar.core"
9+
"nadena.dev.modular-avatar.core",
10+
"Unity.Mathematics"
1011
],
1112
"includePlatforms": [
1213
"Editor"

Ndmf/Editor/MeshiaCascadingAvatarMeshSimplifierEditor.cs

Lines changed: 42 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,7 @@ public override VisualElement CreateInspectorGUI()
186186
var targetTriangleCountField = itemRoot.Q<IntegerField>("TargetTriangleCountField");
187187
var originalTriangleCountField = itemRoot.Q<IntegerField>("OriginalTriangleCountField");
188188
var unknownOriginalTriangleCountField = itemRoot.Q<TextField>("UnknownOriginalTriangleCountField");
189+
var preserveBorderEdgesBonesFoldout = itemRoot.Q<Foldout>("PreserveBorderEdgesBonesFoldout");
189190
itemRoot.BindProperty(entryProperty);
190191
itemRoot.userData = index;
191192
var targetRenderer = entry.GetTargetRenderer(Target);
@@ -225,7 +226,15 @@ public override VisualElement CreateInspectorGUI()
225226

226227
}
227228

229+
var humanBodyBoneIndex = 0;
230+
var preserveBorderEdgesBonesProperty = EntriesProperty.GetArrayElementAtIndex(index).FindPropertyRelative(nameof(MeshiaCascadingAvatarMeshSimplifierRendererEntry.PreserveBorderEdgesBones));
231+
var preserveBorderEdgesBones = preserveBorderEdgesBonesProperty.ulongValue;
232+
foreach (var preserveBorderEdgesBoneToggle in preserveBorderEdgesBonesFoldout.Children().OfType<Toggle>())
233+
{
234+
preserveBorderEdgesBoneToggle.value = (preserveBorderEdgesBones & (1ul << humanBodyBoneIndex)) != 0ul;
228235

236+
humanBodyBoneIndex++;
237+
}
229238
};
230239

231240

@@ -239,6 +248,7 @@ public override VisualElement CreateInspectorGUI()
239248
var triangleCountDivider = itemRoot.Q<Label>("TriangleCountDivider");
240249
var optionsToggle = itemRoot.Q<Toggle>("OptionsToggle");
241250
var optionsField = itemRoot.Q<PropertyField>("OptionsField");
251+
var preserveBorderEdgesBonesFoldout = itemRoot.Q<Foldout>("PreserveBorderEdgesBonesFoldout");
242252
enabledToggle.RegisterValueChangedCallback(changeEvent =>
243253
{
244254
var enabled = changeEvent.newValue;
@@ -268,9 +278,39 @@ public override VisualElement CreateInspectorGUI()
268278

269279
optionsToggle.RegisterValueChangedCallback(changeEvent =>
270280
{
271-
optionsField.style.display = changeEvent.newValue ? DisplayStyle.Flex : DisplayStyle.None;
281+
optionsField.style.display = preserveBorderEdgesBonesFoldout.style.display = changeEvent.newValue ? DisplayStyle.Flex : DisplayStyle.None;
272282
});
273-
283+
284+
285+
286+
for (HumanBodyBones bone = 0; bone < HumanBodyBones.LastBone; bone++)
287+
{
288+
var humanBodyBoneIndex = (int)bone;
289+
Toggle preserveBorderEdgesBoneToggle = new(bone.ToString());
290+
preserveBorderEdgesBoneToggle.RegisterValueChangedCallback(changeEvent =>
291+
{
292+
if(itemRoot.userData is int itemIndex)
293+
{
294+
var preserveBorderEdgesBonesProperty = EntriesProperty.GetArrayElementAtIndex(itemIndex).FindPropertyRelative(nameof(MeshiaCascadingAvatarMeshSimplifierRendererEntry.PreserveBorderEdgesBones));
295+
serializedObject.Update();
296+
var currentMask = preserveBorderEdgesBonesProperty.ulongValue;
297+
if (changeEvent.newValue)
298+
{
299+
currentMask |= (1ul << humanBodyBoneIndex);
300+
}
301+
else
302+
{
303+
currentMask &= ~(1ul << humanBodyBoneIndex);
304+
}
305+
preserveBorderEdgesBonesProperty.ulongValue = currentMask;
306+
307+
serializedObject.ApplyModifiedProperties();
308+
}
309+
310+
});
311+
preserveBorderEdgesBonesFoldout.Add(preserveBorderEdgesBoneToggle);
312+
}
313+
274314
return itemRoot;
275315
};
276316

Ndmf/Editor/MeshiaCascadingAvatarMeshSimplifierRendererEntryEditor.uxml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,5 @@
1313
<ui:Toggle name="OptionsToggle" style="align-self: center;" />
1414
</ui:VisualElement>
1515
<uie:PropertyField binding-path="Options" name="OptionsField" style="display: none;" />
16+
<ui:Foldout text="Preserve Border Edges Bones" name="PreserveBorderEdgesBonesFoldout" value="false" style="display: none;" />
1617
</ui:UXML>

Ndmf/Editor/Preview/MeshiaCascadingAvatarMeshSimplifierPreview.cs

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
11
#nullable enable
22
#if ENABLE_MODULAR_AVATAR
33

4+
using System;
5+
using System.Collections;
46
using System.Collections.Generic;
57
using System.Collections.Immutable;
68
using System.Linq;
79
using nadena.dev.ndmf.preview;
10+
using nadena.dev.ndmf.util;
11+
using Unity.Mathematics;
812
using UnityEngine;
913

1014
namespace Meshia.MeshSimplification.Ndmf.Editor.Preview
@@ -37,15 +41,50 @@ public override ImmutableList<RenderGroup> GetTargetGroups(ComputeContext contex
3741
return groups.ToImmutableList();
3842
}
3943

40-
protected override (MeshSimplificationTarget, MeshSimplifierOptions) QueryTarget(ComputeContext context, RenderGroup group, Renderer original, Renderer proxy)
44+
protected override (MeshSimplificationTarget, MeshSimplifierOptions, BitArray?) QueryTarget(ComputeContext context, RenderGroup group, Renderer original, Renderer proxy)
4145
{
4246
var data = group.GetData<(MeshiaCascadingAvatarMeshSimplifier, int)>();
4347
var component = data.Item1;
4448
var index = data.Item2;
4549

4650
var cascadingTarget = context.Observe(component, c => c.Entries[index] with { }, (a, b) => a.Equals(b));
4751
var target = new MeshSimplificationTarget() { Kind = MeshSimplificationTargetKind.AbsoluteTriangleCount, Value = cascadingTarget.TargetTriangleCount };
48-
return (target, cascadingTarget.Options);
52+
53+
54+
55+
56+
if(original is SkinnedMeshRenderer skinnedMeshRenderer)
57+
{
58+
var avatarRoot = context.GetAvatarRoot(original.gameObject);
59+
if(avatarRoot != null)
60+
{
61+
var avatarAnimator = avatarRoot.GetComponent<Animator>();
62+
63+
var bones = skinnedMeshRenderer.bones;
64+
var preserveBorderEdgeBoneIndices = new BitArray(bones.Length);
65+
66+
for (ulong boneMask = cascadingTarget.PreserveBorderEdgesBones; boneMask != 0ul; boneMask &= boneMask - 1)
67+
{
68+
var bone = (HumanBodyBones)math.tzcnt(boneMask);
69+
var boneTransform = avatarAnimator.GetBoneTransform(bone);
70+
if (boneTransform != null)
71+
{
72+
var boneIndex = Array.IndexOf(bones, boneTransform);
73+
if (boneIndex > 0)
74+
{
75+
preserveBorderEdgeBoneIndices.Set(boneIndex, true);
76+
}
77+
}
78+
}
79+
80+
return (target, cascadingTarget.Options, preserveBorderEdgeBoneIndices);
81+
}
82+
83+
}
84+
return (target, cascadingTarget.Options, null);
85+
86+
87+
4988
}
5089
}
5190
}

Ndmf/Editor/Preview/MeshiaMeshSimplifierPreview.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#nullable enable
22

3+
using System.Collections;
34
using System.Collections.Immutable;
45
using System.Linq;
56
using nadena.dev.ndmf.preview;
@@ -18,12 +19,12 @@ public override ImmutableList<RenderGroup> GetTargetGroups(ComputeContext contex
1819
.Select(renderer => RenderGroup.For(renderer))
1920
.ToImmutableList();
2021
}
21-
protected override (MeshSimplificationTarget, MeshSimplifierOptions) QueryTarget(ComputeContext context, RenderGroup group, Renderer original, Renderer proxy)
22+
protected override (MeshSimplificationTarget, MeshSimplifierOptions, BitArray?) QueryTarget(ComputeContext context, RenderGroup group, Renderer original, Renderer proxy)
2223
{
2324
var ndmfMeshSimplifier = original.GetComponent<MeshiaMeshSimplifier>();
2425
var target = context.Observe(ndmfMeshSimplifier, ndmfMeshSimplifier => ndmfMeshSimplifier.target, (x, y) => x == y);
2526
var options = context.Observe(ndmfMeshSimplifier, ndmfMeshSimplifier => ndmfMeshSimplifier.options, (x, y) => x == y);
26-
return (target, options);
27+
return (target, options, null);
2728
}
2829
}
2930
}

Ndmf/Editor/Preview/MeshiaMeshSimplifierPreviewBase.cs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
using System.Threading.Tasks;
88
using UnityEngine;
99
using nadena.dev.ndmf.preview;
10+
using System.Collections;
1011

1112
namespace Meshia.MeshSimplification.Ndmf.Editor.Preview
1213
{
@@ -39,12 +40,12 @@ async Task<IRenderFilterNode> IRenderFilter.Instantiate(RenderGroup group, IEnum
3940
var proxy = proxyPairs.First().Item2;
4041
var proxyMesh = RendererUtility.GetRequiredMesh(proxy);
4142

42-
var (target, options) = QueryTarget(context, group, original, proxy);
43+
var (target, options, preserveBorderEdgesBoneIndices) = QueryTarget(context, group, original, proxy);
4344

4445
Mesh simplifiedMesh = new();
4546
try
4647
{
47-
await MeshSimplifier.SimplifyAsync(proxyMesh, target, options, simplifiedMesh);
48+
await MeshSimplifier.SimplifyAsync(proxyMesh, target, options, preserveBorderEdgesBoneIndices, simplifiedMesh);
4849
}
4950
catch (Exception)
5051
{
@@ -57,7 +58,7 @@ async Task<IRenderFilterNode> IRenderFilter.Instantiate(RenderGroup group, IEnum
5758
return new NdmfMeshSimplifierPreviewNode(simplifiedMesh);
5859
}
5960

60-
protected abstract (MeshSimplificationTarget, MeshSimplifierOptions) QueryTarget(ComputeContext context, RenderGroup group, Renderer original, Renderer proxy);
61+
protected abstract (MeshSimplificationTarget, MeshSimplifierOptions, BitArray?) QueryTarget(ComputeContext context, RenderGroup group, Renderer original, Renderer proxy);
6162
}
6263

6364
internal class NdmfMeshSimplifierPreviewNode : IRenderFilterNode

Ndmf/Runtime/MeshiaCascadingAvatarMeshSimplifier.cs

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ public class MeshiaCascadingAvatarMeshSimplifier : MonoBehaviour
2222
public List<MeshiaCascadingAvatarMeshSimplifierRendererEntry> Entries = new();
2323
public int TargetTriangleCount = 70000;
2424
public bool AutoAdjustEnabled = true;
25-
25+
2626
public void RefreshEntries()
2727
{
2828
using (ListPool<Renderer>.Get(out var ownedRenderers))
@@ -135,6 +135,7 @@ public record MeshiaCascadingAvatarMeshSimplifierRendererEntry
135135
public AvatarObjectReference RendererObjectReference;
136136
public int TargetTriangleCount;
137137
public MeshSimplifierOptions Options;
138+
public ulong PreserveBorderEdgesBones;
138139
public bool Enabled;
139140
public bool Fixed;
140141

@@ -144,6 +145,37 @@ public MeshiaCascadingAvatarMeshSimplifierRendererEntry(Renderer renderer)
144145
RendererObjectReference.Set(renderer.gameObject);
145146
TargetTriangleCount = RendererUtility.GetMesh(renderer)?.GetTriangleCount() ?? 0;
146147
Options = MeshSimplifierOptions.Default;
148+
PreserveBorderEdgesBones =
149+
(1ul << (int)HumanBodyBones.LeftThumbProximal) |
150+
(1ul << (int)HumanBodyBones.LeftThumbIntermediate) |
151+
(1ul << (int)HumanBodyBones.LeftThumbDistal) |
152+
(1ul << (int)HumanBodyBones.LeftIndexProximal) |
153+
(1ul << (int)HumanBodyBones.LeftIndexIntermediate) |
154+
(1ul << (int)HumanBodyBones.LeftIndexDistal) |
155+
(1ul << (int)HumanBodyBones.LeftMiddleProximal) |
156+
(1ul << (int)HumanBodyBones.LeftMiddleIntermediate) |
157+
(1ul << (int)HumanBodyBones.LeftMiddleDistal) |
158+
(1ul << (int)HumanBodyBones.LeftRingProximal) |
159+
(1ul << (int)HumanBodyBones.LeftRingIntermediate) |
160+
(1ul << (int)HumanBodyBones.LeftRingDistal) |
161+
(1ul << (int)HumanBodyBones.LeftLittleProximal) |
162+
(1ul << (int)HumanBodyBones.LeftLittleIntermediate) |
163+
(1ul << (int)HumanBodyBones.LeftLittleDistal) |
164+
(1ul << (int)HumanBodyBones.RightThumbProximal) |
165+
(1ul << (int)HumanBodyBones.RightThumbIntermediate) |
166+
(1ul << (int)HumanBodyBones.RightThumbDistal) |
167+
(1ul << (int)HumanBodyBones.RightIndexProximal) |
168+
(1ul << (int)HumanBodyBones.RightIndexIntermediate) |
169+
(1ul << (int)HumanBodyBones.RightIndexDistal) |
170+
(1ul << (int)HumanBodyBones.RightMiddleProximal) |
171+
(1ul << (int)HumanBodyBones.RightMiddleIntermediate) |
172+
(1ul << (int)HumanBodyBones.RightMiddleDistal) |
173+
(1ul << (int)HumanBodyBones.RightRingProximal) |
174+
(1ul << (int)HumanBodyBones.RightRingIntermediate) |
175+
(1ul << (int)HumanBodyBones.RightRingDistal) |
176+
(1ul << (int)HumanBodyBones.RightLittleProximal) |
177+
(1ul << (int)HumanBodyBones.RightLittleIntermediate) |
178+
(1ul << (int)HumanBodyBones.RightLittleDistal);
147179
Enabled = true;
148180
Fixed = false;
149181
}
@@ -187,6 +219,7 @@ internal void ResolveReference(Component container)
187219
RendererObjectReference.Get(container);
188220
}
189221
}
222+
190223
}
191224

192225
#endif

Runtime/Jobs/ComputeMergesJob.cs

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,20 +19,28 @@ struct ComputeMergesJob : IJobParallelForDefer
1919
public NativeBitArray VertexIsBorderEdgeBits;
2020
[ReadOnly]
2121
public NativeArray<int2> Edges;
22+
[ReadOnly]
23+
public NativeArray<uint> VertexBlendIndicesBuffer;
24+
25+
[ReadOnly]
26+
public NativeBitArray PreserveBorderEdgesBoneIndices;
2227
[WriteOnly]
2328
public NativeArray<VertexMerge> UnorderedDirtyVertexMerges;
24-
25-
public MeshSimplifierOptions Options;
29+
public bool PreserveBorderEdges;
30+
public bool PreserveSurfaceCurvature;
2631
public void Execute(int index)
2732
{
2833
var mergeFactory = new MergeFactory
2934
{
30-
VertexPositions = VertexPositionBuffer,
35+
VertexPositionBuffer = VertexPositionBuffer,
3136
VertexErrorQuadrics = VertexErrorQuadrics,
3237
VertexContainingTriangles = VertexContainingTriangles,
3338
VertexIsBorderEdgeBits = VertexIsBorderEdgeBits,
3439
TriangleNormals = TriangleNormals,
35-
Options = Options,
40+
PreserveBorderEdges = PreserveBorderEdges,
41+
PreserveSurfaceCurvature = PreserveSurfaceCurvature,
42+
PreserveBorderEdgesBoneIndices = PreserveBorderEdgesBoneIndices,
43+
VertexBlendIndicesBuffer = VertexBlendIndicesBuffer,
3644
};
3745
var edge = Edges[index];
3846
VertexMerge merge;

0 commit comments

Comments
 (0)