From 8af58b5dd56f7ea7a02b677ad7f6adad835cf305 Mon Sep 17 00:00:00 2001 From: NotEvil Date: Fri, 17 Apr 2026 01:40:30 +0200 Subject: [PATCH] =?UTF-8?q?feat(gltf):=20accept=20custom=20bones=20?= =?UTF-8?q?=E2=80=94=20remove=2011-bone=20filter,=20simplify=20joint=20rem?= =?UTF-8?q?ap?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../tiedup/remake/client/gltf/GlbParser.java | 57 +++++++++---------- 1 file changed, 26 insertions(+), 31 deletions(-) diff --git a/src/main/java/com/tiedup/remake/client/gltf/GlbParser.java b/src/main/java/com/tiedup/remake/client/gltf/GlbParser.java index 28228cf..e682c57 100644 --- a/src/main/java/com/tiedup/remake/client/gltf/GlbParser.java +++ b/src/main/java/com/tiedup/remake/client/gltf/GlbParser.java @@ -103,10 +103,8 @@ public final class GlbParser { JsonObject skin = skins.get(0).getAsJsonObject(); JsonArray skinJoints = skin.getAsJsonArray("joints"); - // Filter skin joints to only include known deforming bones - List filteredJointNodes = new ArrayList<>(); - int[] skinJointRemap = new int[skinJoints.size()]; // old skin index -> new filtered index - java.util.Arrays.fill(skinJointRemap, -1); + // Accept all skin joints (no filtering — custom bones are supported) + List allJointNodes = new ArrayList<>(); for (int j = 0; j < skinJoints.size(); j++) { int nodeIdx = skinJoints.get(j).getAsInt(); JsonObject node = nodes.get(nodeIdx).getAsJsonObject(); @@ -117,19 +115,25 @@ public final class GlbParser { if (name.contains("|")) { name = name.substring(name.lastIndexOf('|') + 1); } - if (GltfBoneMapper.isKnownBone(name)) { - skinJointRemap[j] = filteredJointNodes.size(); - filteredJointNodes.add(nodeIdx); - } else { - LOGGER.debug( - "[GltfPipeline] Skipping non-deforming bone: '{}' (node {})", - name, - nodeIdx - ); + // Log info for non-MC bones + if (!GltfBoneMapper.isKnownBone(name)) { + String suggestion = GltfBoneMapper.suggestBoneName(name); + if (suggestion != null) { + LOGGER.warn( + "[GltfPipeline] Unknown bone '{}' in {} — did you mean '{}'? (treated as custom bone)", + name, debugName, suggestion + ); + } else { + LOGGER.info( + "[GltfPipeline] Custom bone '{}' in {} (will follow parent hierarchy in rest pose)", + name, debugName + ); + } } + allJointNodes.add(nodeIdx); } - int jointCount = filteredJointNodes.size(); + int jointCount = allJointNodes.size(); String[] jointNames = new String[jointCount]; int[] parentJointIndices = new int[jointCount]; Quaternionf[] restRotations = new Quaternionf[jointCount]; @@ -139,14 +143,14 @@ public final class GlbParser { int[] nodeToJoint = new int[nodes.size()]; java.util.Arrays.fill(nodeToJoint, -1); for (int j = 0; j < jointCount; j++) { - int nodeIdx = filteredJointNodes.get(j); + int nodeIdx = allJointNodes.get(j); nodeToJoint[nodeIdx] = j; } // Read joint names, rest pose, and build parent mapping java.util.Arrays.fill(parentJointIndices, -1); for (int j = 0; j < jointCount; j++) { - int nodeIdx = filteredJointNodes.get(j); + int nodeIdx = allJointNodes.get(j); JsonObject node = nodes.get(nodeIdx).getAsJsonObject(); String rawName = node.has("name") @@ -200,7 +204,6 @@ public final class GlbParser { } // -- Inverse Bind Matrices -- - // IBM accessor is indexed by original skin joint order, so we pick the filtered entries Matrix4f[] inverseBindMatrices = new Matrix4f[jointCount]; if (skin.has("inverseBindMatrices")) { int ibmAccessor = skin.get("inverseBindMatrices").getAsInt(); @@ -210,12 +213,9 @@ public final class GlbParser { binData, ibmAccessor ); - for (int origJ = 0; origJ < skinJoints.size(); origJ++) { - int newJ = skinJointRemap[origJ]; - if (newJ >= 0) { - inverseBindMatrices[newJ] = new Matrix4f(); - inverseBindMatrices[newJ].set(ibmData, origJ * 16); - } + for (int j = 0; j < jointCount; j++) { + inverseBindMatrices[j] = new Matrix4f(); + inverseBindMatrices[j].set(ibmData, j * 16); } } else { for (int j = 0; j < jointCount; j++) { @@ -344,15 +344,10 @@ public final class GlbParser { binData, attributes.get("JOINTS_0").getAsInt() ); - // Remap vertex joint indices from original skin order to filtered order + // No remap needed — all joints are kept, indices match directly. + // Guard against out-of-range joint indices. for (int i = 0; i < primJoints.length; i++) { - int origIdx = primJoints[i]; - if (origIdx >= 0 && origIdx < skinJointRemap.length) { - primJoints[i] = - skinJointRemap[origIdx] >= 0 - ? skinJointRemap[origIdx] - : 0; - } else { + if (primJoints[i] < 0 || primJoints[i] >= jointCount) { primJoints[i] = 0; } }