diff --git a/Ndmf/Editor/Meshia.MeshSimplification.Ndmf.Editor.asmdef b/Ndmf/Editor/Meshia.MeshSimplification.Ndmf.Editor.asmdef index 63e7b5c..0125d15 100644 --- a/Ndmf/Editor/Meshia.MeshSimplification.Ndmf.Editor.asmdef +++ b/Ndmf/Editor/Meshia.MeshSimplification.Ndmf.Editor.asmdef @@ -6,8 +6,7 @@ "Meshia.MeshSimplification.Ndmf.Runtime", "nadena.dev.ndmf", "nadena.dev.ndmf.runtime", - "nadena.dev.modular-avatar.core", - "Unity.Mathematics" + "nadena.dev.modular-avatar.core" ], "includePlatforms": [ "Editor" diff --git a/Ndmf/Editor/NdmfPlugin.cs b/Ndmf/Editor/NdmfPlugin.cs index 2084413..fcda952 100644 --- a/Ndmf/Editor/NdmfPlugin.cs +++ b/Ndmf/Editor/NdmfPlugin.cs @@ -4,6 +4,7 @@ using nadena.dev.ndmf; using nadena.dev.ndmf.preview; using System; +using System.Collections; using UnityEditor; using UnityEngine; using UnityEngine.Pool; @@ -39,11 +40,11 @@ protected override void Configure() { var meshiaMeshSimplifiers = context.AvatarRootObject.GetComponentsInChildren(true); #if ENABLE_MODULAR_AVATAR - + var meshiaCascadingMeshSimplifiers = context.AvatarRootObject.GetComponentsInChildren(true); #endif - using (ListPool<(Mesh Mesh, MeshSimplificationTarget Target, MeshSimplifierOptions Options, Mesh Destination)>.Get(out var parameters)) + using (ListPool<(Mesh Mesh, MeshSimplificationTarget Target, MeshSimplifierOptions Options, BitArray? preserveBorderEdgesBoneIndices, Mesh Destination)>.Get(out var parameters)) { foreach (var meshiaMeshSimplifier in meshiaMeshSimplifiers) { @@ -51,7 +52,7 @@ protected override void Configure() { var sourceMesh = RendererUtility.GetRequiredMesh(renderer); Mesh simplifiedMesh = new(); - parameters.Add((sourceMesh, meshiaMeshSimplifier.target, meshiaMeshSimplifier.options, simplifiedMesh)); + parameters.Add((sourceMesh, meshiaMeshSimplifier.target, meshiaMeshSimplifier.options, null, simplifiedMesh)); } } #if ENABLE_MODULAR_AVATAR @@ -64,7 +65,10 @@ protected override void Configure() var mesh = RendererUtility.GetRequiredMesh(entry.GetTargetRenderer(meshiaCascadingMeshSimplifier)!); var target = new MeshSimplificationTarget() { Kind = MeshSimplificationTargetKind.AbsoluteTriangleCount, Value = entry.TargetTriangleCount }; Mesh simplifiedMesh = new(); - parameters.Add((mesh, target, entry.Options, simplifiedMesh)); + + var preserveBorderEdgesBoneIndices = MeshiaCascadingAvatarMeshSimplifier.GetPreserveBorderEdgesBoneIndices(context.AvatarRootObject, meshiaCascadingMeshSimplifier, entry); + + parameters.Add((mesh, target, entry.Options, preserveBorderEdgesBoneIndices, simplifiedMesh)); } } @@ -78,7 +82,7 @@ protected override void Configure() { if(meshiaMeshSimplifier.enabled && meshiaMeshSimplifier.TryGetComponent(out var renderer)) { - var (mesh, target, options, simplifiedMesh) = parameters[i++]; + var (mesh, target, options, _, simplifiedMesh) = parameters[i++]; AssetDatabase.AddObjectToAsset(simplifiedMesh, context.AssetContainer); RendererUtility.SetMesh(renderer, simplifiedMesh); } @@ -96,7 +100,7 @@ protected override void Configure() { if (!cascadingTarget.IsValid(meshiaCascadingMeshSimplifier) || !cascadingTarget.Enabled) continue; var renderer = cascadingTarget.GetTargetRenderer(meshiaCascadingMeshSimplifier)!; - var (mesh, target, options, simplifiedMesh) = parameters[i++]; + var (mesh, target, options, _, simplifiedMesh) = parameters[i++]; AssetDatabase.AddObjectToAsset(simplifiedMesh, context.AssetContainer); RendererUtility.SetMesh(renderer, simplifiedMesh); diff --git a/Ndmf/Editor/Preview/MeshiaCascadingAvatarMeshSimplifierPreview.cs b/Ndmf/Editor/Preview/MeshiaCascadingAvatarMeshSimplifierPreview.cs index c0bb9ac..ec03289 100644 --- a/Ndmf/Editor/Preview/MeshiaCascadingAvatarMeshSimplifierPreview.cs +++ b/Ndmf/Editor/Preview/MeshiaCascadingAvatarMeshSimplifierPreview.cs @@ -7,8 +7,6 @@ using System.Collections.Immutable; using System.Linq; using nadena.dev.ndmf.preview; -using nadena.dev.ndmf.util; -using Unity.Mathematics; using UnityEngine; namespace Meshia.MeshSimplification.Ndmf.Editor.Preview @@ -50,42 +48,12 @@ protected override (MeshSimplificationTarget, MeshSimplifierOptions, BitArray?) var cascadingTarget = context.Observe(component, c => c.Entries[index] with { }, (a, b) => a.Equals(b)); var target = new MeshSimplificationTarget() { Kind = MeshSimplificationTargetKind.AbsoluteTriangleCount, Value = cascadingTarget.TargetTriangleCount }; - - - - if(original is SkinnedMeshRenderer skinnedMeshRenderer) - { - var avatarRoot = context.GetAvatarRoot(original.gameObject); - if(avatarRoot != null) - { - var avatarAnimator = avatarRoot.GetComponent(); - - var bones = skinnedMeshRenderer.bones; - var preserveBorderEdgeBoneIndices = new BitArray(bones.Length); - - for (ulong boneMask = cascadingTarget.PreserveBorderEdgesBones; boneMask != 0ul; boneMask &= boneMask - 1) - { - var bone = (HumanBodyBones)math.tzcnt(boneMask); - var boneTransform = avatarAnimator.GetBoneTransform(bone); - if (boneTransform != null) - { - var boneIndex = Array.IndexOf(bones, boneTransform); - if (boneIndex >= 0) - { - preserveBorderEdgeBoneIndices.Set(boneIndex, true); - } - } - } - - return (target, cascadingTarget.Options, preserveBorderEdgeBoneIndices); - } - - } - return (target, cascadingTarget.Options, null); - - - + var avatarRoot = context.GetAvatarRoot(original.gameObject); + var preserveBorderEdgeBoneIndices = MeshiaCascadingAvatarMeshSimplifier.GetPreserveBorderEdgesBoneIndices(avatarRoot, component, cascadingTarget); + return (target, cascadingTarget.Options, preserveBorderEdgeBoneIndices); } + + } } diff --git a/Ndmf/Runtime/Meshia.MeshSimplification.Ndmf.Runtime.asmdef b/Ndmf/Runtime/Meshia.MeshSimplification.Ndmf.Runtime.asmdef index 79cf285..5d5ab3a 100644 --- a/Ndmf/Runtime/Meshia.MeshSimplification.Ndmf.Runtime.asmdef +++ b/Ndmf/Runtime/Meshia.MeshSimplification.Ndmf.Runtime.asmdef @@ -5,7 +5,8 @@ "Meshia.MeshSimplification.Runtime", "VRC.SDKBase", "nadena.dev.modular-avatar.core", - "nadena.dev.ndmf.runtime" + "nadena.dev.ndmf.runtime", + "Unity.Mathematics" ], "includePlatforms": [], "excludePlatforms": [], diff --git a/Ndmf/Runtime/MeshiaCascadingAvatarMeshSimplifier.cs b/Ndmf/Runtime/MeshiaCascadingAvatarMeshSimplifier.cs index b6241b4..528c134 100644 --- a/Ndmf/Runtime/MeshiaCascadingAvatarMeshSimplifier.cs +++ b/Ndmf/Runtime/MeshiaCascadingAvatarMeshSimplifier.cs @@ -6,10 +6,11 @@ using System.Collections.Generic; using System.Linq; using UnityEngine; -using nadena.dev.ndmf.runtime; using nadena.dev.modular_avatar.core; using UnityEngine.Pool; using System.Diagnostics.CodeAnalysis; +using System.Collections; +using Unity.Mathematics; namespace Meshia.MeshSimplification.Ndmf { @@ -127,6 +128,35 @@ public void ResolveReferences() target.ResolveReference(this); } } + public static BitArray? GetPreserveBorderEdgesBoneIndices(GameObject avatarRoot, MeshiaCascadingAvatarMeshSimplifier avatarMeshSimplifier, MeshiaCascadingAvatarMeshSimplifierRendererEntry entry) + { + if (avatarRoot.TryGetComponent(out Animator avatarAnimator) && entry.GetTargetRenderer(avatarMeshSimplifier) is SkinnedMeshRenderer skinnedMeshRenderer) + { + var bones = skinnedMeshRenderer.bones; + var preserveBorderEdgeBoneIndices = new BitArray(bones.Length); + + for (ulong boneMask = entry.PreserveBorderEdgesBones; boneMask != 0ul; boneMask &= boneMask - 1) + { + var bone = (HumanBodyBones)math.tzcnt(boneMask); + var boneTransform = avatarAnimator.GetBoneTransform(bone); + if (boneTransform != null) + { + var boneIndex = Array.IndexOf(bones, boneTransform); + if (boneIndex != -1) + { + preserveBorderEdgeBoneIndices.Set(boneIndex, true); + } + } + } + return preserveBorderEdgeBoneIndices; + } + else + { + return null; + } + + + } } [Serializable] diff --git a/Runtime/MeshSimplifier.cs b/Runtime/MeshSimplifier.cs index 33a5d3c..aedccfb 100644 --- a/Runtime/MeshSimplifier.cs +++ b/Runtime/MeshSimplifier.cs @@ -2,6 +2,7 @@ using System; using System.Collections; using System.Collections.Generic; +using System.Linq; using System.Threading; using System.Threading.Tasks; using Unity.Collections; @@ -67,7 +68,17 @@ public struct MeshSimplifier : INativeDisposable /// The options for this mesh simplification. /// The destination to write simplified mesh. /// To process multiple meshes at once, use instead. - public static void Simplify(Mesh mesh, MeshSimplificationTarget target, MeshSimplifierOptions options, Mesh destination) + public static void Simplify(Mesh mesh, MeshSimplificationTarget target, MeshSimplifierOptions options, Mesh destination) + => Simplify(mesh, target, options, null, destination); + /// + /// Simplifies the given and writes the result to . + /// + /// The mesh to simplify. + /// The simplification target for this mesh simplification. + /// The options for this mesh simplification. + /// The destination to write simplified mesh. + /// To process multiple meshes at once, use instead. + public static void Simplify(Mesh mesh, MeshSimplificationTarget target, MeshSimplifierOptions options, BitArray? preserveBorderEdgesBoneIndices, Mesh destination) { Allocator allocator = Unity.Collections.Allocator.TempJob; var originalMeshDataArray = Mesh.AcquireReadOnlyMeshData(mesh); @@ -76,11 +87,21 @@ public static void Simplify(Mesh mesh, MeshSimplificationTarget target, MeshSimp var meshSimplifier = new MeshSimplifier(allocator); + NativeBitArray nativePreserveBorderEdgesBoneIndices = new(preserveBorderEdgesBoneIndices?.Length ?? 0, allocator, NativeArrayOptions.UninitializedMemory); + if (preserveBorderEdgesBoneIndices is not null) + { + for (int i = 0; i < preserveBorderEdgesBoneIndices.Length; i++) + { + nativePreserveBorderEdgesBoneIndices.Set(i, preserveBorderEdgesBoneIndices[i]); + } + } + var load = meshSimplifier.ScheduleLoadMeshData(originalMeshData, options); var simplifiedMeshDataArray = Mesh.AllocateWritableMeshData(1); NativeList simplifiedBlendShapes = new(allocator); - var simplify = meshSimplifier.ScheduleSimplify(originalMeshData, blendShapes, target, load); + var simplify = meshSimplifier.ScheduleSimplify(originalMeshData, blendShapes, target, nativePreserveBorderEdgesBoneIndices, load); + nativePreserveBorderEdgesBoneIndices.Dispose(simplify); var write = meshSimplifier.ScheduleWriteMeshData(originalMeshData, blendShapes, simplifiedMeshDataArray[0], simplifiedBlendShapes, simplify); meshSimplifier.Dispose(write); JobHandle.ScheduleBatchedJobs(); @@ -102,7 +123,10 @@ public static void Simplify(Mesh mesh, MeshSimplificationTarget target, MeshSimp } simplifiedBlendShapes.Dispose(); } - public static void SimplifyBatch(IReadOnlyList<(Mesh Mesh, MeshSimplificationTarget Target, MeshSimplifierOptions Options, Mesh Destination)> parameters) + public static void SimplifyBatch(IReadOnlyList<(Mesh Mesh, MeshSimplificationTarget Target, MeshSimplifierOptions Options, Mesh Destination)> parameters) + => SimplifyBatch(parameters.Select<(Mesh Mesh, MeshSimplificationTarget Target, MeshSimplifierOptions Options, Mesh Destination), (Mesh, MeshSimplificationTarget, MeshSimplifierOptions, BitArray?, Mesh)>(p => (p.Mesh, p.Target, p.Options, null, p.Destination)).ToList()); + + public static void SimplifyBatch(IReadOnlyList<(Mesh Mesh, MeshSimplificationTarget Target, MeshSimplifierOptions Options, BitArray? PreserveBorderEdgesBoneIndices, Mesh Destination)> parameters) { Allocator allocator = Unity.Collections.Allocator.TempJob; @@ -124,16 +148,25 @@ public static void SimplifyBatch(IReadOnlyList<(Mesh Mesh, MeshSimplificationTar for (int i = 0; i < parameters.Count; i++) { - var (mesh, target, options, destination) = parameters[i]; + var (mesh, target, options, preserveBorderEdgesBoneIndices, destination) = parameters[i]; var originalMeshData = originalMeshDataArray[i]; var blendShapes = BlendShapeData.GetMeshBlendShapes(mesh, allocator); blendShapesList[i] = blendShapes; var meshSimplifier = new MeshSimplifier(allocator); + NativeBitArray nativePreserveBorderEdgesBoneIndices = new(preserveBorderEdgesBoneIndices?.Length ?? 0, allocator, NativeArrayOptions.UninitializedMemory); + if (preserveBorderEdgesBoneIndices is not null) + { + for (int boneIndex = 0; boneIndex < preserveBorderEdgesBoneIndices.Length; boneIndex++) + { + nativePreserveBorderEdgesBoneIndices.Set(boneIndex, preserveBorderEdgesBoneIndices[boneIndex]); + } + } var load = meshSimplifier.ScheduleLoadMeshData(originalMeshData, options); NativeList simplifiedBlendShapes = new(allocator); simplifiedBlendShapesList[i] = simplifiedBlendShapes; - var simplify = meshSimplifier.ScheduleSimplify(originalMeshData, blendShapes, target, load); + var simplify = meshSimplifier.ScheduleSimplify(originalMeshData, blendShapes, target, nativePreserveBorderEdgesBoneIndices, load); + nativePreserveBorderEdgesBoneIndices.Dispose(simplify); var write = meshSimplifier.ScheduleWriteMeshData(originalMeshData, blendShapes, simplifiedMeshDataArray[i], simplifiedBlendShapes, simplify); meshSimplifier.Dispose(write); jobHandles[i] = write;