diff --git a/Test~/MeshInfo2/MeshInfo2Test.cs b/Test~/MeshInfo2/MeshInfo2Test.cs index 5139f935..8bbdc533 100644 --- a/Test~/MeshInfo2/MeshInfo2Test.cs +++ b/Test~/MeshInfo2/MeshInfo2Test.cs @@ -217,5 +217,59 @@ public void ComputeActualPositionWithBones() Assert.That(position, Is.EqualTo(vertex.Position)); } } + + // test with binary-edited fbx which is originally exported from blender + [Test] + public void MultipleSameNameBlendShapeBlenderBinaryEdited() + { + var fbx = TestUtils.GetAssetAt("MeshInfo2/same-name-blendshape-blender-binary-edited.fbx"); + var renderer = fbx.GetComponent(); + var mesh = renderer.sharedMesh; + + // check the mesh has same name blendShape + Assert.That(mesh.blendShapeCount, Is.EqualTo(2)); + Assert.That(mesh.GetBlendShapeName(0), Is.EqualTo("BlendShape1")); + Assert.That(mesh.GetBlendShapeName(1), Is.EqualTo("BlendShape1")); + + using var meshInfo2 = new MeshInfo2(renderer); + // we've checked no exception is thrown + + // second shape is renamed + Assert.That(meshInfo2.BlendShapes[0].name, Is.EqualTo("BlendShape1")); + Assert.That(meshInfo2.BlendShapes[1].name, Does.StartWith("BlendShape1-nameConflict-")); + // and there is buffer for each vertex + foreach (var vertex in meshInfo2.Vertices) + { + Assert.That(vertex.BlendShapeBuffer.Shapes[meshInfo2.BlendShapes[0].name], Is.Not.Null); + Assert.That(vertex.BlendShapeBuffer.Shapes[meshInfo2.BlendShapes[1].name], Is.Not.Null); + } + } + + // test with real fbx + [Test] + public void MultipleSameNameBlendShape3dsMax() + { + var fbx = TestUtils.GetAssetAt("MeshInfo2/same-name-blendshape-3ds-max.fbx"); + var renderer = fbx.transform.Find("Box001").GetComponent(); + var mesh = renderer.sharedMesh; + + // check the mesh has same name blendShape + Assert.That(mesh.blendShapeCount, Is.EqualTo(2)); + Assert.That(mesh.GetBlendShapeName(0), Is.EqualTo("Shape")); + Assert.That(mesh.GetBlendShapeName(1), Is.EqualTo("Shape")); + + using var meshInfo2 = new MeshInfo2(renderer); + // we've checked no exception is thrown + + // second shape is renamed + Assert.That(meshInfo2.BlendShapes[0].name, Is.EqualTo("Shape")); + Assert.That(meshInfo2.BlendShapes[1].name, Does.StartWith("Shape-nameConflict-")); + // and there is buffer for each vertex + foreach (var vertex in meshInfo2.Vertices) + { + Assert.That(vertex.BlendShapeBuffer.Shapes[meshInfo2.BlendShapes[0].name], Is.Not.Null); + Assert.That(vertex.BlendShapeBuffer.Shapes[meshInfo2.BlendShapes[1].name], Is.Not.Null); + } + } } } diff --git a/Test~/MeshInfo2/same-name-blendshape-3ds-max.fbx b/Test~/MeshInfo2/same-name-blendshape-3ds-max.fbx new file mode 100644 index 00000000..c2afe2ba Binary files /dev/null and b/Test~/MeshInfo2/same-name-blendshape-3ds-max.fbx differ diff --git a/Test~/MeshInfo2/same-name-blendshape-3ds-max.fbx.meta b/Test~/MeshInfo2/same-name-blendshape-3ds-max.fbx.meta new file mode 100644 index 00000000..15476028 --- /dev/null +++ b/Test~/MeshInfo2/same-name-blendshape-3ds-max.fbx.meta @@ -0,0 +1,109 @@ +fileFormatVersion: 2 +guid: 7ca8f16ddc64441cbaf1855da11db6ea +ModelImporter: + serializedVersion: 22200 + internalIDToNameTable: [] + externalObjects: {} + materials: + materialImportMode: 2 + materialName: 0 + materialSearch: 1 + materialLocation: 1 + animations: + legacyGenerateAnimations: 4 + bakeSimulation: 0 + resampleCurves: 1 + optimizeGameObjects: 0 + removeConstantScaleCurves: 0 + motionNodeName: + rigImportErrors: + rigImportWarnings: + animationImportErrors: + animationImportWarnings: + animationRetargetingWarnings: + animationDoRetargetingWarnings: 0 + importAnimatedCustomProperties: 0 + importConstraints: 0 + animationCompression: 1 + animationRotationError: 0.5 + animationPositionError: 0.5 + animationScaleError: 0.5 + animationWrapMode: 0 + extraExposedTransformPaths: [] + extraUserProperties: [] + clipAnimations: [] + isReadable: 0 + meshes: + lODScreenPercentages: [] + globalScale: 1 + meshCompression: 0 + addColliders: 0 + useSRGBMaterialColor: 1 + sortHierarchyByName: 1 + importPhysicalCameras: 1 + importVisibility: 1 + importBlendShapes: 1 + importCameras: 1 + importLights: 1 + nodeNameCollisionStrategy: 1 + fileIdsGeneration: 2 + swapUVChannels: 0 + generateSecondaryUV: 0 + useFileUnits: 1 + keepQuads: 0 + weldVertices: 1 + bakeAxisConversion: 0 + preserveHierarchy: 0 + skinWeightsMode: 0 + maxBonesPerVertex: 4 + minBoneWeight: 0.001 + optimizeBones: 1 + meshOptimizationFlags: -1 + indexFormat: 0 + secondaryUVAngleDistortion: 8 + secondaryUVAreaDistortion: 15.000001 + secondaryUVHardAngle: 88 + secondaryUVMarginMethod: 1 + secondaryUVMinLightmapResolution: 40 + secondaryUVMinObjectScale: 1 + secondaryUVPackMargin: 4 + useFileScale: 1 + strictVertexDataChecks: 0 + tangentSpace: + normalSmoothAngle: 60 + normalImportMode: 0 + tangentImportMode: 3 + normalCalculationMode: 4 + legacyComputeAllNormalsFromSmoothingGroupsWhenMeshHasBlendShapes: 0 + blendShapeNormalImportMode: 1 + normalSmoothingSource: 0 + referencedClips: [] + importAnimation: 1 + humanDescription: + serializedVersion: 3 + human: [] + skeleton: [] + armTwist: 0.5 + foreArmTwist: 0.5 + upperLegTwist: 0.5 + legTwist: 0.5 + armStretch: 0.05 + legStretch: 0.05 + feetSpacing: 0 + globalScale: 1 + rootMotionBoneName: + hasTranslationDoF: 0 + hasExtraRoot: 0 + skeletonHasParents: 1 + lastHumanDescriptionAvatarSource: {instanceID: 0} + autoGenerateAvatarMappingIfUnspecified: 1 + animationType: 2 + humanoidOversampling: 1 + avatarSetup: 0 + addHumanoidExtraRootOnlyWhenUsingAvatar: 1 + importBlendShapeDeformPercent: 1 + remapMaterialsIfMaterialImportModeIsNone: 0 + additionalBone: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Test~/MeshInfo2/same-name-blendshape-blender-binary-edited.fbx b/Test~/MeshInfo2/same-name-blendshape-blender-binary-edited.fbx new file mode 100644 index 00000000..8e1ed699 Binary files /dev/null and b/Test~/MeshInfo2/same-name-blendshape-blender-binary-edited.fbx differ diff --git a/Test~/MeshInfo2/same-name-blendshape-blender-binary-edited.fbx.meta b/Test~/MeshInfo2/same-name-blendshape-blender-binary-edited.fbx.meta new file mode 100644 index 00000000..4d643e93 --- /dev/null +++ b/Test~/MeshInfo2/same-name-blendshape-blender-binary-edited.fbx.meta @@ -0,0 +1,109 @@ +fileFormatVersion: 2 +guid: f03bf31712e364e1387d197f42586cc9 +ModelImporter: + serializedVersion: 22200 + internalIDToNameTable: [] + externalObjects: {} + materials: + materialImportMode: 2 + materialName: 0 + materialSearch: 1 + materialLocation: 1 + animations: + legacyGenerateAnimations: 4 + bakeSimulation: 0 + resampleCurves: 1 + optimizeGameObjects: 0 + removeConstantScaleCurves: 0 + motionNodeName: + rigImportErrors: + rigImportWarnings: + animationImportErrors: + animationImportWarnings: + animationRetargetingWarnings: + animationDoRetargetingWarnings: 0 + importAnimatedCustomProperties: 0 + importConstraints: 0 + animationCompression: 1 + animationRotationError: 0.5 + animationPositionError: 0.5 + animationScaleError: 0.5 + animationWrapMode: 0 + extraExposedTransformPaths: [] + extraUserProperties: [] + clipAnimations: [] + isReadable: 0 + meshes: + lODScreenPercentages: [] + globalScale: 1 + meshCompression: 0 + addColliders: 0 + useSRGBMaterialColor: 1 + sortHierarchyByName: 1 + importPhysicalCameras: 1 + importVisibility: 1 + importBlendShapes: 1 + importCameras: 1 + importLights: 1 + nodeNameCollisionStrategy: 1 + fileIdsGeneration: 2 + swapUVChannels: 0 + generateSecondaryUV: 0 + useFileUnits: 1 + keepQuads: 0 + weldVertices: 1 + bakeAxisConversion: 0 + preserveHierarchy: 0 + skinWeightsMode: 0 + maxBonesPerVertex: 4 + minBoneWeight: 0.001 + optimizeBones: 1 + meshOptimizationFlags: -1 + indexFormat: 0 + secondaryUVAngleDistortion: 8 + secondaryUVAreaDistortion: 15.000001 + secondaryUVHardAngle: 88 + secondaryUVMarginMethod: 1 + secondaryUVMinLightmapResolution: 40 + secondaryUVMinObjectScale: 1 + secondaryUVPackMargin: 4 + useFileScale: 1 + strictVertexDataChecks: 0 + tangentSpace: + normalSmoothAngle: 60 + normalImportMode: 0 + tangentImportMode: 3 + normalCalculationMode: 4 + legacyComputeAllNormalsFromSmoothingGroupsWhenMeshHasBlendShapes: 0 + blendShapeNormalImportMode: 1 + normalSmoothingSource: 0 + referencedClips: [] + importAnimation: 1 + humanDescription: + serializedVersion: 3 + human: [] + skeleton: [] + armTwist: 0.5 + foreArmTwist: 0.5 + upperLegTwist: 0.5 + legTwist: 0.5 + armStretch: 0.05 + legStretch: 0.05 + feetSpacing: 0 + globalScale: 1 + rootMotionBoneName: + hasTranslationDoF: 0 + hasExtraRoot: 0 + skeletonHasParents: 1 + lastHumanDescriptionAvatarSource: {instanceID: 0} + autoGenerateAvatarMappingIfUnspecified: 1 + animationType: 2 + humanoidOversampling: 1 + avatarSetup: 0 + addHumanoidExtraRootOnlyWhenUsingAvatar: 1 + importBlendShapeDeformPercent: 1 + remapMaterialsIfMaterialImportModeIsNone: 0 + additionalBone: 0 + userData: + assetBundleName: + assetBundleVariant: