summaryrefslogtreecommitdiff
path: root/Assets/ThirdParty/VRM
diff options
context:
space:
mode:
Diffstat (limited to 'Assets/ThirdParty/VRM')
-rw-r--r--Assets/ThirdParty/VRM/MeshUtility.meta8
-rw-r--r--Assets/ThirdParty/VRM/MeshUtility/CHANGELOG.md7
-rw-r--r--Assets/ThirdParty/VRM/MeshUtility/CHANGELOG.md.meta7
-rw-r--r--Assets/ThirdParty/VRM/MeshUtility/Documentation.meta8
-rw-r--r--Assets/ThirdParty/VRM/MeshUtility/Documentation/MeshUtility.md7
-rw-r--r--Assets/ThirdParty/VRM/MeshUtility/Documentation/MeshUtility.md.meta7
-rw-r--r--Assets/ThirdParty/VRM/MeshUtility/Documentation/images.meta8
-rw-r--r--Assets/ThirdParty/VRM/MeshUtility/Documentation/images/blendshape_separator.jpgbin0 -> 47176 bytes
-rw-r--r--Assets/ThirdParty/VRM/MeshUtility/Documentation/images/blendshape_separator.jpg.meta88
-rw-r--r--Assets/ThirdParty/VRM/MeshUtility/Documentation/images/installation_1.jpgbin0 -> 23760 bytes
-rw-r--r--Assets/ThirdParty/VRM/MeshUtility/Documentation/images/installation_1.jpg.meta88
-rw-r--r--Assets/ThirdParty/VRM/MeshUtility/Documentation/images/installation_2.jpgbin0 -> 20387 bytes
-rw-r--r--Assets/ThirdParty/VRM/MeshUtility/Documentation/images/installation_2.jpg.meta88
-rw-r--r--Assets/ThirdParty/VRM/MeshUtility/Documentation/images/installation_3.jpgbin0 -> 24575 bytes
-rw-r--r--Assets/ThirdParty/VRM/MeshUtility/Documentation/images/installation_3.jpg.meta88
-rw-r--r--Assets/ThirdParty/VRM/MeshUtility/Documentation/images/interface_1.jpgbin0 -> 17973 bytes
-rw-r--r--Assets/ThirdParty/VRM/MeshUtility/Documentation/images/interface_1.jpg.meta88
-rw-r--r--Assets/ThirdParty/VRM/MeshUtility/Documentation/images/interface_2.jpgbin0 -> 13868 bytes
-rw-r--r--Assets/ThirdParty/VRM/MeshUtility/Documentation/images/interface_2.jpg.meta88
-rw-r--r--Assets/ThirdParty/VRM/MeshUtility/Documentation/images/interface_3.jpgbin0 -> 26061 bytes
-rw-r--r--Assets/ThirdParty/VRM/MeshUtility/Documentation/images/interface_3.jpg.meta88
-rw-r--r--Assets/ThirdParty/VRM/MeshUtility/Documentation/images/result_1.jpgbin0 -> 28604 bytes
-rw-r--r--Assets/ThirdParty/VRM/MeshUtility/Documentation/images/result_1.jpg.meta88
-rw-r--r--Assets/ThirdParty/VRM/MeshUtility/Documentation/images/result_2.jpgbin0 -> 21222 bytes
-rw-r--r--Assets/ThirdParty/VRM/MeshUtility/Documentation/images/result_2.jpg.meta88
-rw-r--r--Assets/ThirdParty/VRM/MeshUtility/Documentation/notes.meta8
-rw-r--r--Assets/ThirdParty/VRM/MeshUtility/Documentation/notes/MeshSeparator.md25
-rw-r--r--Assets/ThirdParty/VRM/MeshUtility/Documentation/notes/MeshSeparator.md.meta7
-rw-r--r--Assets/ThirdParty/VRM/MeshUtility/Editor.meta8
-rw-r--r--Assets/ThirdParty/VRM/MeshUtility/Editor/BoneMeshEraserWizard.cs200
-rw-r--r--Assets/ThirdParty/VRM/MeshUtility/Editor/BoneMeshEraserWizard.cs.meta13
-rw-r--r--Assets/ThirdParty/VRM/MeshUtility/Editor/HumanoidEditor.cs324
-rw-r--r--Assets/ThirdParty/VRM/MeshUtility/Editor/HumanoidEditor.cs.meta11
-rw-r--r--Assets/ThirdParty/VRM/MeshUtility/Editor/MeshUtility.Editor.asmdef16
-rw-r--r--Assets/ThirdParty/VRM/MeshUtility/Editor/MeshUtility.Editor.asmdef.meta7
-rw-r--r--Assets/ThirdParty/VRM/MeshUtility/Editor/MeshUtility.cs286
-rw-r--r--Assets/ThirdParty/VRM/MeshUtility/Editor/MeshUtility.cs.meta11
-rw-r--r--Assets/ThirdParty/VRM/MeshUtility/LICENSE.md9
-rw-r--r--Assets/ThirdParty/VRM/MeshUtility/LICENSE.md.meta7
-rw-r--r--Assets/ThirdParty/VRM/MeshUtility/README.md58
-rw-r--r--Assets/ThirdParty/VRM/MeshUtility/README.md.meta7
-rw-r--r--Assets/ThirdParty/VRM/MeshUtility/README.url2
-rw-r--r--Assets/ThirdParty/VRM/MeshUtility/README.url.meta7
-rw-r--r--Assets/ThirdParty/VRM/MeshUtility/Runtime.meta8
-rw-r--r--Assets/ThirdParty/VRM/MeshUtility/Runtime/BindposeGizmo.cs158
-rw-r--r--Assets/ThirdParty/VRM/MeshUtility/Runtime/BindposeGizmo.cs.meta13
-rw-r--r--Assets/ThirdParty/VRM/MeshUtility/Runtime/BoneMeshEraser.cs166
-rw-r--r--Assets/ThirdParty/VRM/MeshUtility/Runtime/BoneMeshEraser.cs.meta13
-rw-r--r--Assets/ThirdParty/VRM/MeshUtility/Runtime/BoneNormalizer.cs507
-rw-r--r--Assets/ThirdParty/VRM/MeshUtility/Runtime/BoneNormalizer.cs.meta13
-rw-r--r--Assets/ThirdParty/VRM/MeshUtility/Runtime/Humanoid.cs441
-rw-r--r--Assets/ThirdParty/VRM/MeshUtility/Runtime/Humanoid.cs.meta11
-rw-r--r--Assets/ThirdParty/VRM/MeshUtility/Runtime/HumanoidLoader.cs60
-rw-r--r--Assets/ThirdParty/VRM/MeshUtility/Runtime/HumanoidLoader.cs.meta11
-rw-r--r--Assets/ThirdParty/VRM/MeshUtility/Runtime/MeshExtensions.cs85
-rw-r--r--Assets/ThirdParty/VRM/MeshUtility/Runtime/MeshExtensions.cs.meta12
-rw-r--r--Assets/ThirdParty/VRM/MeshUtility/Runtime/MeshIntegrationResult.cs13
-rw-r--r--Assets/ThirdParty/VRM/MeshUtility/Runtime/MeshIntegrationResult.cs.meta11
-rw-r--r--Assets/ThirdParty/VRM/MeshUtility/Runtime/MeshIntegrator.cs253
-rw-r--r--Assets/ThirdParty/VRM/MeshUtility/Runtime/MeshIntegrator.cs.meta3
-rw-r--r--Assets/ThirdParty/VRM/MeshUtility/Runtime/MeshIntegratorUtility.cs140
-rw-r--r--Assets/ThirdParty/VRM/MeshUtility/Runtime/MeshIntegratorUtility.cs.meta3
-rw-r--r--Assets/ThirdParty/VRM/MeshUtility/Runtime/MeshUtility.asmdef3
-rw-r--r--Assets/ThirdParty/VRM/MeshUtility/Runtime/MeshUtility.asmdef.meta7
-rw-r--r--Assets/ThirdParty/VRM/MeshUtility/Runtime/UnityExtensions.cs319
-rw-r--r--Assets/ThirdParty/VRM/MeshUtility/Runtime/UnityExtensions.cs.meta11
-rw-r--r--Assets/ThirdParty/VRM/MeshUtility/Runtime/UnityPath.cs435
-rw-r--r--Assets/ThirdParty/VRM/MeshUtility/Runtime/UnityPath.cs.meta12
-rw-r--r--Assets/ThirdParty/VRM/MeshUtility/package.json13
-rw-r--r--Assets/ThirdParty/VRM/MeshUtility/package.json.meta7
70 files changed, 4578 insertions, 0 deletions
diff --git a/Assets/ThirdParty/VRM/MeshUtility.meta b/Assets/ThirdParty/VRM/MeshUtility.meta
new file mode 100644
index 00000000..28298acd
--- /dev/null
+++ b/Assets/ThirdParty/VRM/MeshUtility.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: f11c20c3f50e40b4f8f6259f8e0886e0
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/ThirdParty/VRM/MeshUtility/CHANGELOG.md b/Assets/ThirdParty/VRM/MeshUtility/CHANGELOG.md
new file mode 100644
index 00000000..8e0827e1
--- /dev/null
+++ b/Assets/ThirdParty/VRM/MeshUtility/CHANGELOG.md
@@ -0,0 +1,7 @@
+# Changelog
+All notable changes to this package will be documented in this file.
+
+## [0.0.1] - 2020-07-01
+### Added
+- The first release of MeshUtility
+- Add MeshSeparator: the mesh with BlendShape can be separated out \ No newline at end of file
diff --git a/Assets/ThirdParty/VRM/MeshUtility/CHANGELOG.md.meta b/Assets/ThirdParty/VRM/MeshUtility/CHANGELOG.md.meta
new file mode 100644
index 00000000..fdcf1a9a
--- /dev/null
+++ b/Assets/ThirdParty/VRM/MeshUtility/CHANGELOG.md.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: 988849cd155716d4f9c3a8f18a856470
+TextScriptImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/ThirdParty/VRM/MeshUtility/Documentation.meta b/Assets/ThirdParty/VRM/MeshUtility/Documentation.meta
new file mode 100644
index 00000000..3a651bf6
--- /dev/null
+++ b/Assets/ThirdParty/VRM/MeshUtility/Documentation.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 42e2174ab737d474ebaee9d1c19b7934
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/ThirdParty/VRM/MeshUtility/Documentation/MeshUtility.md b/Assets/ThirdParty/VRM/MeshUtility/Documentation/MeshUtility.md
new file mode 100644
index 00000000..0a111e70
--- /dev/null
+++ b/Assets/ThirdParty/VRM/MeshUtility/Documentation/MeshUtility.md
@@ -0,0 +1,7 @@
+# MeshUtility
+
+A mesh processing package for mesh separation, etc.
+
+## Documentation Link
+
+[MeshSeparator](https://github.com/vrm-c/UniVRM/tree/master/Assets/MeshUtility/Documentation/notes/MeshSeparator.md) \ No newline at end of file
diff --git a/Assets/ThirdParty/VRM/MeshUtility/Documentation/MeshUtility.md.meta b/Assets/ThirdParty/VRM/MeshUtility/Documentation/MeshUtility.md.meta
new file mode 100644
index 00000000..3e93b85f
--- /dev/null
+++ b/Assets/ThirdParty/VRM/MeshUtility/Documentation/MeshUtility.md.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: 43890cb851a34c5488d15e1a32e7dadc
+TextScriptImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/ThirdParty/VRM/MeshUtility/Documentation/images.meta b/Assets/ThirdParty/VRM/MeshUtility/Documentation/images.meta
new file mode 100644
index 00000000..82cf4db8
--- /dev/null
+++ b/Assets/ThirdParty/VRM/MeshUtility/Documentation/images.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 19a2e88b29a2db943aee731aafda8a84
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/ThirdParty/VRM/MeshUtility/Documentation/images/blendshape_separator.jpg b/Assets/ThirdParty/VRM/MeshUtility/Documentation/images/blendshape_separator.jpg
new file mode 100644
index 00000000..b28eb462
--- /dev/null
+++ b/Assets/ThirdParty/VRM/MeshUtility/Documentation/images/blendshape_separator.jpg
Binary files differ
diff --git a/Assets/ThirdParty/VRM/MeshUtility/Documentation/images/blendshape_separator.jpg.meta b/Assets/ThirdParty/VRM/MeshUtility/Documentation/images/blendshape_separator.jpg.meta
new file mode 100644
index 00000000..b013c05f
--- /dev/null
+++ b/Assets/ThirdParty/VRM/MeshUtility/Documentation/images/blendshape_separator.jpg.meta
@@ -0,0 +1,88 @@
+fileFormatVersion: 2
+guid: a9a09bb093d309947958f67bfe21e095
+TextureImporter:
+ fileIDToRecycleName: {}
+ externalObjects: {}
+ serializedVersion: 9
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 1
+ sRGBTexture: 1
+ linearTexture: 0
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapsPreserveCoverage: 0
+ alphaTestReferenceValue: 0.5
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: 0.25
+ normalMapFilter: 0
+ isReadable: 0
+ streamingMipmaps: 0
+ streamingMipmapsPriority: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 6
+ cubemapConvolution: 0
+ seamlessCubemap: 0
+ textureFormat: 1
+ maxTextureSize: 2048
+ textureSettings:
+ serializedVersion: 2
+ filterMode: -1
+ aniso: -1
+ mipBias: -100
+ wrapU: -1
+ wrapV: -1
+ wrapW: -1
+ nPOTScale: 1
+ lightmap: 0
+ compressionQuality: 50
+ spriteMode: 0
+ spriteExtrude: 1
+ spriteMeshType: 1
+ alignment: 0
+ spritePivot: {x: 0.5, y: 0.5}
+ spritePixelsToUnits: 100
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spriteGenerateFallbackPhysicsShape: 1
+ alphaUsage: 1
+ alphaIsTransparency: 0
+ spriteTessellationDetail: -1
+ textureType: 0
+ textureShape: 1
+ singleChannelComponent: 0
+ maxTextureSizeSet: 0
+ compressionQualitySet: 0
+ textureFormatSet: 0
+ platformSettings:
+ - serializedVersion: 2
+ buildTarget: DefaultTexturePlatform
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ androidETC2FallbackOverride: 0
+ spriteSheet:
+ serializedVersion: 2
+ sprites: []
+ outline: []
+ physicsShape: []
+ bones: []
+ spriteID:
+ vertices: []
+ indices:
+ edges: []
+ weights: []
+ spritePackingTag:
+ pSDRemoveMatte: 0
+ pSDShowRemoveMatteOption: 0
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/ThirdParty/VRM/MeshUtility/Documentation/images/installation_1.jpg b/Assets/ThirdParty/VRM/MeshUtility/Documentation/images/installation_1.jpg
new file mode 100644
index 00000000..bd916403
--- /dev/null
+++ b/Assets/ThirdParty/VRM/MeshUtility/Documentation/images/installation_1.jpg
Binary files differ
diff --git a/Assets/ThirdParty/VRM/MeshUtility/Documentation/images/installation_1.jpg.meta b/Assets/ThirdParty/VRM/MeshUtility/Documentation/images/installation_1.jpg.meta
new file mode 100644
index 00000000..fcd26b64
--- /dev/null
+++ b/Assets/ThirdParty/VRM/MeshUtility/Documentation/images/installation_1.jpg.meta
@@ -0,0 +1,88 @@
+fileFormatVersion: 2
+guid: b3d26d2cfebad4b43a904c4a9978fadf
+TextureImporter:
+ fileIDToRecycleName: {}
+ externalObjects: {}
+ serializedVersion: 9
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 1
+ sRGBTexture: 1
+ linearTexture: 0
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapsPreserveCoverage: 0
+ alphaTestReferenceValue: 0.5
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: 0.25
+ normalMapFilter: 0
+ isReadable: 0
+ streamingMipmaps: 0
+ streamingMipmapsPriority: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 6
+ cubemapConvolution: 0
+ seamlessCubemap: 0
+ textureFormat: 1
+ maxTextureSize: 2048
+ textureSettings:
+ serializedVersion: 2
+ filterMode: -1
+ aniso: -1
+ mipBias: -100
+ wrapU: -1
+ wrapV: -1
+ wrapW: -1
+ nPOTScale: 1
+ lightmap: 0
+ compressionQuality: 50
+ spriteMode: 0
+ spriteExtrude: 1
+ spriteMeshType: 1
+ alignment: 0
+ spritePivot: {x: 0.5, y: 0.5}
+ spritePixelsToUnits: 100
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spriteGenerateFallbackPhysicsShape: 1
+ alphaUsage: 1
+ alphaIsTransparency: 0
+ spriteTessellationDetail: -1
+ textureType: 0
+ textureShape: 1
+ singleChannelComponent: 0
+ maxTextureSizeSet: 0
+ compressionQualitySet: 0
+ textureFormatSet: 0
+ platformSettings:
+ - serializedVersion: 2
+ buildTarget: DefaultTexturePlatform
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ androidETC2FallbackOverride: 0
+ spriteSheet:
+ serializedVersion: 2
+ sprites: []
+ outline: []
+ physicsShape: []
+ bones: []
+ spriteID:
+ vertices: []
+ indices:
+ edges: []
+ weights: []
+ spritePackingTag:
+ pSDRemoveMatte: 0
+ pSDShowRemoveMatteOption: 0
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/ThirdParty/VRM/MeshUtility/Documentation/images/installation_2.jpg b/Assets/ThirdParty/VRM/MeshUtility/Documentation/images/installation_2.jpg
new file mode 100644
index 00000000..e31b7ec9
--- /dev/null
+++ b/Assets/ThirdParty/VRM/MeshUtility/Documentation/images/installation_2.jpg
Binary files differ
diff --git a/Assets/ThirdParty/VRM/MeshUtility/Documentation/images/installation_2.jpg.meta b/Assets/ThirdParty/VRM/MeshUtility/Documentation/images/installation_2.jpg.meta
new file mode 100644
index 00000000..26b42b79
--- /dev/null
+++ b/Assets/ThirdParty/VRM/MeshUtility/Documentation/images/installation_2.jpg.meta
@@ -0,0 +1,88 @@
+fileFormatVersion: 2
+guid: 323176881f04b704bad2644d21ce914a
+TextureImporter:
+ fileIDToRecycleName: {}
+ externalObjects: {}
+ serializedVersion: 9
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 1
+ sRGBTexture: 1
+ linearTexture: 0
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapsPreserveCoverage: 0
+ alphaTestReferenceValue: 0.5
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: 0.25
+ normalMapFilter: 0
+ isReadable: 0
+ streamingMipmaps: 0
+ streamingMipmapsPriority: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 6
+ cubemapConvolution: 0
+ seamlessCubemap: 0
+ textureFormat: 1
+ maxTextureSize: 2048
+ textureSettings:
+ serializedVersion: 2
+ filterMode: -1
+ aniso: -1
+ mipBias: -100
+ wrapU: -1
+ wrapV: -1
+ wrapW: -1
+ nPOTScale: 1
+ lightmap: 0
+ compressionQuality: 50
+ spriteMode: 0
+ spriteExtrude: 1
+ spriteMeshType: 1
+ alignment: 0
+ spritePivot: {x: 0.5, y: 0.5}
+ spritePixelsToUnits: 100
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spriteGenerateFallbackPhysicsShape: 1
+ alphaUsage: 1
+ alphaIsTransparency: 0
+ spriteTessellationDetail: -1
+ textureType: 0
+ textureShape: 1
+ singleChannelComponent: 0
+ maxTextureSizeSet: 0
+ compressionQualitySet: 0
+ textureFormatSet: 0
+ platformSettings:
+ - serializedVersion: 2
+ buildTarget: DefaultTexturePlatform
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ androidETC2FallbackOverride: 0
+ spriteSheet:
+ serializedVersion: 2
+ sprites: []
+ outline: []
+ physicsShape: []
+ bones: []
+ spriteID:
+ vertices: []
+ indices:
+ edges: []
+ weights: []
+ spritePackingTag:
+ pSDRemoveMatte: 0
+ pSDShowRemoveMatteOption: 0
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/ThirdParty/VRM/MeshUtility/Documentation/images/installation_3.jpg b/Assets/ThirdParty/VRM/MeshUtility/Documentation/images/installation_3.jpg
new file mode 100644
index 00000000..5d0aaed2
--- /dev/null
+++ b/Assets/ThirdParty/VRM/MeshUtility/Documentation/images/installation_3.jpg
Binary files differ
diff --git a/Assets/ThirdParty/VRM/MeshUtility/Documentation/images/installation_3.jpg.meta b/Assets/ThirdParty/VRM/MeshUtility/Documentation/images/installation_3.jpg.meta
new file mode 100644
index 00000000..f3b98799
--- /dev/null
+++ b/Assets/ThirdParty/VRM/MeshUtility/Documentation/images/installation_3.jpg.meta
@@ -0,0 +1,88 @@
+fileFormatVersion: 2
+guid: e9dd20fb6b4bcb146b40e8f729725fa9
+TextureImporter:
+ fileIDToRecycleName: {}
+ externalObjects: {}
+ serializedVersion: 9
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 1
+ sRGBTexture: 1
+ linearTexture: 0
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapsPreserveCoverage: 0
+ alphaTestReferenceValue: 0.5
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: 0.25
+ normalMapFilter: 0
+ isReadable: 0
+ streamingMipmaps: 0
+ streamingMipmapsPriority: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 6
+ cubemapConvolution: 0
+ seamlessCubemap: 0
+ textureFormat: 1
+ maxTextureSize: 2048
+ textureSettings:
+ serializedVersion: 2
+ filterMode: -1
+ aniso: -1
+ mipBias: -100
+ wrapU: -1
+ wrapV: -1
+ wrapW: -1
+ nPOTScale: 1
+ lightmap: 0
+ compressionQuality: 50
+ spriteMode: 0
+ spriteExtrude: 1
+ spriteMeshType: 1
+ alignment: 0
+ spritePivot: {x: 0.5, y: 0.5}
+ spritePixelsToUnits: 100
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spriteGenerateFallbackPhysicsShape: 1
+ alphaUsage: 1
+ alphaIsTransparency: 0
+ spriteTessellationDetail: -1
+ textureType: 0
+ textureShape: 1
+ singleChannelComponent: 0
+ maxTextureSizeSet: 0
+ compressionQualitySet: 0
+ textureFormatSet: 0
+ platformSettings:
+ - serializedVersion: 2
+ buildTarget: DefaultTexturePlatform
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ androidETC2FallbackOverride: 0
+ spriteSheet:
+ serializedVersion: 2
+ sprites: []
+ outline: []
+ physicsShape: []
+ bones: []
+ spriteID:
+ vertices: []
+ indices:
+ edges: []
+ weights: []
+ spritePackingTag:
+ pSDRemoveMatte: 0
+ pSDShowRemoveMatteOption: 0
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/ThirdParty/VRM/MeshUtility/Documentation/images/interface_1.jpg b/Assets/ThirdParty/VRM/MeshUtility/Documentation/images/interface_1.jpg
new file mode 100644
index 00000000..eec170ec
--- /dev/null
+++ b/Assets/ThirdParty/VRM/MeshUtility/Documentation/images/interface_1.jpg
Binary files differ
diff --git a/Assets/ThirdParty/VRM/MeshUtility/Documentation/images/interface_1.jpg.meta b/Assets/ThirdParty/VRM/MeshUtility/Documentation/images/interface_1.jpg.meta
new file mode 100644
index 00000000..ea056784
--- /dev/null
+++ b/Assets/ThirdParty/VRM/MeshUtility/Documentation/images/interface_1.jpg.meta
@@ -0,0 +1,88 @@
+fileFormatVersion: 2
+guid: 1ddbc5d5bb1796c4ab3ccdd5d0c29aa7
+TextureImporter:
+ fileIDToRecycleName: {}
+ externalObjects: {}
+ serializedVersion: 9
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 1
+ sRGBTexture: 1
+ linearTexture: 0
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapsPreserveCoverage: 0
+ alphaTestReferenceValue: 0.5
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: 0.25
+ normalMapFilter: 0
+ isReadable: 0
+ streamingMipmaps: 0
+ streamingMipmapsPriority: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 6
+ cubemapConvolution: 0
+ seamlessCubemap: 0
+ textureFormat: 1
+ maxTextureSize: 2048
+ textureSettings:
+ serializedVersion: 2
+ filterMode: -1
+ aniso: -1
+ mipBias: -100
+ wrapU: -1
+ wrapV: -1
+ wrapW: -1
+ nPOTScale: 1
+ lightmap: 0
+ compressionQuality: 50
+ spriteMode: 0
+ spriteExtrude: 1
+ spriteMeshType: 1
+ alignment: 0
+ spritePivot: {x: 0.5, y: 0.5}
+ spritePixelsToUnits: 100
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spriteGenerateFallbackPhysicsShape: 1
+ alphaUsage: 1
+ alphaIsTransparency: 0
+ spriteTessellationDetail: -1
+ textureType: 0
+ textureShape: 1
+ singleChannelComponent: 0
+ maxTextureSizeSet: 0
+ compressionQualitySet: 0
+ textureFormatSet: 0
+ platformSettings:
+ - serializedVersion: 2
+ buildTarget: DefaultTexturePlatform
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ androidETC2FallbackOverride: 0
+ spriteSheet:
+ serializedVersion: 2
+ sprites: []
+ outline: []
+ physicsShape: []
+ bones: []
+ spriteID:
+ vertices: []
+ indices:
+ edges: []
+ weights: []
+ spritePackingTag:
+ pSDRemoveMatte: 0
+ pSDShowRemoveMatteOption: 0
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/ThirdParty/VRM/MeshUtility/Documentation/images/interface_2.jpg b/Assets/ThirdParty/VRM/MeshUtility/Documentation/images/interface_2.jpg
new file mode 100644
index 00000000..98adf2b9
--- /dev/null
+++ b/Assets/ThirdParty/VRM/MeshUtility/Documentation/images/interface_2.jpg
Binary files differ
diff --git a/Assets/ThirdParty/VRM/MeshUtility/Documentation/images/interface_2.jpg.meta b/Assets/ThirdParty/VRM/MeshUtility/Documentation/images/interface_2.jpg.meta
new file mode 100644
index 00000000..8754427e
--- /dev/null
+++ b/Assets/ThirdParty/VRM/MeshUtility/Documentation/images/interface_2.jpg.meta
@@ -0,0 +1,88 @@
+fileFormatVersion: 2
+guid: 23c78259991e1cf49a88e110cd18e0ed
+TextureImporter:
+ fileIDToRecycleName: {}
+ externalObjects: {}
+ serializedVersion: 9
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 1
+ sRGBTexture: 1
+ linearTexture: 0
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapsPreserveCoverage: 0
+ alphaTestReferenceValue: 0.5
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: 0.25
+ normalMapFilter: 0
+ isReadable: 0
+ streamingMipmaps: 0
+ streamingMipmapsPriority: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 6
+ cubemapConvolution: 0
+ seamlessCubemap: 0
+ textureFormat: 1
+ maxTextureSize: 2048
+ textureSettings:
+ serializedVersion: 2
+ filterMode: -1
+ aniso: -1
+ mipBias: -100
+ wrapU: -1
+ wrapV: -1
+ wrapW: -1
+ nPOTScale: 1
+ lightmap: 0
+ compressionQuality: 50
+ spriteMode: 0
+ spriteExtrude: 1
+ spriteMeshType: 1
+ alignment: 0
+ spritePivot: {x: 0.5, y: 0.5}
+ spritePixelsToUnits: 100
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spriteGenerateFallbackPhysicsShape: 1
+ alphaUsage: 1
+ alphaIsTransparency: 0
+ spriteTessellationDetail: -1
+ textureType: 0
+ textureShape: 1
+ singleChannelComponent: 0
+ maxTextureSizeSet: 0
+ compressionQualitySet: 0
+ textureFormatSet: 0
+ platformSettings:
+ - serializedVersion: 2
+ buildTarget: DefaultTexturePlatform
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ androidETC2FallbackOverride: 0
+ spriteSheet:
+ serializedVersion: 2
+ sprites: []
+ outline: []
+ physicsShape: []
+ bones: []
+ spriteID:
+ vertices: []
+ indices:
+ edges: []
+ weights: []
+ spritePackingTag:
+ pSDRemoveMatte: 0
+ pSDShowRemoveMatteOption: 0
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/ThirdParty/VRM/MeshUtility/Documentation/images/interface_3.jpg b/Assets/ThirdParty/VRM/MeshUtility/Documentation/images/interface_3.jpg
new file mode 100644
index 00000000..e9d52bf4
--- /dev/null
+++ b/Assets/ThirdParty/VRM/MeshUtility/Documentation/images/interface_3.jpg
Binary files differ
diff --git a/Assets/ThirdParty/VRM/MeshUtility/Documentation/images/interface_3.jpg.meta b/Assets/ThirdParty/VRM/MeshUtility/Documentation/images/interface_3.jpg.meta
new file mode 100644
index 00000000..4dc7751a
--- /dev/null
+++ b/Assets/ThirdParty/VRM/MeshUtility/Documentation/images/interface_3.jpg.meta
@@ -0,0 +1,88 @@
+fileFormatVersion: 2
+guid: c6bc8b3735742bd439c4f5eee478cc1a
+TextureImporter:
+ fileIDToRecycleName: {}
+ externalObjects: {}
+ serializedVersion: 9
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 1
+ sRGBTexture: 1
+ linearTexture: 0
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapsPreserveCoverage: 0
+ alphaTestReferenceValue: 0.5
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: 0.25
+ normalMapFilter: 0
+ isReadable: 0
+ streamingMipmaps: 0
+ streamingMipmapsPriority: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 6
+ cubemapConvolution: 0
+ seamlessCubemap: 0
+ textureFormat: 1
+ maxTextureSize: 2048
+ textureSettings:
+ serializedVersion: 2
+ filterMode: -1
+ aniso: -1
+ mipBias: -100
+ wrapU: -1
+ wrapV: -1
+ wrapW: -1
+ nPOTScale: 1
+ lightmap: 0
+ compressionQuality: 50
+ spriteMode: 0
+ spriteExtrude: 1
+ spriteMeshType: 1
+ alignment: 0
+ spritePivot: {x: 0.5, y: 0.5}
+ spritePixelsToUnits: 100
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spriteGenerateFallbackPhysicsShape: 1
+ alphaUsage: 1
+ alphaIsTransparency: 0
+ spriteTessellationDetail: -1
+ textureType: 0
+ textureShape: 1
+ singleChannelComponent: 0
+ maxTextureSizeSet: 0
+ compressionQualitySet: 0
+ textureFormatSet: 0
+ platformSettings:
+ - serializedVersion: 2
+ buildTarget: DefaultTexturePlatform
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ androidETC2FallbackOverride: 0
+ spriteSheet:
+ serializedVersion: 2
+ sprites: []
+ outline: []
+ physicsShape: []
+ bones: []
+ spriteID:
+ vertices: []
+ indices:
+ edges: []
+ weights: []
+ spritePackingTag:
+ pSDRemoveMatte: 0
+ pSDShowRemoveMatteOption: 0
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/ThirdParty/VRM/MeshUtility/Documentation/images/result_1.jpg b/Assets/ThirdParty/VRM/MeshUtility/Documentation/images/result_1.jpg
new file mode 100644
index 00000000..65d704cd
--- /dev/null
+++ b/Assets/ThirdParty/VRM/MeshUtility/Documentation/images/result_1.jpg
Binary files differ
diff --git a/Assets/ThirdParty/VRM/MeshUtility/Documentation/images/result_1.jpg.meta b/Assets/ThirdParty/VRM/MeshUtility/Documentation/images/result_1.jpg.meta
new file mode 100644
index 00000000..03db4542
--- /dev/null
+++ b/Assets/ThirdParty/VRM/MeshUtility/Documentation/images/result_1.jpg.meta
@@ -0,0 +1,88 @@
+fileFormatVersion: 2
+guid: 1be7c06f1e0cc2a448ad9166891d03dd
+TextureImporter:
+ fileIDToRecycleName: {}
+ externalObjects: {}
+ serializedVersion: 9
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 1
+ sRGBTexture: 1
+ linearTexture: 0
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapsPreserveCoverage: 0
+ alphaTestReferenceValue: 0.5
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: 0.25
+ normalMapFilter: 0
+ isReadable: 0
+ streamingMipmaps: 0
+ streamingMipmapsPriority: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 6
+ cubemapConvolution: 0
+ seamlessCubemap: 0
+ textureFormat: 1
+ maxTextureSize: 2048
+ textureSettings:
+ serializedVersion: 2
+ filterMode: -1
+ aniso: -1
+ mipBias: -100
+ wrapU: -1
+ wrapV: -1
+ wrapW: -1
+ nPOTScale: 1
+ lightmap: 0
+ compressionQuality: 50
+ spriteMode: 0
+ spriteExtrude: 1
+ spriteMeshType: 1
+ alignment: 0
+ spritePivot: {x: 0.5, y: 0.5}
+ spritePixelsToUnits: 100
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spriteGenerateFallbackPhysicsShape: 1
+ alphaUsage: 1
+ alphaIsTransparency: 0
+ spriteTessellationDetail: -1
+ textureType: 0
+ textureShape: 1
+ singleChannelComponent: 0
+ maxTextureSizeSet: 0
+ compressionQualitySet: 0
+ textureFormatSet: 0
+ platformSettings:
+ - serializedVersion: 2
+ buildTarget: DefaultTexturePlatform
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ androidETC2FallbackOverride: 0
+ spriteSheet:
+ serializedVersion: 2
+ sprites: []
+ outline: []
+ physicsShape: []
+ bones: []
+ spriteID:
+ vertices: []
+ indices:
+ edges: []
+ weights: []
+ spritePackingTag:
+ pSDRemoveMatte: 0
+ pSDShowRemoveMatteOption: 0
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/ThirdParty/VRM/MeshUtility/Documentation/images/result_2.jpg b/Assets/ThirdParty/VRM/MeshUtility/Documentation/images/result_2.jpg
new file mode 100644
index 00000000..951347ea
--- /dev/null
+++ b/Assets/ThirdParty/VRM/MeshUtility/Documentation/images/result_2.jpg
Binary files differ
diff --git a/Assets/ThirdParty/VRM/MeshUtility/Documentation/images/result_2.jpg.meta b/Assets/ThirdParty/VRM/MeshUtility/Documentation/images/result_2.jpg.meta
new file mode 100644
index 00000000..20249090
--- /dev/null
+++ b/Assets/ThirdParty/VRM/MeshUtility/Documentation/images/result_2.jpg.meta
@@ -0,0 +1,88 @@
+fileFormatVersion: 2
+guid: d2fa21619ba10b043a82f64ccca30878
+TextureImporter:
+ fileIDToRecycleName: {}
+ externalObjects: {}
+ serializedVersion: 9
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 1
+ sRGBTexture: 1
+ linearTexture: 0
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapsPreserveCoverage: 0
+ alphaTestReferenceValue: 0.5
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: 0.25
+ normalMapFilter: 0
+ isReadable: 0
+ streamingMipmaps: 0
+ streamingMipmapsPriority: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 6
+ cubemapConvolution: 0
+ seamlessCubemap: 0
+ textureFormat: 1
+ maxTextureSize: 2048
+ textureSettings:
+ serializedVersion: 2
+ filterMode: -1
+ aniso: -1
+ mipBias: -100
+ wrapU: -1
+ wrapV: -1
+ wrapW: -1
+ nPOTScale: 1
+ lightmap: 0
+ compressionQuality: 50
+ spriteMode: 0
+ spriteExtrude: 1
+ spriteMeshType: 1
+ alignment: 0
+ spritePivot: {x: 0.5, y: 0.5}
+ spritePixelsToUnits: 100
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spriteGenerateFallbackPhysicsShape: 1
+ alphaUsage: 1
+ alphaIsTransparency: 0
+ spriteTessellationDetail: -1
+ textureType: 0
+ textureShape: 1
+ singleChannelComponent: 0
+ maxTextureSizeSet: 0
+ compressionQualitySet: 0
+ textureFormatSet: 0
+ platformSettings:
+ - serializedVersion: 2
+ buildTarget: DefaultTexturePlatform
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ androidETC2FallbackOverride: 0
+ spriteSheet:
+ serializedVersion: 2
+ sprites: []
+ outline: []
+ physicsShape: []
+ bones: []
+ spriteID:
+ vertices: []
+ indices:
+ edges: []
+ weights: []
+ spritePackingTag:
+ pSDRemoveMatte: 0
+ pSDShowRemoveMatteOption: 0
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/ThirdParty/VRM/MeshUtility/Documentation/notes.meta b/Assets/ThirdParty/VRM/MeshUtility/Documentation/notes.meta
new file mode 100644
index 00000000..72f20c27
--- /dev/null
+++ b/Assets/ThirdParty/VRM/MeshUtility/Documentation/notes.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: ea010ddf8bf34de4fb36d95afb078702
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/ThirdParty/VRM/MeshUtility/Documentation/notes/MeshSeparator.md b/Assets/ThirdParty/VRM/MeshUtility/Documentation/notes/MeshSeparator.md
new file mode 100644
index 00000000..da93e7d9
--- /dev/null
+++ b/Assets/ThirdParty/VRM/MeshUtility/Documentation/notes/MeshSeparator.md
@@ -0,0 +1,25 @@
+# MeshSeparator
+
+MeshSeparator provides a functionality of separating meshes contained BlendShape. Simply select a GameObject with skinned Meshes and click processing. The mesh splitting results are generated in the Assets folder. The model with sparse BlendShape data distributed in a large-volume mesh can be benefited from size reduction and performance improvements after mesh separation.
+
+## How to use
+
+Select a GameObject contained skinned mesh and BlendShape:
+
+<img src="../images/interface_1.jpg" width="200">
+
+Select `Mesh Utility` -> `MeshSeparator`:
+
+<img src="../images/interface_2.jpg" width="200">
+
+The separate meshes are saved in the Assets folder. GameObjects with separate meshes are also available in the Hierarchy Window:
+
+<img src="../images/interface_3.jpg" width="200">
+
+In this example, the model's mesh are split into two parts: face and body:
+
+Face: with BlendShape | Body: without BlendShape
+:-------------------------:|:-------------------------:
+<img title="result_1.jpg" src="../images/result_1.jpg" width="200"> | <img title="result_2.jpg" src="../images/result_2.jpg" width="200">
+
+Note that if all the polygons of a mesh are used by BlendShape, MeshSeparator will not perform mesh separation. \ No newline at end of file
diff --git a/Assets/ThirdParty/VRM/MeshUtility/Documentation/notes/MeshSeparator.md.meta b/Assets/ThirdParty/VRM/MeshUtility/Documentation/notes/MeshSeparator.md.meta
new file mode 100644
index 00000000..13d9f1f9
--- /dev/null
+++ b/Assets/ThirdParty/VRM/MeshUtility/Documentation/notes/MeshSeparator.md.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: ad5ca4fe4bdde854bb90cb5a3aa267d4
+TextScriptImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/ThirdParty/VRM/MeshUtility/Editor.meta b/Assets/ThirdParty/VRM/MeshUtility/Editor.meta
new file mode 100644
index 00000000..9c63441d
--- /dev/null
+++ b/Assets/ThirdParty/VRM/MeshUtility/Editor.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 1e0d906064b5cad4394c89ec960a887e
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/ThirdParty/VRM/MeshUtility/Editor/BoneMeshEraserWizard.cs b/Assets/ThirdParty/VRM/MeshUtility/Editor/BoneMeshEraserWizard.cs
new file mode 100644
index 00000000..63bf9045
--- /dev/null
+++ b/Assets/ThirdParty/VRM/MeshUtility/Editor/BoneMeshEraserWizard.cs
@@ -0,0 +1,200 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using UnityEditor;
+using UnityEngine;
+
+
+namespace MeshUtility
+{
+ [CustomPropertyDrawer(typeof(BoneMeshEraser.EraseBone))]
+ public class EraseBoneDrawer : PropertyDrawer
+ {
+ public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
+ {
+ //EditorGUI.BeginProperty(position, label, property);
+
+ var leftWidth = 0.6f;
+ var rightWidth = 1.0f - leftWidth;
+
+ var leftSide = new Rect(position.x, position.y, position.width * leftWidth, position.height);
+ var rightSide = new Rect(position.width * leftWidth, position.y, position.width * rightWidth, position.height);
+ {
+ EditorGUI.PropertyField(leftSide, property.FindPropertyRelative("Bone"), new GUIContent("", ""));
+ EditorGUI.PropertyField(rightSide, property.FindPropertyRelative("Erase"));
+ }
+
+ //EditorGUI.EndProperty();
+ }
+
+ public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
+ {
+ var height = base.GetPropertyHeight(property, label);
+ return height;
+ }
+ }
+
+ public class BoneMeshEraserWizard : ScriptableWizard
+ {
+ const string ASSET_SUFFIX = ".asset";
+
+ [SerializeField]
+ SkinnedMeshRenderer m_skinnedMesh;
+
+ [SerializeField]
+ Animator m_animator;
+
+ [SerializeField]
+ Transform EraseRoot;
+
+ [SerializeField]
+ BoneMeshEraser.EraseBone[] m_eraseBones;
+
+ [MenuItem(MeshUtility.MENU_PARENT + "BoneMeshEraser Wizard", priority = 4)]
+ static void CreateWizard()
+ {
+ ScriptableWizard.DisplayWizard<BoneMeshEraserWizard>("BoneMeshEraser", "Erase triangles by bone", "Erase");
+ }
+
+ private void OnEnable()
+ {
+ var root = Selection.activeGameObject;
+ if (root != null)
+ {
+ m_animator = root.GetComponent<Animator>();
+ m_skinnedMesh = root.GetComponent<SkinnedMeshRenderer>();
+ OnValidate();
+ }
+ }
+
+ void OnValidate()
+ {
+ //Debug.Log("OnValidate");
+ if (m_skinnedMesh == null)
+ {
+ m_eraseBones = new BoneMeshEraser.EraseBone[] { };
+ return;
+ }
+
+ if (EraseRoot == null)
+ {
+ if (m_animator != null)
+ {
+ EraseRoot = m_animator.GetBoneTransform(HumanBodyBones.Head);
+ //Debug.LogFormat("head: {0}", EraseRoot);
+ }
+ }
+
+ m_eraseBones = m_skinnedMesh.bones.Select(x =>
+ {
+ var eb = new BoneMeshEraser.EraseBone
+ {
+ Bone = x,
+ };
+
+ if (EraseRoot != null)
+ {
+ // 首の子孫を消去
+ if (eb.Bone.Ancestor().Any(y => y == EraseRoot))
+ {
+ //Debug.LogFormat("erase {0}", x);
+ eb.Erase = true;
+ }
+ }
+
+ return eb;
+ })
+ .ToArray();
+ }
+
+ void OnWizardUpdate()
+ {
+ helpString = "select target skinnedMesh and animator";
+ }
+
+
+
+ static int IndexOf(Transform[] list, Transform target)
+ {
+ for (int i = 0; i < list.Length; ++i)
+ {
+ if (list[i] == target)
+ {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ SkinnedMeshRenderer _Erase(GameObject go)
+ {
+ if (go == null)
+ {
+ Debug.LogWarning("select root object in hierarchy");
+ return null;
+ }
+ if (m_skinnedMesh == null)
+ {
+ Debug.LogWarning("no skinnedmesh");
+ return null;
+ }
+
+ var bones = m_skinnedMesh.bones;
+ var eraseBones = m_eraseBones
+ .Where(x => x.Erase)
+ .Select(x => Array.IndexOf(bones, x.Bone))
+ .ToArray();
+
+ var meshNode = new GameObject("BoneMeshEraser");
+ meshNode.transform.SetParent(go.transform, false);
+
+ var erased = meshNode.AddComponent<SkinnedMeshRenderer>();
+ erased.sharedMesh = BoneMeshEraser.CreateErasedMesh(m_skinnedMesh.sharedMesh, eraseBones);
+ erased.sharedMaterials = m_skinnedMesh.sharedMaterials;
+ erased.bones = m_skinnedMesh.bones;
+
+ return erased;
+ }
+
+ void Erase()
+ {
+ var go = Selection.activeGameObject;
+ var renderer = _Erase(go);
+ if (renderer == null)
+ {
+ return;
+ }
+
+ // save mesh to Assets
+ var assetPath = string.Format("{0}{1}", go.name, ASSET_SUFFIX);
+ var prefab = MeshUtility.GetPrefab(go);
+ if (prefab != null)
+ {
+ var prefabPath = AssetDatabase.GetAssetPath(prefab);
+ assetPath = string.Format("{0}/{1}{2}",
+ Path.GetDirectoryName(prefabPath),
+ Path.GetFileNameWithoutExtension(prefabPath),
+ ASSET_SUFFIX
+ );
+ }
+
+ Debug.LogFormat("CreateAsset: {0}", assetPath);
+ AssetDatabase.CreateAsset(renderer.sharedMesh, assetPath);
+ }
+
+ void OnWizardCreate()
+ {
+ //Debug.Log("OnWizardCreate");
+ Erase();
+
+ // close
+ }
+
+ void OnWizardOtherButton()
+ {
+ //Debug.Log("OnWizardOtherButton");
+ Erase();
+ }
+ }
+}
diff --git a/Assets/ThirdParty/VRM/MeshUtility/Editor/BoneMeshEraserWizard.cs.meta b/Assets/ThirdParty/VRM/MeshUtility/Editor/BoneMeshEraserWizard.cs.meta
new file mode 100644
index 00000000..ef9f3976
--- /dev/null
+++ b/Assets/ThirdParty/VRM/MeshUtility/Editor/BoneMeshEraserWizard.cs.meta
@@ -0,0 +1,13 @@
+fileFormatVersion: 2
+guid: 881b00db73f639c48a3f043a775fa61a
+timeCreated: 1518503829
+licenseType: Free
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/ThirdParty/VRM/MeshUtility/Editor/HumanoidEditor.cs b/Assets/ThirdParty/VRM/MeshUtility/Editor/HumanoidEditor.cs
new file mode 100644
index 00000000..f9a99cfc
--- /dev/null
+++ b/Assets/ThirdParty/VRM/MeshUtility/Editor/HumanoidEditor.cs
@@ -0,0 +1,324 @@
+using System.Collections;
+using System.Collections.Generic;
+using System.Linq;
+using System.IO;
+using UnityEditor;
+using UnityEngine;
+using System;
+
+namespace MeshUtility
+{
+ [CustomEditor(typeof(Humanoid))]
+ public class HumanoidEditor : Editor
+ {
+ const int LABEL_WIDTH = 100;
+
+ Humanoid m_target;
+
+ SerializedProperty m_Hips;
+ #region leg
+ SerializedProperty m_LeftUpperLeg;
+ SerializedProperty m_RightUpperLeg;
+ SerializedProperty m_LeftLowerLeg;
+ SerializedProperty m_RightLowerLeg;
+ SerializedProperty m_LeftFoot;
+ SerializedProperty m_RightFoot;
+ SerializedProperty m_LeftToes;
+ SerializedProperty m_RightToes;
+
+ #endregion
+
+ #region spine
+ SerializedProperty m_Spine;
+ SerializedProperty m_Chest;
+ SerializedProperty m_UpperChest;
+ SerializedProperty m_Neck;
+ SerializedProperty m_Head;
+ SerializedProperty m_LeftEye;
+ SerializedProperty m_RightEye;
+ SerializedProperty m_Jaw;
+
+ #endregion
+
+ #region arm
+ SerializedProperty m_LeftShoulder;
+ SerializedProperty m_RightShoulder;
+ SerializedProperty m_LeftUpperArm;
+ SerializedProperty m_RightUpperArm;
+ SerializedProperty m_LeftLowerArm;
+ SerializedProperty m_RightLowerArm;
+ SerializedProperty m_LeftHand;
+ SerializedProperty m_RightHand;
+
+ #endregion
+
+ #region fingers
+ SerializedProperty m_LeftThumbProximal;
+ SerializedProperty m_LeftThumbIntermediate;
+ SerializedProperty m_LeftThumbDistal;
+ SerializedProperty m_LeftIndexProximal;
+ SerializedProperty m_LeftIndexIntermediate;
+ SerializedProperty m_LeftIndexDistal;
+ SerializedProperty m_LeftMiddleProximal;
+ SerializedProperty m_LeftMiddleIntermediate;
+ SerializedProperty m_LeftMiddleDistal;
+ SerializedProperty m_LeftRingProximal;
+ SerializedProperty m_LeftRingIntermediate;
+ SerializedProperty m_LeftRingDistal;
+ SerializedProperty m_LeftLittleProximal;
+ SerializedProperty m_LeftLittleIntermediate;
+ SerializedProperty m_LeftLittleDistal;
+ SerializedProperty m_RightThumbProximal;
+ SerializedProperty m_RightThumbIntermediate;
+ SerializedProperty m_RightThumbDistal;
+ SerializedProperty m_RightIndexProximal;
+ SerializedProperty m_RightIndexIntermediate;
+ SerializedProperty m_RightIndexDistal;
+ SerializedProperty m_RightMiddleProximal;
+ SerializedProperty m_RightMiddleIntermediate;
+ SerializedProperty m_RightMiddleDistal;
+ SerializedProperty m_RightRingProximal;
+ SerializedProperty m_RightRingIntermediate;
+ SerializedProperty m_RightRingDistal;
+ SerializedProperty m_RightLittleProximal;
+ SerializedProperty m_RightLittleIntermediate;
+ SerializedProperty m_RightLittleDistal;
+
+ #endregion
+
+ void OnEnable()
+ {
+ m_target = target as Humanoid;
+ m_Hips = serializedObject.FindProperty($"m_{nameof(Humanoid.Hips)}");
+
+ #region legs
+ m_LeftUpperLeg = serializedObject.FindProperty($"m_{nameof(Humanoid.LeftUpperLeg)}");
+ m_RightUpperLeg = serializedObject.FindProperty($"m_{nameof(Humanoid.RightUpperLeg)}");
+ m_LeftLowerLeg = serializedObject.FindProperty($"m_{nameof(Humanoid.LeftLowerLeg)}");
+ m_RightLowerLeg = serializedObject.FindProperty($"m_{nameof(Humanoid.RightLowerLeg)}");
+ m_LeftFoot = serializedObject.FindProperty($"m_{nameof(Humanoid.LeftFoot)}");
+ m_RightFoot = serializedObject.FindProperty($"m_{nameof(Humanoid.RightFoot)}");
+ m_LeftToes = serializedObject.FindProperty($"m_{nameof(Humanoid.LeftToes)}");
+ m_RightToes = serializedObject.FindProperty($"m_{nameof(Humanoid.RightToes)}");
+ #endregion
+
+ #region spine
+ m_Spine = serializedObject.FindProperty($"m_{nameof(Humanoid.Spine)}");
+ m_Chest = serializedObject.FindProperty($"m_{nameof(Humanoid.Chest)}");
+ m_UpperChest = serializedObject.FindProperty($"m_{nameof(Humanoid.UpperChest)}");
+ m_Neck = serializedObject.FindProperty($"m_{nameof(Humanoid.Neck)}");
+ m_Head = serializedObject.FindProperty($"m_{nameof(Humanoid.Head)}");
+ m_LeftEye = serializedObject.FindProperty($"m_{nameof(Humanoid.LeftEye)}");
+ m_RightEye = serializedObject.FindProperty($"m_{nameof(Humanoid.RightEye)}");
+ m_Jaw = serializedObject.FindProperty($"m_{nameof(Humanoid.Jaw)}");
+
+ #endregion
+
+ #region arm
+ m_LeftShoulder = serializedObject.FindProperty($"m_{nameof(Humanoid.LeftShoulder)}");
+ m_RightShoulder = serializedObject.FindProperty($"m_{nameof(Humanoid.RightShoulder)}");
+ m_LeftUpperArm = serializedObject.FindProperty($"m_{nameof(Humanoid.LeftUpperArm)}");
+ m_RightUpperArm = serializedObject.FindProperty($"m_{nameof(Humanoid.RightUpperArm)}");
+ m_LeftLowerArm = serializedObject.FindProperty($"m_{nameof(Humanoid.LeftLowerArm)}");
+ m_RightLowerArm = serializedObject.FindProperty($"m_{nameof(Humanoid.RightLowerArm)}");
+ m_LeftHand = serializedObject.FindProperty($"m_{nameof(Humanoid.LeftHand)}");
+ m_RightHand = serializedObject.FindProperty($"m_{nameof(Humanoid.RightHand)}");
+
+ #endregion
+
+ #region fingers
+ m_LeftThumbProximal = serializedObject.FindProperty($"m_{nameof(Humanoid.LeftThumbProximal)}");
+ m_LeftThumbIntermediate = serializedObject.FindProperty($"m_{nameof(Humanoid.LeftThumbIntermediate)}");
+ m_LeftThumbDistal = serializedObject.FindProperty($"m_{nameof(Humanoid.LeftThumbDistal)}");
+ m_LeftIndexProximal = serializedObject.FindProperty($"m_{nameof(Humanoid.LeftIndexProximal)}");
+ m_LeftIndexIntermediate = serializedObject.FindProperty($"m_{nameof(Humanoid.LeftIndexIntermediate)}");
+ m_LeftIndexDistal = serializedObject.FindProperty($"m_{nameof(Humanoid.LeftIndexDistal)}");
+ m_LeftMiddleProximal = serializedObject.FindProperty($"m_{nameof(Humanoid.LeftMiddleProximal)}");
+ m_LeftMiddleIntermediate = serializedObject.FindProperty($"m_{nameof(Humanoid.LeftMiddleIntermediate)}");
+ m_LeftMiddleDistal = serializedObject.FindProperty($"m_{nameof(Humanoid.LeftMiddleDistal)}");
+ m_LeftRingProximal = serializedObject.FindProperty($"m_{nameof(Humanoid.LeftRingProximal)}");
+ m_LeftRingIntermediate = serializedObject.FindProperty($"m_{nameof(Humanoid.LeftRingIntermediate)}");
+ m_LeftRingDistal = serializedObject.FindProperty($"m_{nameof(Humanoid.LeftRingDistal)}");
+ m_LeftLittleProximal = serializedObject.FindProperty($"m_{nameof(Humanoid.LeftLittleProximal)}");
+ m_LeftLittleIntermediate = serializedObject.FindProperty($"m_{nameof(Humanoid.LeftLittleIntermediate)}");
+ m_LeftLittleDistal = serializedObject.FindProperty($"m_{nameof(Humanoid.LeftLittleDistal)}");
+ m_RightThumbProximal = serializedObject.FindProperty($"m_{nameof(Humanoid.RightThumbProximal)}");
+ m_RightThumbIntermediate = serializedObject.FindProperty($"m_{nameof(Humanoid.RightThumbIntermediate)}");
+ m_RightThumbDistal = serializedObject.FindProperty($"m_{nameof(Humanoid.RightThumbDistal)}");
+ m_RightIndexProximal = serializedObject.FindProperty($"m_{nameof(Humanoid.RightIndexProximal)}");
+ m_RightIndexIntermediate = serializedObject.FindProperty($"m_{nameof(Humanoid.RightIndexIntermediate)}");
+ m_RightIndexDistal = serializedObject.FindProperty($"m_{nameof(Humanoid.RightIndexDistal)}");
+ m_RightMiddleProximal = serializedObject.FindProperty($"m_{nameof(Humanoid.RightMiddleProximal)}");
+ m_RightMiddleIntermediate = serializedObject.FindProperty($"m_{nameof(Humanoid.RightMiddleIntermediate)}");
+ m_RightMiddleDistal = serializedObject.FindProperty($"m_{nameof(Humanoid.RightMiddleDistal)}");
+ m_RightRingProximal = serializedObject.FindProperty($"m_{nameof(Humanoid.RightRingProximal)}");
+ m_RightRingIntermediate = serializedObject.FindProperty($"m_{nameof(Humanoid.RightRingIntermediate)}");
+ m_RightRingDistal = serializedObject.FindProperty($"m_{nameof(Humanoid.RightRingDistal)}");
+ m_RightLittleProximal = serializedObject.FindProperty($"m_{nameof(Humanoid.RightLittleProximal)}");
+ m_RightLittleIntermediate = serializedObject.FindProperty($"m_{nameof(Humanoid.RightLittleIntermediate)}");
+ m_RightLittleDistal = serializedObject.FindProperty($"m_{nameof(Humanoid.RightLittleDistal)}");
+ #endregion
+ }
+
+ struct Horizontal : IDisposable
+ {
+ public static Horizontal Using()
+ {
+ EditorGUILayout.BeginHorizontal();
+ return default;
+ }
+ public void Dispose()
+ {
+ EditorGUILayout.EndHorizontal();
+ }
+ }
+
+ static void HorizontalFields(string label, params SerializedProperty[] props)
+ {
+ try
+ {
+ EditorGUILayout.BeginHorizontal();
+
+ GUILayout.Label(label, GUILayout.Width(LABEL_WIDTH));
+ GUILayout.FlexibleSpace();
+
+ foreach (var prop in props)
+ {
+ EditorGUILayout.PropertyField(prop, GUIContent.none, true, GUILayout.MinWidth(100));
+ }
+ }
+ finally
+ {
+ EditorGUILayout.EndHorizontal();
+ }
+ }
+
+ static bool s_spineFold;
+ static bool s_legFold;
+ static bool s_armFold;
+ static bool s_fingerFold;
+ static string GetDialogDir(UnityEngine.Object obj)
+ {
+ var prefab = PrefabUtility.GetCorrespondingObjectFromSource(obj);
+ if (prefab == null)
+ {
+ return null;
+ }
+ return UnityPath.FromAsset(prefab).FullPath;
+ }
+
+ public override void OnInspectorGUI()
+ {
+ foreach (var validation in m_target.Validate())
+ {
+ EditorGUILayout.HelpBox(validation.Message, validation.IsError ? MessageType.Error : MessageType.Warning);
+ }
+
+ // prefer
+ serializedObject.Update();
+
+ EditorGUILayout.PropertyField(m_Hips);
+
+ s_spineFold = EditorGUILayout.Foldout(s_spineFold, "Body");
+ if (s_spineFold)
+ {
+ EditorGUILayout.PropertyField(m_Spine);
+ EditorGUILayout.PropertyField(m_Chest);
+ EditorGUILayout.PropertyField(m_UpperChest);
+ EditorGUILayout.PropertyField(m_Neck);
+ EditorGUILayout.PropertyField(m_Head);
+ EditorGUILayout.PropertyField(m_Jaw);
+ HorizontalFields("Eye", m_LeftEye, m_RightEye);
+ }
+
+ s_legFold = EditorGUILayout.Foldout(s_legFold, "Leg");
+ if (s_legFold)
+ {
+ HorizontalFields("UpperLeg", m_LeftUpperLeg, m_RightUpperLeg);
+ HorizontalFields("LowerLeg", m_LeftLowerLeg, m_RightLowerLeg);
+ HorizontalFields("Foot", m_LeftFoot, m_RightFoot);
+ HorizontalFields("Toes", m_LeftToes, m_RightToes);
+ }
+
+ s_armFold = EditorGUILayout.Foldout(s_armFold, "Arm");
+ if (s_armFold)
+ {
+ HorizontalFields("Shoulder", m_LeftShoulder, m_RightShoulder);
+ HorizontalFields("UpperArm", m_LeftUpperArm, m_RightUpperArm);
+ HorizontalFields("LowerArm", m_LeftLowerArm, m_RightLowerArm);
+ HorizontalFields("Hand", m_LeftHand, m_RightHand);
+ }
+
+ s_fingerFold = EditorGUILayout.Foldout(s_fingerFold, "Finger");
+ if (s_fingerFold)
+ {
+ HorizontalFields("LeftThumb", m_LeftThumbProximal, m_LeftThumbIntermediate, m_LeftThumbDistal);
+ HorizontalFields("LeftIndex", m_LeftIndexProximal, m_LeftIndexIntermediate, m_LeftIndexDistal);
+ HorizontalFields("LeftMiddle", m_LeftMiddleProximal, m_LeftMiddleIntermediate, m_LeftMiddleDistal);
+ HorizontalFields("LeftRing", m_LeftRingProximal, m_LeftRingIntermediate, m_LeftRingDistal);
+ HorizontalFields("LeftLittle", m_LeftLittleProximal, m_LeftLittleIntermediate, m_LeftLittleDistal);
+ HorizontalFields("RightThumb", m_RightThumbProximal, m_RightThumbIntermediate, m_RightThumbDistal);
+ HorizontalFields("RightIndex", m_RightIndexProximal, m_RightIndexIntermediate, m_RightIndexDistal);
+ HorizontalFields("RightMiddle", m_RightMiddleProximal, m_RightMiddleIntermediate, m_RightMiddleDistal);
+ HorizontalFields("RightRing", m_RightRingProximal, m_RightRingIntermediate, m_RightRingDistal);
+ HorizontalFields("RightLittle", m_RightLittleProximal, m_RightLittleIntermediate, m_RightLittleDistal);
+ }
+
+ serializedObject.ApplyModifiedProperties();
+
+ // create avatar
+ if (GUILayout.Button("Create UnityEngine.Avatar"))
+ {
+ var path = EditorUtility.SaveFilePanel(
+ "Save avatar",
+ GetDialogDir(m_target),
+ string.Format("{0}.avatar.asset", serializedObject.targetObject.name),
+ "asset");
+ if (!string.IsNullOrEmpty(path))
+ {
+ var avatar = m_target.CreateAvatar();
+ if (avatar != null)
+ {
+ var unityPath = UnityPath.FromFullpath(path);
+ avatar.name = "avatar";
+ Debug.LogFormat("Create avatar {0}", unityPath);
+ AssetDatabase.CreateAsset(avatar, unityPath.Value);
+ AssetDatabase.ImportAsset(unityPath.Value);
+
+ // replace
+ var animator = m_target.GetComponent<Animator>();
+ if (animator == null)
+ {
+ animator = m_target.gameObject.AddComponent<Animator>();
+ }
+ animator.avatar = avatar;
+
+ Selection.activeObject = avatar;
+ }
+ }
+ }
+ }
+
+ void OnSceneGUI()
+ {
+ // var bones = m_target.Bones;
+ // if (bones != null)
+ // {
+ // for (int i = 0; i < bones.Length; ++i)
+ // {
+ // DrawBone((HumanBodyBones)i, bones[i]);
+ // }
+ // foreach (var x in m_bones)
+ // {
+ // x.Draw();
+ // }
+ // }
+
+ var forward = m_target.GetForward();
+
+ var begin = m_target.transform.position;
+ var end = begin + forward;
+ Handles.DrawLine(begin, end);
+ }
+ }
+}
diff --git a/Assets/ThirdParty/VRM/MeshUtility/Editor/HumanoidEditor.cs.meta b/Assets/ThirdParty/VRM/MeshUtility/Editor/HumanoidEditor.cs.meta
new file mode 100644
index 00000000..dffaaa18
--- /dev/null
+++ b/Assets/ThirdParty/VRM/MeshUtility/Editor/HumanoidEditor.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 57cc7b16eb4146c4ab5631f538e2489f
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/ThirdParty/VRM/MeshUtility/Editor/MeshUtility.Editor.asmdef b/Assets/ThirdParty/VRM/MeshUtility/Editor/MeshUtility.Editor.asmdef
new file mode 100644
index 00000000..9854cd8f
--- /dev/null
+++ b/Assets/ThirdParty/VRM/MeshUtility/Editor/MeshUtility.Editor.asmdef
@@ -0,0 +1,16 @@
+{
+ "name": "MeshUtility.Editor",
+ "references": [
+ "MeshUtility"
+ ],
+ "optionalUnityReferences": [],
+ "includePlatforms": [
+ "Editor"
+ ],
+ "excludePlatforms": [],
+ "allowUnsafeCode": false,
+ "overrideReferences": false,
+ "precompiledReferences": [],
+ "autoReferenced": true,
+ "defineConstraints": []
+} \ No newline at end of file
diff --git a/Assets/ThirdParty/VRM/MeshUtility/Editor/MeshUtility.Editor.asmdef.meta b/Assets/ThirdParty/VRM/MeshUtility/Editor/MeshUtility.Editor.asmdef.meta
new file mode 100644
index 00000000..ad84160c
--- /dev/null
+++ b/Assets/ThirdParty/VRM/MeshUtility/Editor/MeshUtility.Editor.asmdef.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: eedb868807606df4db953419ab9e0780
+AssemblyDefinitionImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/ThirdParty/VRM/MeshUtility/Editor/MeshUtility.cs b/Assets/ThirdParty/VRM/MeshUtility/Editor/MeshUtility.cs
new file mode 100644
index 00000000..045879c6
--- /dev/null
+++ b/Assets/ThirdParty/VRM/MeshUtility/Editor/MeshUtility.cs
@@ -0,0 +1,286 @@
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using UnityEngine;
+using UnityEditor;
+
+namespace MeshUtility
+{
+ public class MeshUtility
+ {
+ public const string MENU_PARENT = "Mesh Utility/";
+ public const int MENU_PRIORITY = 11;
+
+ private const string ASSET_SUFFIX = ".mesh.asset";
+ private const string MENU_NAME = MENU_PARENT + "MeshSeparator";
+ private static readonly Vector3 ZERO_MOVEMENT = Vector3.zero;
+
+ public static Object GetPrefab(GameObject instance)
+ {
+#if UNITY_2018_2_OR_NEWER
+ return PrefabUtility.GetCorrespondingObjectFromSource(instance);
+#else
+ return PrefabUtility.GetPrefabParent(go);
+#endif
+ }
+
+ private enum BlendShapeLogic
+ {
+ WithBlendShape,
+ WithoutBlendShape,
+ }
+
+ [MenuItem(MENU_NAME, validate = true)]
+ private static bool ShowLogValidation()
+ {
+ if (Selection.activeTransform == null)
+ return false;
+ else
+ return true;
+ }
+
+ [MenuItem(MENU_NAME, priority = 2)]
+ public static void SeparateSkinnedMeshContainedBlendShape()
+ {
+ var go = Selection.activeTransform.gameObject;
+
+ if (go.GetComponentsInChildren<SkinnedMeshRenderer>().Length > 0)
+ {
+ SeparationProcessing(go);
+ go.SetActive(false);
+ }
+ else
+ {
+ EditorUtility.DisplayDialog("Error", "No skinnedMeshRenderer contained", "ok");
+ }
+ }
+
+ [MenuItem("Mesh Utility/MeshSeparator Docs", priority = MeshUtility.MENU_PRIORITY)]
+ public static void LinkToMeshSeparatorDocs()
+ {
+ Application.OpenURL("https://github.com/vrm-c/UniVRM/tree/master/Assets/MeshUtility");
+ }
+
+ private static void SeparationProcessing(GameObject go)
+ {
+ var outputObject = GameObject.Instantiate(go);
+ var skinnedMeshRenderers = outputObject.GetComponentsInChildren<SkinnedMeshRenderer>();
+ foreach (var skinnedMeshRenderer in skinnedMeshRenderers)
+ {
+ if (skinnedMeshRenderer.sharedMesh.blendShapeCount > 0)
+ {
+ SeparatePolyWithBlendShape(skinnedMeshRenderer);
+ }
+ }
+ }
+
+ private static void SeparatePolyWithBlendShape(SkinnedMeshRenderer skinnedMeshRendererInput)
+ {
+ var indicesUsedByBlendShape = new Dictionary<int, int>();
+ var mesh = skinnedMeshRendererInput.sharedMesh;
+
+ // retrieve the original BlendShape data
+ for (int i = 0; i < mesh.blendShapeCount; ++i)
+ {
+ var deltaVertices = new Vector3[mesh.vertexCount];
+ var deltaNormals = new Vector3[mesh.vertexCount];
+ var deltaTangents = new Vector3[mesh.vertexCount];
+ mesh.GetBlendShapeFrameVertices(i, 0, deltaVertices, deltaNormals, deltaTangents);
+
+ for (int j = 0; j < deltaVertices.Length; j++)
+ {
+ if (!deltaVertices[j].Equals(ZERO_MOVEMENT))
+ {
+ if (!indicesUsedByBlendShape.Values.Contains(j))
+ {
+ indicesUsedByBlendShape.Add(indicesUsedByBlendShape.Count, j);
+ }
+ }
+ }
+ }
+
+ var subMeshCount = mesh.subMeshCount;
+ var submeshesWithBlendShape = new Dictionary<int, int[]>();
+ var submeshesWithoutBlendShape = new Dictionary<int, int[]>();
+ var vertexIndexWithBlendShape = new Dictionary<int, int>();
+ var vertexCounterWithBlendShape = 0;
+ var vertexIndexWithoutBlendShape = new Dictionary<int, int>();
+ var vertexCounterWithoutBlendShape = 0;
+
+ // check blendshape's vertex index from submesh
+ for (int i = 0; i < subMeshCount; i++)
+ {
+ var triangle = mesh.GetTriangles(i);
+ var submeshWithBlendShape = new List<int>();
+ var submeshWithoutBlendShape = new List<int>();
+
+ for (int j = 0; j < triangle.Length; j += 3)
+ {
+ if (indicesUsedByBlendShape.Values.Contains(triangle[j]) ||
+ indicesUsedByBlendShape.Values.Contains(triangle[j + 1]) ||
+ indicesUsedByBlendShape.Values.Contains(triangle[j + 2]))
+ {
+ BuildNewTriangleList(vertexIndexWithBlendShape, triangle, j, submeshWithBlendShape, ref vertexCounterWithBlendShape);
+ }
+ else
+ {
+ BuildNewTriangleList(vertexIndexWithoutBlendShape, triangle, j, submeshWithoutBlendShape, ref vertexCounterWithoutBlendShape);
+ }
+ }
+ if (submeshWithBlendShape.Count > 0)
+ submeshesWithBlendShape.Add(i, submeshWithBlendShape.ToArray());
+ if (submeshWithoutBlendShape.Count > 0)
+ submeshesWithoutBlendShape.Add(i, submeshWithoutBlendShape.ToArray()); ;
+ }
+
+ // check if any BlendShape exists
+ if (submeshesWithoutBlendShape.Count > 0)
+ {
+ // put the mesh without BlendShape in a new SkinnedMeshRenderer
+ var srcGameObject = skinnedMeshRendererInput.gameObject;
+ var srcTransform = skinnedMeshRendererInput.transform.parent;
+ var targetObjectForMeshWithoutBS = GameObject.Instantiate(srcGameObject);
+ targetObjectForMeshWithoutBS.name = srcGameObject.name + "_WithoutBlendShape";
+ targetObjectForMeshWithoutBS.transform.SetParent(srcTransform);
+ var skinnedMeshRendererWithoutBS = targetObjectForMeshWithoutBS.GetComponent<SkinnedMeshRenderer>();
+
+ // build meshes with/without BlendShape
+ BuildNewMesh(skinnedMeshRendererInput, vertexIndexWithBlendShape, submeshesWithBlendShape, BlendShapeLogic.WithBlendShape);
+ BuildNewMesh(skinnedMeshRendererWithoutBS, vertexIndexWithoutBlendShape, submeshesWithoutBlendShape, BlendShapeLogic.WithoutBlendShape);
+ }
+ }
+
+ private static void BuildNewTriangleList(Dictionary<int, int> newVerticesListLookUp, int[] triangleList, int index,
+ List<int> newTriangleList, ref int vertexCounter)
+ {
+ // build new vertex list and triangle list
+ // vertex 1
+ if (!newVerticesListLookUp.Keys.Contains(triangleList[index]))
+ {
+ newVerticesListLookUp.Add(triangleList[index], vertexCounter);
+ newTriangleList.Add(vertexCounter);
+ vertexCounter++;
+ }
+ else
+ {
+ var newVertexIndex = newVerticesListLookUp[triangleList[index]];
+ newTriangleList.Add(newVertexIndex);
+ }
+ // vertex 2
+ if (!newVerticesListLookUp.Keys.Contains(triangleList[index + 1]))
+ {
+ newVerticesListLookUp.Add(triangleList[index + 1], vertexCounter);
+ newTriangleList.Add(vertexCounter);
+ vertexCounter++;
+ }
+ else
+ {
+ var newVertexIndex = newVerticesListLookUp[triangleList[index + 1]];
+ newTriangleList.Add(newVertexIndex);
+ }
+ // vertex 3
+ if (!newVerticesListLookUp.Keys.Contains(triangleList[index + 2]))
+ {
+ newVerticesListLookUp.Add(triangleList[index + 2], vertexCounter);
+ newTriangleList.Add(vertexCounter);
+ vertexCounter++;
+ }
+ else
+ {
+ var newVertexIndex = newVerticesListLookUp[triangleList[index + 2]];
+ newTriangleList.Add(newVertexIndex);
+ }
+ }
+
+ private static void BuildNewMesh(SkinnedMeshRenderer skinnedMeshRenderer, Dictionary<int, int> newIndexLookUpDict,
+ Dictionary<int, int[]> subMeshes, BlendShapeLogic blendShapeLabel)
+ {
+ // get original mesh data
+ var materialList = new List<Material>();
+ skinnedMeshRenderer.GetSharedMaterials(materialList);
+ var mesh = skinnedMeshRenderer.sharedMesh;
+ var meshVertices = mesh.vertices;
+ var meshNormals = mesh.normals;
+ var meshTangents = mesh.tangents;
+ var meshColors = mesh.colors;
+ var meshBoneWeights = mesh.boneWeights;
+ var meshUVs = mesh.uv;
+
+ // build new mesh
+ var materialListNew = new List<Material>();
+ var newMesh = new Mesh();
+
+ if (mesh.vertexCount > ushort.MaxValue)
+ {
+#if UNITY_2017_3_OR_NEWER
+ Debug.LogFormat("exceed 65535 vertices: {0}", mesh.vertexCount);
+ newMesh.indexFormat = UnityEngine.Rendering.IndexFormat.UInt32;
+#else
+ throw new NotImplementedException(String.Format("exceed 65535 vertices: {0}", integrator.Positions.Count.ToString()));
+#endif
+ }
+
+ var newDataLength = newIndexLookUpDict.Count;
+ var newIndexLookUp = newIndexLookUpDict.Keys.ToArray();
+
+ newMesh.vertices = newIndexLookUp.Select(x => meshVertices[x]).ToArray();
+ if (meshNormals.Length > 0) newMesh.normals = newIndexLookUp.Select(x => meshNormals[x]).ToArray();
+ if (meshTangents.Length > 0) newMesh.tangents = newIndexLookUp.Select(x => meshTangents[x]).ToArray();
+ if (meshColors.Length > 0) newMesh.colors = newIndexLookUp.Select(x => meshColors[x]).ToArray();
+ if (meshBoneWeights.Length > 0) newMesh.boneWeights = newIndexLookUp.Select(x => meshBoneWeights[x]).ToArray();
+ if (meshUVs.Length > 0) newMesh.uv = newIndexLookUp.Select(x => meshUVs[x]).ToArray();
+ newMesh.bindposes = mesh.bindposes;
+
+ // add BlendShape data
+ if (blendShapeLabel == BlendShapeLogic.WithBlendShape)
+ {
+ for (int i = 0; i < mesh.blendShapeCount; i++)
+ {
+ // get original BlendShape data
+ var srcVertices = new Vector3[mesh.vertexCount];
+ var srcNormals = new Vector3[mesh.vertexCount];
+ var srcTangents = new Vector3[mesh.vertexCount];
+ mesh.GetBlendShapeFrameVertices(i, 0, srcVertices, srcNormals, srcTangents);
+
+ // declare the size for the destination array
+ var dstVertices = new Vector3[newDataLength];
+ var dstNormals = new Vector3[newDataLength];
+ var dstTangents = new Vector3[newDataLength];
+
+ dstVertices = newIndexLookUp.Select(x => srcVertices[x]).ToArray();
+ dstNormals = newIndexLookUp.Select(x => srcNormals[x]).ToArray();
+ dstTangents = newIndexLookUp.Select(x => srcTangents[x]).ToArray();
+ newMesh.AddBlendShapeFrame(mesh.GetBlendShapeName(i), mesh.GetBlendShapeFrameWeight(i, 0),
+ dstVertices, dstNormals, dstTangents);
+ }
+ }
+
+ newMesh.subMeshCount = subMeshes.Count;
+ var cosMaterialIndex = subMeshes.Keys.ToArray();
+
+ // build material list
+ for (int i = 0; i < subMeshes.Count; i++)
+ {
+ newMesh.SetTriangles(subMeshes[cosMaterialIndex[i]], i);
+ materialListNew.Add(materialList[cosMaterialIndex[i]]);
+ }
+ skinnedMeshRenderer.sharedMaterials = materialListNew.ToArray();
+ skinnedMeshRenderer.sharedMesh = newMesh;
+
+ // save mesh as asset
+ var assetPath = string.Format("{0}{1}", Path.GetFileNameWithoutExtension(mesh.name), ASSET_SUFFIX);
+ Debug.Log(assetPath);
+ if (!string.IsNullOrEmpty((AssetDatabase.GetAssetPath(mesh))))
+ {
+ var directory = Path.GetDirectoryName(AssetDatabase.GetAssetPath(mesh)).Replace("\\", "/");
+ assetPath = string.Format("{0}/{1}{2}", directory, Path.GetFileNameWithoutExtension(mesh.name) + "_" + blendShapeLabel.ToString(), ASSET_SUFFIX);
+ }
+ else
+ {
+ assetPath = string.Format("Assets/{0}{1}", Path.GetFileNameWithoutExtension(mesh.name) + "_" + blendShapeLabel.ToString(), ASSET_SUFFIX);
+ }
+ Debug.LogFormat("CreateAsset: {0}", assetPath);
+ AssetDatabase.CreateAsset(newMesh, assetPath);
+ }
+ }
+} \ No newline at end of file
diff --git a/Assets/ThirdParty/VRM/MeshUtility/Editor/MeshUtility.cs.meta b/Assets/ThirdParty/VRM/MeshUtility/Editor/MeshUtility.cs.meta
new file mode 100644
index 00000000..2fb0aadd
--- /dev/null
+++ b/Assets/ThirdParty/VRM/MeshUtility/Editor/MeshUtility.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: c1bbe850b95e44740bbbb44064e17d25
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/ThirdParty/VRM/MeshUtility/LICENSE.md b/Assets/ThirdParty/VRM/MeshUtility/LICENSE.md
new file mode 100644
index 00000000..7a9585e4
--- /dev/null
+++ b/Assets/ThirdParty/VRM/MeshUtility/LICENSE.md
@@ -0,0 +1,9 @@
+MIT License
+
+Copyright (c) 2020 VRM Consortium
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice (including the next paragraph) shall be included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file
diff --git a/Assets/ThirdParty/VRM/MeshUtility/LICENSE.md.meta b/Assets/ThirdParty/VRM/MeshUtility/LICENSE.md.meta
new file mode 100644
index 00000000..6462af9e
--- /dev/null
+++ b/Assets/ThirdParty/VRM/MeshUtility/LICENSE.md.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: 5759a25d3024bd94a92b0af38bac243c
+TextScriptImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/ThirdParty/VRM/MeshUtility/README.md b/Assets/ThirdParty/VRM/MeshUtility/README.md
new file mode 100644
index 00000000..c96f8f90
--- /dev/null
+++ b/Assets/ThirdParty/VRM/MeshUtility/README.md
@@ -0,0 +1,58 @@
+# MeshUtility
+
+Mesh processing tool in Unity platform.
+
+## Utilities
+
+### MeshSeparator
+
+Separate the target mesh into different categories based on given conditions.
+
+Currently support BlendShape mesh separation. See [documentation](Documentation/notes/MeshSeparator.md) for more details.
+
+<img src="Documentation/images/blendshape_separator.jpg" width="300">
+
+### MeshIntegrator
+
+Integrate all the meshes of a Prefab (Project window).
+
+### Integrate Static Mesh
+
+Integrate all the static meshes in the Hierarchy (Root and its children).
+
+### MeshNormalizer
+
+Bake the Hierarchy. This is VRM normalize backend.
+MeshNormalizer can do blendShape bake.
+
+## Import MeshUtility
+
+There are two ways to import MeshUtility into a Unity project.
+
+### 1. Unity Package Manager (from Unity 2019)
+
+You can add MeshUtility package via `UPM`. First click `Window` from menu on top, then select `Package Manager`.
+
+<img src="Documentation/images/installation_1.jpg" width="200">
+
+In `Package Manager`, click `Add package from git URL` and paste `https://github.com/vrm-c/UniVRM.git?path=/Assets/MeshUtility`.
+
+<img src="Documentation/images/installation_2.jpg" width="200">
+
+Now check your project window. You shall see MeshUtility in the `Packages` folder.
+
+### 2. Add package name and its url in manifest.json
+
+Another way of importing MeshUtility is manually adding necessary information in manifest.json, which is in the directory of `Package folder` in your Unity project. Open manifest.json with text editor and add the followings in `dependencies`:
+
+```json
+{
+ "dependencies": {
+ "com.vrmc.meshutility": "https://github.com/vrm-c/UniVRM.git?path=/Assets/MeshUtility",
+ }
+}
+```
+
+Go back to the Unity project. The system will automatically load the package.
+
+<img src="Documentation/images/installation_3.jpg" width="200"> \ No newline at end of file
diff --git a/Assets/ThirdParty/VRM/MeshUtility/README.md.meta b/Assets/ThirdParty/VRM/MeshUtility/README.md.meta
new file mode 100644
index 00000000..b5c1eb77
--- /dev/null
+++ b/Assets/ThirdParty/VRM/MeshUtility/README.md.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: febba2ec3ea2c9247ab21226ce81f924
+TextScriptImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/ThirdParty/VRM/MeshUtility/README.url b/Assets/ThirdParty/VRM/MeshUtility/README.url
new file mode 100644
index 00000000..79542bae
--- /dev/null
+++ b/Assets/ThirdParty/VRM/MeshUtility/README.url
@@ -0,0 +1,2 @@
+[InternetShortcut]
+URL=https://github.com/vrm-c/UniVRM/tree/master/Assets/MeshUtility \ No newline at end of file
diff --git a/Assets/ThirdParty/VRM/MeshUtility/README.url.meta b/Assets/ThirdParty/VRM/MeshUtility/README.url.meta
new file mode 100644
index 00000000..6ee109b6
--- /dev/null
+++ b/Assets/ThirdParty/VRM/MeshUtility/README.url.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: 42e2fc8311d7ef44fa3975996ba1645d
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/ThirdParty/VRM/MeshUtility/Runtime.meta b/Assets/ThirdParty/VRM/MeshUtility/Runtime.meta
new file mode 100644
index 00000000..3b08e959
--- /dev/null
+++ b/Assets/ThirdParty/VRM/MeshUtility/Runtime.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: fc6ddf08077eac64fb9e33738e1c314d
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/ThirdParty/VRM/MeshUtility/Runtime/BindposeGizmo.cs b/Assets/ThirdParty/VRM/MeshUtility/Runtime/BindposeGizmo.cs
new file mode 100644
index 00000000..23e233e5
--- /dev/null
+++ b/Assets/ThirdParty/VRM/MeshUtility/Runtime/BindposeGizmo.cs
@@ -0,0 +1,158 @@
+using System.Collections.Generic;
+using System.Linq;
+using UnityEngine;
+// using UniGLTF;
+#if UNITY_EDITOR
+using UnityEditor;
+#endif
+
+
+namespace MeshUtility
+{
+ [DisallowMultipleComponent]
+ public class BindposeGizmo : MonoBehaviour
+ {
+ [SerializeField]
+ Mesh m_target;
+
+ [SerializeField]
+ float[] m_boneWeights;
+
+ [SerializeField, Range(0.1f, 1.0f)]
+ float m_gizmoSize = 0.02f;
+
+ [SerializeField]
+ Color m_meshGizmoColor = Color.yellow;
+
+ [SerializeField]
+ Color m_bindGizmoColor = Color.red;
+
+ private void Reset()
+ {
+ var renderer = GetComponent<SkinnedMeshRenderer>();
+ if (renderer == null) return;
+ m_target = renderer.sharedMesh;
+ }
+
+#if UNITY_EDITOR
+ #region ToBindpose
+ [ContextMenu("ToBindpose")]
+ void ToBindpose()
+ {
+ var renderer = GetComponent<SkinnedMeshRenderer>();
+
+ var root =
+ renderer.bones
+ .Select(x => Ancestors(x).Reverse().ToArray())
+ .Aggregate((a, b) =>
+ {
+ int i = 0;
+ for (; i < a.Length && i < b.Length; ++i)
+ {
+ if (a[i] != b[i])
+ {
+ break;
+ }
+ }
+ return a.Take(i).ToArray();
+ })
+ .Last()
+ ;
+
+ var map = new Dictionary<Transform, Matrix4x4>();
+ for (int i = 0; i < renderer.bones.Length; ++i)
+ {
+ map[renderer.bones[i]] = m_target.bindposes[i];
+ }
+
+ {
+ var bones = Traverse(root);
+ Undo.RecordObjects(bones.ToArray(), "toBindpose");
+
+ foreach (var x in bones)
+ {
+ var bind = default(Matrix4x4);
+ if (map.TryGetValue(x, out bind))
+ {
+ var toWorld = renderer.transform.localToWorldMatrix * bind.inverse;
+ x.position = toWorld.GetColumn(3);
+ x.rotation = toWorld.ExtractRotation();
+ }
+ }
+
+ //EditorUtility.SetDirty(transform);
+ }
+ }
+
+ IEnumerable<Transform> Traverse(Transform self)
+ {
+ yield return self;
+
+ foreach (Transform child in self)
+ {
+ foreach (var x in Traverse(child))
+ {
+ yield return x;
+ }
+ }
+ }
+
+ IEnumerable<Transform> Ancestors(Transform self)
+ {
+ yield return self;
+
+ if (self.parent != null)
+ {
+ foreach (var x in Ancestors(self.parent))
+ {
+ yield return x;
+ }
+ }
+ }
+ #endregion
+#endif
+
+ private void OnDrawGizmos()
+ {
+ if (m_target == null)
+ {
+ return;
+ }
+
+ Gizmos.matrix = transform.localToWorldMatrix;
+
+ if (m_target.bindposes != null && m_target.bindposes.Length > 0)
+ {
+ if (m_boneWeights == null || m_boneWeights.Length != m_target.bindposes.Length)
+ {
+ m_boneWeights = new float[m_target.bindposes.Length];
+ foreach (var bw in m_target.boneWeights)
+ {
+ if (bw.weight0 > 0) m_boneWeights[bw.boneIndex0] += bw.weight0;
+ if (bw.weight1 > 0) m_boneWeights[bw.boneIndex1] += bw.weight1;
+ if (bw.weight2 > 0) m_boneWeights[bw.boneIndex2] += bw.weight2;
+ if (bw.weight3 > 0) m_boneWeights[bw.boneIndex3] += bw.weight3;
+ }
+ }
+
+ Gizmos.color = m_meshGizmoColor;
+ Gizmos.DrawWireMesh(m_target);
+
+ for (var i = 0; i < m_target.bindposes.Length; ++i)
+ {
+ var color = m_bindGizmoColor * m_boneWeights[i];
+ color.a = 1.0f;
+ Gizmos.color = color;
+
+ Gizmos.matrix = transform.localToWorldMatrix * m_target.bindposes[i].inverse;
+ Gizmos.DrawWireCube(Vector3.zero, Vector3.one * m_gizmoSize);
+ }
+ }
+ else
+ {
+ Gizmos.color = Color.gray;
+ Gizmos.DrawWireMesh(m_target);
+ }
+ }
+ }
+}
diff --git a/Assets/ThirdParty/VRM/MeshUtility/Runtime/BindposeGizmo.cs.meta b/Assets/ThirdParty/VRM/MeshUtility/Runtime/BindposeGizmo.cs.meta
new file mode 100644
index 00000000..1567b1e4
--- /dev/null
+++ b/Assets/ThirdParty/VRM/MeshUtility/Runtime/BindposeGizmo.cs.meta
@@ -0,0 +1,13 @@
+fileFormatVersion: 2
+guid: 3ada4f7077a352343aed57e71a58885d
+timeCreated: 1518245944
+licenseType: Free
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/ThirdParty/VRM/MeshUtility/Runtime/BoneMeshEraser.cs b/Assets/ThirdParty/VRM/MeshUtility/Runtime/BoneMeshEraser.cs
new file mode 100644
index 00000000..64ee850d
--- /dev/null
+++ b/Assets/ThirdParty/VRM/MeshUtility/Runtime/BoneMeshEraser.cs
@@ -0,0 +1,166 @@
+using System;
+using System.Collections.Generic;
+using UnityEngine;
+
+
+namespace MeshUtility
+{
+ public static class BoneMeshEraser
+ {
+ private struct ExcludeBoneIndex
+ {
+ public readonly bool Bone0;
+ public readonly bool Bone1;
+ public readonly bool Bone2;
+ public readonly bool Bone3;
+
+ public ExcludeBoneIndex(bool bone0, bool bone1, bool bone2, bool bone3)
+ {
+ Bone0 = bone0;
+ Bone1 = bone1;
+ Bone2 = bone2;
+ Bone3 = bone3;
+ }
+ }
+
+ [Serializable]
+ public struct EraseBone
+ {
+ public Transform Bone;
+ public bool Erase;
+
+ public override string ToString()
+ {
+ return Bone.name + ":" + Erase;
+ }
+ }
+
+ static int ExcludeTriangles(int[] triangles, BoneWeight[] bws, int[] exclude)
+ {
+ int count = 0;
+ if (bws != null && bws.Length > 0)
+ {
+ for (int i = 0; i < triangles.Length; i += 3)
+ {
+ var a = triangles[i];
+ var b = triangles[i + 1];
+ var c = triangles[i + 2];
+
+ {
+ var bw = bws[a];
+ var eb = AreBoneContains(ref exclude, bw.boneIndex0, bw.boneIndex1, bw.boneIndex2, bw.boneIndex3);
+ if (bw.weight0 > 0 && eb.Bone0) continue;
+ if (bw.weight1 > 0 && eb.Bone1) continue;
+ if (bw.weight2 > 0 && eb.Bone2) continue;
+ if (bw.weight3 > 0 && eb.Bone3) continue;
+ }
+ {
+ var bw = bws[b];
+ var eb = AreBoneContains(ref exclude, bw.boneIndex0, bw.boneIndex1, bw.boneIndex2, bw.boneIndex3);
+ if (bw.weight0 > 0 && eb.Bone0) continue;
+ if (bw.weight1 > 0 && eb.Bone1) continue;
+ if (bw.weight2 > 0 && eb.Bone2) continue;
+ if (bw.weight3 > 0 && eb.Bone3) continue;
+ }
+ {
+ var bw = bws[c];
+ var eb = AreBoneContains(ref exclude, bw.boneIndex0, bw.boneIndex1, bw.boneIndex2, bw.boneIndex3);
+ if (bw.weight0 > 0 && eb.Bone0) continue;
+ if (bw.weight1 > 0 && eb.Bone1) continue;
+ if (bw.weight2 > 0 && eb.Bone2) continue;
+ if (bw.weight3 > 0 && eb.Bone3) continue;
+ }
+
+ triangles[count++] = a;
+ triangles[count++] = b;
+ triangles[count++] = c;
+ }
+ }
+
+ return count;
+ }
+
+ private static ExcludeBoneIndex AreBoneContains(ref int[] exclude, int boneIndex0, int boneIndex1,
+ int boneIndex2, int boneIndex3)
+ {
+ var b0 = false;
+ var b1 = false;
+ var b2 = false;
+ var b3 = false;
+ for (int i = 0; i < exclude.Length; i++)
+ {
+ if (exclude[i] == boneIndex0)
+ {
+ b0 = true;
+ continue;
+ }
+
+ if (exclude[i] == boneIndex1)
+ {
+ b1 = true;
+ continue;
+ }
+
+ if (exclude[i] == boneIndex2)
+ {
+ b2 = true;
+ continue;
+ }
+
+ if (exclude[i] == boneIndex3)
+ {
+ b3 = true;
+ }
+ }
+
+ return new ExcludeBoneIndex(b0, b1, b2, b3);
+ }
+
+ public static Mesh CreateErasedMesh(Mesh src, int[] eraseBoneIndices)
+ {
+ /*
+ Debug.LogFormat("{0} exclude: {1}",
+ src.name,
+ String.Join(", ", eraseBoneIndices.Select(x => x.ToString()).ToArray())
+ );
+ */
+ var mesh = new Mesh();
+ mesh.name = src.name + "(erased)";
+
+#if UNITY_2017_3_OR_NEWER
+ mesh.indexFormat = src.indexFormat;
+#endif
+
+ mesh.vertices = src.vertices;
+ mesh.normals = src.normals;
+ mesh.uv = src.uv;
+ mesh.tangents = src.tangents;
+ mesh.boneWeights = src.boneWeights;
+ mesh.bindposes = src.bindposes;
+ mesh.subMeshCount = src.subMeshCount;
+ for (int i = 0; i < src.subMeshCount; ++i)
+ {
+ var indices = src.GetIndices(i);
+ var count = ExcludeTriangles(indices, mesh.boneWeights, eraseBoneIndices);
+ var dst = new int[count];
+ Array.Copy(indices, 0, dst, 0, count);
+ mesh.SetIndices(dst, MeshTopology.Triangles, i);
+ }
+
+ return mesh;
+ }
+
+ public static IEnumerable<Transform> Ancestor(this Transform t)
+ {
+ yield return t;
+
+ if (t.parent != null)
+ {
+ foreach (var x in Ancestor(t.parent))
+ {
+ yield return x;
+ }
+ }
+ }
+ }
+}
diff --git a/Assets/ThirdParty/VRM/MeshUtility/Runtime/BoneMeshEraser.cs.meta b/Assets/ThirdParty/VRM/MeshUtility/Runtime/BoneMeshEraser.cs.meta
new file mode 100644
index 00000000..db633e87
--- /dev/null
+++ b/Assets/ThirdParty/VRM/MeshUtility/Runtime/BoneMeshEraser.cs.meta
@@ -0,0 +1,13 @@
+fileFormatVersion: 2
+guid: 270bf7461f6f8d546ae540cb7d5fc6f3
+timeCreated: 1519018975
+licenseType: Free
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/ThirdParty/VRM/MeshUtility/Runtime/BoneNormalizer.cs b/Assets/ThirdParty/VRM/MeshUtility/Runtime/BoneNormalizer.cs
new file mode 100644
index 00000000..b5f5231c
--- /dev/null
+++ b/Assets/ThirdParty/VRM/MeshUtility/Runtime/BoneNormalizer.cs
@@ -0,0 +1,507 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using UnityEngine;
+
+
+namespace MeshUtility
+{
+ public static class BoneNormalizer
+ {
+ public delegate Avatar CreateAvatarFunc(GameObject original, GameObject normalized, Dictionary<Transform, Transform> boneMap);
+
+ static (GameObject, Dictionary<Transform, Transform>) NormalizeHierarchy(GameObject go, CreateAvatarFunc createAvatar)
+ {
+ var boneMap = new Dictionary<Transform, Transform>();
+
+ //
+ // 回転・スケールの無いヒエラルキーをコピーする
+ //
+ var normalized = new GameObject(go.name + "(normalized)");
+ normalized.transform.position = go.transform.position;
+ CopyAndBuild(go.transform, normalized.transform, boneMap);
+
+ //
+ // 新しいヒエラルキーからAvatarを作る
+ //
+ {
+ var animator = normalized.AddComponent<Animator>();
+ var avatar = createAvatar(go, normalized, boneMap);
+ avatar.name = go.name + ".normalized";
+ animator.avatar = avatar;
+ }
+
+ return (normalized, boneMap);
+ }
+
+ /// <summary>
+ /// 回転とスケールを除去したヒエラルキーをコピーする。
+ /// </summary>
+ /// <param name="src"></param>
+ /// <param name="dst"></param>
+ static void CopyAndBuild(Transform src, Transform dst, Dictionary<Transform, Transform> boneMap)
+ {
+ boneMap[src] = dst;
+
+ foreach (Transform child in src)
+ {
+ if (child.gameObject.activeSelf)
+ {
+ var dstChild = new GameObject(child.name);
+ dstChild.transform.SetParent(dst);
+ dstChild.transform.position = child.position; // copy position only
+
+ CopyAndBuild(child, dstChild.transform, boneMap);
+ }
+ }
+ }
+
+ class BlendShapeReport
+ {
+ string m_name;
+ int m_count;
+ struct BlendShapeStat
+ {
+ public int Index;
+ public string Name;
+ public int VertexCount;
+ public int NormalCount;
+ public int TangentCount;
+
+ public override string ToString()
+ {
+ return string.Format("[{0}]{1}: {2}, {3}, {4}\n", Index, Name, VertexCount, NormalCount, TangentCount);
+ }
+ }
+ List<BlendShapeStat> m_stats = new List<BlendShapeStat>();
+ public int Count
+ {
+ get { return m_stats.Count; }
+ }
+ public BlendShapeReport(Mesh mesh)
+ {
+ m_name = mesh.name;
+ m_count = mesh.vertexCount;
+ }
+ public void SetCount(int index, string name, int v, int n, int t)
+ {
+ m_stats.Add(new BlendShapeStat
+ {
+ Index = index,
+ Name = name,
+ VertexCount = v,
+ NormalCount = n,
+ TangentCount = t,
+ });
+ }
+ public override string ToString()
+ {
+ return String.Format("NormalizeSkinnedMesh: {0}({1}verts)\n{2}",
+ m_name,
+ m_count,
+ String.Join("", m_stats.Select(x => x.ToString()).ToArray()));
+ }
+ }
+
+ /// <summary>
+ /// index が 有効であれば、setter に weight を渡す。無効であれば setter に 0 を渡す。
+ /// </summary>
+ /// <param name="indexMap"></param>
+ /// <param name="srcIndex"></param>
+ /// <param name="weight"></param>
+ /// <param name="setter"></param>
+ static bool CopyOrDropWeight(int[] indexMap, int srcIndex, float weight, Action<int, float> setter)
+ {
+ if (srcIndex < 0 || srcIndex >= indexMap.Length)
+ {
+ // ありえるかどうかわからないが BoneWeight.boneIndexN に変な値が入っている.
+ setter(0, 0);
+ return false;
+ }
+
+ var dstIndex = indexMap[srcIndex];
+ if (dstIndex != -1)
+ {
+ // 有効なindex。weightをコピーする
+ setter(dstIndex, weight);
+ return true;
+ }
+ else
+ {
+ // 無効なindex。0でクリアする
+ setter(0, 0);
+ return false;
+ }
+ }
+
+ /// <summary>
+ /// BoneWeight[] src から新しいボーンウェイトを作成する。
+ /// </summary>
+ /// <param name="src">変更前のBoneWeight[]</param>
+ /// <param name="boneMap">新旧のボーンの対応表。新しい方は無効なボーンが除去されてnullの部分がある</param>
+ /// <param name="srcBones">変更前のボーン配列</param>
+ /// <param name="dstBones">変更後のボーン配列。除去されたボーンがある場合、変更前より短い</param>
+ /// <returns></returns>
+ public static BoneWeight[] MapBoneWeight(BoneWeight[] src,
+ Dictionary<Transform, Transform> boneMap,
+ Transform[] srcBones,
+ Transform[] dstBones
+ )
+ {
+ // 処理前後の index の対応表を作成する
+ var indexMap = new int[srcBones.Length];
+ for (int i = 0; i < srcBones.Length; ++i)
+ {
+ var srcBone = srcBones[i];
+ if (srcBone == null)
+ {
+ // 元のボーンが無い
+ indexMap[i] = -1;
+ Debug.LogWarningFormat("bones[{0}] is null", i);
+ }
+ else
+ {
+ if (boneMap.TryGetValue(srcBone, out Transform dstBone))
+ {
+ // 対応するボーンが存在する
+ var dstIndex = Array.IndexOf(dstBones, dstBone);
+ if (dstIndex == -1)
+ {
+ // ありえない。バグ
+ throw new Exception();
+ }
+ indexMap[i] = dstIndex;
+ }
+ else
+ {
+ // 先のボーンが無い
+ indexMap[i] = -1;
+ Debug.LogWarningFormat("{0} is removed", srcBone.name);
+ }
+ }
+ }
+
+ // 新しいBoneWeightを作成する
+ var newBoneWeights = new BoneWeight[src.Length];
+ for (int i = 0; i < src.Length; ++i)
+ {
+ BoneWeight srcBoneWeight = src[i];
+
+ // 0
+ CopyOrDropWeight(indexMap, srcBoneWeight.boneIndex0, srcBoneWeight.weight0, (newIndex, newWeight) =>
+ {
+ newBoneWeights[i].boneIndex0 = newIndex;
+ newBoneWeights[i].weight0 = newWeight;
+ });
+ // 1
+ CopyOrDropWeight(indexMap, srcBoneWeight.boneIndex1, srcBoneWeight.weight1, (newIndex, newWeight) =>
+ {
+ newBoneWeights[i].boneIndex1 = newIndex;
+ newBoneWeights[i].weight1 = newWeight;
+ });
+ // 2
+ CopyOrDropWeight(indexMap, srcBoneWeight.boneIndex2, srcBoneWeight.weight2, (newIndex, newWeight) =>
+ {
+ newBoneWeights[i].boneIndex2 = newIndex;
+ newBoneWeights[i].weight2 = newWeight;
+ });
+ // 3
+ CopyOrDropWeight(indexMap, srcBoneWeight.boneIndex3, srcBoneWeight.weight3, (newIndex, newWeight) =>
+ {
+ newBoneWeights[i].boneIndex3 = newIndex;
+ newBoneWeights[i].weight3 = newWeight;
+ });
+ }
+
+ return newBoneWeights;
+ }
+
+ /// <summary>
+ /// srcのSkinnedMeshRendererを正規化して、dstにアタッチする
+ /// </summary>
+ /// <param name="src">正規化前のSkinnedMeshRendererのTransform</param>
+ /// <param name="dst">正規化後のSkinnedMeshRendererのTransform</param>
+ /// <param name="boneMap">正規化前のボーンから正規化後のボーンを得る</param>
+ static void NormalizeSkinnedMesh(Transform src, Transform dst, Dictionary<Transform, Transform> boneMap, bool clearBlendShape)
+ {
+ var srcRenderer = src.GetComponent<SkinnedMeshRenderer>();
+ if (srcRenderer == null
+ || !srcRenderer.enabled
+ || srcRenderer.sharedMesh == null
+ || srcRenderer.sharedMesh.vertexCount == 0)
+ {
+ // 有効なSkinnedMeshRendererが無かった
+ return;
+ }
+
+ var srcMesh = srcRenderer.sharedMesh;
+ var originalSrcMesh = srcMesh;
+
+ // clear blendShape
+ if (clearBlendShape)
+ {
+ for (int i = 0; i < srcMesh.blendShapeCount; ++i)
+ {
+ srcRenderer.SetBlendShapeWeight(i, 0);
+ }
+ }
+
+ // 元の Transform[] bones から、無効なboneを取り除いて前に詰めた配列を作る
+ var dstBones = srcRenderer.bones
+ .Where(x => x != null && boneMap.ContainsKey(x))
+ .Select(x => boneMap[x])
+ .ToArray();
+
+ var hasBoneWeight = srcRenderer.bones != null && srcRenderer.bones.Length > 0;
+ if (!hasBoneWeight)
+ {
+ // Before bake, bind no weight bones
+ //Debug.LogFormat("no weight: {0}", srcMesh.name);
+
+ srcMesh = srcMesh.Copy(true);
+ var bw = new BoneWeight
+ {
+ boneIndex0 = 0,
+ boneIndex1 = 0,
+ boneIndex2 = 0,
+ boneIndex3 = 0,
+ weight0 = 1.0f,
+ weight1 = 0.0f,
+ weight2 = 0.0f,
+ weight3 = 0.0f,
+ };
+ srcMesh.boneWeights = Enumerable.Range(0, srcMesh.vertexCount).Select(x => bw).ToArray();
+ srcMesh.bindposes = new Matrix4x4[] { Matrix4x4.identity };
+
+ srcRenderer.rootBone = srcRenderer.transform;
+ dstBones = new[] { boneMap[srcRenderer.transform] };
+ srcRenderer.bones = new[] { srcRenderer.transform };
+ srcRenderer.sharedMesh = srcMesh;
+ }
+
+ // BakeMesh
+ var mesh = srcMesh.Copy(false);
+ mesh.name = srcMesh.name + ".baked";
+ srcRenderer.BakeMesh(mesh);
+
+ var blendShapeValues = new Dictionary<int, float>();
+ for (int i = 0; i < srcMesh.blendShapeCount; i++)
+ {
+ var val = srcRenderer.GetBlendShapeWeight(i);
+ if (val > 0) blendShapeValues.Add(i, val);
+ }
+
+ // 新しい骨格のボーンウェイトを作成する
+ mesh.boneWeights = MapBoneWeight(srcMesh.boneWeights, boneMap, srcRenderer.bones, dstBones);
+
+ // recalc bindposes
+ mesh.bindposes = dstBones.Select(x => x.worldToLocalMatrix * dst.transform.localToWorldMatrix).ToArray();
+
+ //var m = src.localToWorldMatrix; // include scaling
+ var m = default(Matrix4x4);
+ m.SetTRS(Vector3.zero, src.rotation, Vector3.one); // rotation only
+ mesh.ApplyMatrix(m);
+
+ //
+ // BlendShapes
+ //
+ var meshVertices = mesh.vertices;
+ var meshNormals = mesh.normals;
+#if VRM_NORMALIZE_BLENDSHAPE_TANGENT
+ var meshTangents = mesh.tangents.Select(x => (Vector3)x).ToArray();
+#endif
+
+ var originalBlendShapePositions = new Vector3[meshVertices.Length];
+ var originalBlendShapeNormals = new Vector3[meshVertices.Length];
+ var originalBlendShapeTangents = new Vector3[meshVertices.Length];
+
+ var report = new BlendShapeReport(srcMesh);
+ var blendShapeMesh = new Mesh();
+ for (int i = 0; i < srcMesh.blendShapeCount; ++i)
+ {
+ // check blendShape
+ srcRenderer.sharedMesh.GetBlendShapeFrameVertices(i, 0, originalBlendShapePositions, originalBlendShapeNormals, originalBlendShapeTangents);
+ var hasVertices = originalBlendShapePositions.Count(x => x != Vector3.zero);
+ var hasNormals = originalBlendShapeNormals.Count(x => x != Vector3.zero);
+#if VRM_NORMALIZE_BLENDSHAPE_TANGENT
+ var hasTangents = originalBlendShapeTangents.Count(x => x != Vector3.zero);
+#else
+ var hasTangents = 0;
+#endif
+ var name = srcMesh.GetBlendShapeName(i);
+ if (string.IsNullOrEmpty(name))
+ {
+ name = String.Format("{0}", i);
+ }
+
+ report.SetCount(i, name, hasVertices, hasNormals, hasTangents);
+
+ srcRenderer.SetBlendShapeWeight(i, 100.0f);
+ srcRenderer.BakeMesh(blendShapeMesh);
+ if (blendShapeMesh.vertices.Length != mesh.vertices.Length)
+ {
+ throw new Exception("different vertex count");
+ }
+
+ var value = blendShapeValues.ContainsKey(i) ? blendShapeValues[i] : 0;
+ srcRenderer.SetBlendShapeWeight(i, value);
+
+ Vector3[] vertices = blendShapeMesh.vertices;
+
+ for (int j = 0; j < vertices.Length; ++j)
+ {
+ if (originalBlendShapePositions[j] == Vector3.zero)
+ {
+ vertices[j] = Vector3.zero;
+ }
+ else
+ {
+ vertices[j] = m.MultiplyPoint(vertices[j]) - meshVertices[j];
+ }
+ }
+
+ Vector3[] normals = blendShapeMesh.normals;
+ for (int j = 0; j < normals.Length; ++j)
+ {
+ if (originalBlendShapeNormals[j] == Vector3.zero)
+ {
+ normals[j] = Vector3.zero;
+
+ }
+ else
+ {
+ normals[j] = m.MultiplyVector(normals[j]) - meshNormals[j];
+ }
+ }
+
+ Vector3[] tangents = blendShapeMesh.tangents.Select(x => (Vector3)x).ToArray();
+#if VRM_NORMALIZE_BLENDSHAPE_TANGENT
+ for (int j = 0; j < tangents.Length; ++j)
+ {
+ if (originalBlendShapeTangents[j] == Vector3.zero)
+ {
+ tangents[j] = Vector3.zero;
+ }
+ else
+ {
+ tangents[j] = m.MultiplyVector(tangents[j]) - meshTangents[j];
+ }
+ }
+#endif
+
+ var frameCount = srcMesh.GetBlendShapeFrameCount(i);
+ for (int f = 0; f < frameCount; f++)
+ {
+
+ var weight = srcMesh.GetBlendShapeFrameWeight(i, f);
+
+ try
+ {
+ mesh.AddBlendShapeFrame(name,
+ weight,
+ vertices,
+ hasNormals > 0 ? normals : null,
+ hasTangents > 0 ? tangents : null
+ );
+ }
+ catch (Exception)
+ {
+ Debug.LogErrorFormat("fail to mesh.AddBlendShapeFrame {0}.{1}",
+ mesh.name,
+ srcMesh.GetBlendShapeName(i)
+ );
+ throw;
+ }
+ }
+ }
+
+ if (report.Count > 0)
+ {
+ Debug.LogFormat("{0}", report.ToString());
+ }
+
+ var dstRenderer = dst.gameObject.AddComponent<SkinnedMeshRenderer>();
+ dstRenderer.sharedMaterials = srcRenderer.sharedMaterials;
+ if (srcRenderer.rootBone != null)
+ {
+ dstRenderer.rootBone = boneMap[srcRenderer.rootBone];
+ }
+ dstRenderer.bones = dstBones;
+ dstRenderer.sharedMesh = mesh;
+
+ if (!hasBoneWeight)
+ {
+ // restore bones
+ srcRenderer.bones = new Transform[] { };
+ srcRenderer.sharedMesh = originalSrcMesh;
+ }
+ }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="src"></param>
+ /// <param name="dst"></param>
+ static void NormalizeNoneSkinnedMesh(Transform src, Transform dst)
+ {
+ var srcFilter = src.GetComponent<MeshFilter>();
+ if (srcFilter == null
+ || srcFilter.sharedMesh == null
+ || srcFilter.sharedMesh.vertexCount == 0)
+ {
+ return;
+ }
+
+ var srcRenderer = src.GetComponent<MeshRenderer>();
+ if (srcRenderer == null || !srcRenderer.enabled)
+ {
+ return;
+ }
+
+ // Meshに乗っているボーンの姿勢を適用する
+ var dstFilter = dst.gameObject.AddComponent<MeshFilter>();
+
+ var dstMesh = srcFilter.sharedMesh.Copy(false);
+ dstMesh.ApplyRotationAndScale(src.localToWorldMatrix);
+ dstFilter.sharedMesh = dstMesh;
+
+ // Materialをコピー
+ var dstRenderer = dst.gameObject.AddComponent<MeshRenderer>();
+ dstRenderer.sharedMaterials = srcRenderer.sharedMaterials;
+ }
+
+ /// <summary>
+ /// 回転とスケールを除去したヒエラルキーのコピーを作成する(MeshをBakeする)
+ /// </summary>
+ /// <param name="go">対象のヒエラルキーのルート</param>
+ /// <param name="clearBlendShapeBeforeNormalize">BlendShapeを0クリアするか否か。false の場合 BlendShape の現状を Bake する</param>
+ /// <param name="createAvatar">Avatarを作る関数</param>
+ /// <returns></returns>
+ public static (GameObject, Dictionary<Transform, Transform>) Execute(GameObject go,
+ bool clearBlendShapeBeforeNormalize, CreateAvatarFunc createAvatar)
+ {
+ //
+ // 正規化されたヒエラルキーを作る
+ //
+ var (normalized, boneMap) = NormalizeHierarchy(go, createAvatar);
+
+ //
+ // 各メッシュから回転・スケールを取り除いてBinding行列を再計算する
+ //
+ foreach (var src in go.transform.Traverse())
+ {
+ Transform dst;
+ if (!boneMap.TryGetValue(src, out dst))
+ {
+ continue;
+ }
+
+ NormalizeSkinnedMesh(src, dst, boneMap, clearBlendShapeBeforeNormalize);
+
+ NormalizeNoneSkinnedMesh(src, dst);
+ }
+
+ return (normalized, boneMap);
+ }
+ }
+}
diff --git a/Assets/ThirdParty/VRM/MeshUtility/Runtime/BoneNormalizer.cs.meta b/Assets/ThirdParty/VRM/MeshUtility/Runtime/BoneNormalizer.cs.meta
new file mode 100644
index 00000000..4663d268
--- /dev/null
+++ b/Assets/ThirdParty/VRM/MeshUtility/Runtime/BoneNormalizer.cs.meta
@@ -0,0 +1,13 @@
+fileFormatVersion: 2
+guid: b330ec419f98af14687c302638922ab0
+timeCreated: 1519379418
+licenseType: Free
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/ThirdParty/VRM/MeshUtility/Runtime/Humanoid.cs b/Assets/ThirdParty/VRM/MeshUtility/Runtime/Humanoid.cs
new file mode 100644
index 00000000..c6d61948
--- /dev/null
+++ b/Assets/ThirdParty/VRM/MeshUtility/Runtime/Humanoid.cs
@@ -0,0 +1,441 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Linq;
+using UnityEngine;
+
+namespace MeshUtility
+{
+ /// <summary>
+ /// Bone割り当てを保持する。
+ /// ヒエラルキーのルート(おそらくHipsの親)にアタッチする
+ /// </summary>
+ [DisallowMultipleComponent]
+ public class Humanoid : MonoBehaviour
+ {
+ [SerializeField] private Transform m_Hips; public Transform Hips => m_Hips;
+
+ #region leg
+ [SerializeField] private Transform m_LeftUpperLeg; public Transform LeftUpperLeg => m_LeftUpperLeg;
+ [SerializeField] private Transform m_RightUpperLeg; public Transform RightUpperLeg => m_RightUpperLeg;
+ [SerializeField] private Transform m_LeftLowerLeg; public Transform LeftLowerLeg => m_LeftLowerLeg;
+ [SerializeField] private Transform m_RightLowerLeg; public Transform RightLowerLeg => m_RightLowerLeg;
+ [SerializeField] private Transform m_LeftFoot; public Transform LeftFoot => m_LeftFoot;
+ [SerializeField] private Transform m_RightFoot; public Transform RightFoot => m_RightFoot;
+ [SerializeField] private Transform m_LeftToes; public Transform LeftToes => m_LeftToes;
+ [SerializeField] private Transform m_RightToes; public Transform RightToes => m_RightToes;
+ #endregion
+
+ #region spine
+ [SerializeField] private Transform m_Spine; public Transform Spine => m_Spine;
+ [SerializeField] private Transform m_Chest; public Transform Chest => m_Chest;
+ [SerializeField] private Transform m_UpperChest; public Transform UpperChest => m_UpperChest;
+ [SerializeField] private Transform m_Neck; public Transform Neck => m_Neck;
+ [SerializeField] private Transform m_Head; public Transform Head => m_Head;
+ [SerializeField] private Transform m_LeftEye; public Transform LeftEye => m_LeftEye;
+ [SerializeField] private Transform m_RightEye; public Transform RightEye => m_RightEye;
+ [SerializeField] private Transform m_Jaw; public Transform Jaw => m_Jaw;
+ #endregion
+
+ #region arm
+ [SerializeField] private Transform m_LeftShoulder; public Transform LeftShoulder => m_LeftShoulder;
+ [SerializeField] private Transform m_RightShoulder; public Transform RightShoulder => m_RightShoulder;
+ [SerializeField] private Transform m_LeftUpperArm; public Transform LeftUpperArm => m_LeftUpperArm;
+ [SerializeField] private Transform m_RightUpperArm; public Transform RightUpperArm => m_RightUpperArm;
+ [SerializeField] private Transform m_LeftLowerArm; public Transform LeftLowerArm => m_LeftLowerArm;
+ [SerializeField] private Transform m_RightLowerArm; public Transform RightLowerArm => m_RightLowerArm;
+ [SerializeField] private Transform m_LeftHand; public Transform LeftHand => m_LeftHand;
+ [SerializeField] private Transform m_RightHand; public Transform RightHand => m_RightHand;
+ #endregion
+
+ #region fingers
+ [SerializeField] private Transform m_LeftThumbProximal; public Transform LeftThumbProximal => m_LeftThumbProximal;
+ [SerializeField] private Transform m_LeftThumbIntermediate; public Transform LeftThumbIntermediate => m_LeftThumbIntermediate;
+ [SerializeField] private Transform m_LeftThumbDistal; public Transform LeftThumbDistal => m_LeftThumbDistal;
+ [SerializeField] private Transform m_LeftIndexProximal; public Transform LeftIndexProximal => m_LeftIndexProximal;
+ [SerializeField] private Transform m_LeftIndexIntermediate; public Transform LeftIndexIntermediate => m_LeftIndexIntermediate;
+ [SerializeField] private Transform m_LeftIndexDistal; public Transform LeftIndexDistal => m_LeftIndexDistal;
+ [SerializeField] private Transform m_LeftMiddleProximal; public Transform LeftMiddleProximal => m_LeftMiddleProximal;
+ [SerializeField] private Transform m_LeftMiddleIntermediate; public Transform LeftMiddleIntermediate => m_LeftMiddleIntermediate;
+ [SerializeField] private Transform m_LeftMiddleDistal; public Transform LeftMiddleDistal => m_LeftMiddleDistal;
+ [SerializeField] private Transform m_LeftRingProximal; public Transform LeftRingProximal => m_LeftRingProximal;
+ [SerializeField] private Transform m_LeftRingIntermediate; public Transform LeftRingIntermediate => m_LeftRingIntermediate;
+ [SerializeField] private Transform m_LeftRingDistal; public Transform LeftRingDistal => m_LeftRingDistal;
+ [SerializeField] private Transform m_LeftLittleProximal; public Transform LeftLittleProximal => m_LeftLittleProximal;
+ [SerializeField] private Transform m_LeftLittleIntermediate; public Transform LeftLittleIntermediate => m_LeftLittleIntermediate;
+ [SerializeField] private Transform m_LeftLittleDistal; public Transform LeftLittleDistal => m_LeftLittleDistal;
+ [SerializeField] private Transform m_RightThumbProximal; public Transform RightThumbProximal => m_RightThumbProximal;
+ [SerializeField] private Transform m_RightThumbIntermediate; public Transform RightThumbIntermediate => m_RightThumbIntermediate;
+ [SerializeField] private Transform m_RightThumbDistal; public Transform RightThumbDistal => m_RightThumbDistal;
+ [SerializeField] private Transform m_RightIndexProximal; public Transform RightIndexProximal => m_RightIndexProximal;
+ [SerializeField] private Transform m_RightIndexIntermediate; public Transform RightIndexIntermediate => m_RightIndexIntermediate;
+ [SerializeField] private Transform m_RightIndexDistal; public Transform RightIndexDistal => m_RightIndexDistal;
+ [SerializeField] private Transform m_RightMiddleProximal; public Transform RightMiddleProximal => m_RightMiddleProximal;
+ [SerializeField] private Transform m_RightMiddleIntermediate; public Transform RightMiddleIntermediate => m_RightMiddleIntermediate;
+ [SerializeField] private Transform m_RightMiddleDistal; public Transform RightMiddleDistal => m_RightMiddleDistal;
+ [SerializeField] private Transform m_RightRingProximal; public Transform RightRingProximal => m_RightRingProximal;
+ [SerializeField] private Transform m_RightRingIntermediate; public Transform RightRingIntermediate => m_RightRingIntermediate;
+ [SerializeField] private Transform m_RightRingDistal; public Transform RightRingDistal => m_RightRingDistal;
+ [SerializeField] private Transform m_RightLittleProximal; public Transform RightLittleProximal => m_RightLittleProximal;
+ [SerializeField] private Transform m_RightLittleIntermediate; public Transform RightLittleIntermediate => m_RightLittleIntermediate;
+ [SerializeField] private Transform m_RightLittleDistal; public Transform RightLittleDistal => m_RightLittleDistal;
+ #endregion
+
+ void Reset()
+ {
+ AssignBonesFromAnimator();
+ }
+
+ public struct Validation
+ {
+ public readonly string Message;
+ public readonly bool IsError;
+
+ public Validation(string message, bool isError)
+ {
+ Message = message;
+ IsError = isError;
+ }
+ }
+
+ IEnumerable<Validation> Required(params (string, Transform)[] props)
+ {
+ foreach (var prop in props)
+ {
+ if (prop.Item2 == null)
+ {
+ var name = prop.Item1;
+ if (name.StartsWith("m_"))
+ {
+ name = name.Substring(2);
+ }
+ yield return new Validation($"{name} is Required", true);
+ }
+ }
+ }
+
+ static Vector3 GetForward(Transform l, Transform r)
+ {
+ if (l == null || r == null)
+ {
+ return Vector3.zero;
+ }
+ var lr = (r.position - l.position).normalized;
+ return Vector3.Cross(lr, Vector3.up);
+ }
+
+ public Vector3 GetForward()
+ {
+ return GetForward(m_LeftUpperLeg, m_RightUpperLeg);
+ }
+
+ public IEnumerable<Validation> Validate()
+ {
+ foreach (var validation in Required(
+ (nameof(m_Hips), m_Hips), (nameof(m_Spine), m_Spine), (nameof(m_Head), m_Head),
+ (nameof(m_LeftUpperLeg), m_LeftUpperLeg), (nameof(m_LeftLowerLeg), m_LeftLowerLeg), (nameof(m_LeftFoot), m_LeftFoot),
+ (nameof(m_RightUpperLeg), m_RightUpperLeg), (nameof(m_RightLowerLeg), m_RightLowerLeg), (nameof(m_RightFoot), m_RightFoot),
+ (nameof(m_LeftUpperArm), m_LeftUpperArm), (nameof(m_LeftLowerArm), m_LeftLowerArm), (nameof(m_LeftHand), m_LeftHand),
+ (nameof(m_RightUpperArm), m_RightUpperArm), (nameof(m_RightLowerArm), m_RightLowerArm), (nameof(m_RightHand), m_RightHand)
+ ))
+ {
+ yield return validation;
+ }
+
+ // var forward = GetForward();
+ // if (Vector3.Dot(Vector3.forward, forward) < 0.5f)
+ // {
+ // yield return new Validation("Not facing the Z-axis positive direction", true);
+ // }
+ }
+
+ /// <summary>
+ /// ボーン割り当てから UnityEngine.Avatar を生成する
+ /// </summary>
+ /// <returns></returns>
+ public Avatar CreateAvatar()
+ {
+ return HumanoidLoader.LoadHumanoidAvatar(transform, BoneMap);
+ }
+
+ public Transform GetBoneTransform(HumanBodyBones bone)
+ {
+ switch (bone)
+ {
+ case HumanBodyBones.Hips: return Hips;
+
+ #region leg
+ case HumanBodyBones.LeftUpperLeg: return LeftUpperLeg;
+ case HumanBodyBones.RightUpperLeg: return RightUpperLeg;
+ case HumanBodyBones.LeftLowerLeg: return LeftLowerLeg;
+ case HumanBodyBones.RightLowerLeg: return RightLowerLeg;
+ case HumanBodyBones.LeftFoot: return LeftFoot;
+ case HumanBodyBones.RightFoot: return RightFoot;
+ case HumanBodyBones.LeftToes: return LeftToes;
+ case HumanBodyBones.RightToes: return RightToes;
+ #endregion
+
+ #region spine
+ case HumanBodyBones.Spine: return Spine;
+ case HumanBodyBones.Chest: return Chest;
+ case HumanBodyBones.UpperChest: return UpperChest;
+ case HumanBodyBones.Neck: return Neck;
+ case HumanBodyBones.Head: return Head;
+ case HumanBodyBones.LeftEye: return LeftEye;
+ case HumanBodyBones.RightEye: return RightEye;
+ case HumanBodyBones.Jaw: return Jaw;
+ #endregion
+
+ #region arm
+ case HumanBodyBones.LeftShoulder: return LeftShoulder;
+ case HumanBodyBones.RightShoulder: return RightShoulder;
+ case HumanBodyBones.LeftUpperArm: return LeftUpperArm;
+ case HumanBodyBones.RightUpperArm: return RightUpperArm;
+ case HumanBodyBones.LeftLowerArm: return LeftLowerArm;
+ case HumanBodyBones.RightLowerArm: return RightLowerArm;
+ case HumanBodyBones.LeftHand: return LeftHand;
+ case HumanBodyBones.RightHand: return RightHand;
+ #endregion
+
+ #region fingers
+ case HumanBodyBones.LeftThumbProximal: return LeftThumbProximal;
+ case HumanBodyBones.LeftThumbIntermediate: return LeftThumbIntermediate;
+ case HumanBodyBones.LeftThumbDistal: return LeftThumbDistal;
+ case HumanBodyBones.LeftIndexProximal: return LeftIndexProximal;
+ case HumanBodyBones.LeftIndexIntermediate: return LeftIndexIntermediate;
+ case HumanBodyBones.LeftIndexDistal: return LeftIndexDistal;
+ case HumanBodyBones.LeftMiddleProximal: return LeftMiddleProximal;
+ case HumanBodyBones.LeftMiddleIntermediate: return LeftMiddleIntermediate;
+ case HumanBodyBones.LeftMiddleDistal: return LeftMiddleDistal;
+ case HumanBodyBones.LeftRingProximal: return LeftRingProximal;
+ case HumanBodyBones.LeftRingIntermediate: return LeftRingIntermediate;
+ case HumanBodyBones.LeftRingDistal: return LeftRingDistal;
+ case HumanBodyBones.LeftLittleProximal: return LeftLittleProximal;
+ case HumanBodyBones.LeftLittleIntermediate: return LeftLittleIntermediate;
+ case HumanBodyBones.LeftLittleDistal: return LeftLittleDistal;
+ case HumanBodyBones.RightThumbProximal: return RightThumbProximal;
+ case HumanBodyBones.RightThumbIntermediate: return RightThumbIntermediate;
+ case HumanBodyBones.RightThumbDistal: return RightThumbDistal;
+ case HumanBodyBones.RightIndexProximal: return RightIndexProximal;
+ case HumanBodyBones.RightIndexIntermediate: return RightIndexIntermediate;
+ case HumanBodyBones.RightIndexDistal: return RightIndexDistal;
+ case HumanBodyBones.RightMiddleProximal: return RightMiddleProximal;
+ case HumanBodyBones.RightMiddleIntermediate: return RightMiddleIntermediate;
+ case HumanBodyBones.RightMiddleDistal: return RightMiddleDistal;
+ case HumanBodyBones.RightRingProximal: return RightRingProximal;
+ case HumanBodyBones.RightRingIntermediate: return RightRingIntermediate;
+ case HumanBodyBones.RightRingDistal: return RightRingDistal;
+ case HumanBodyBones.RightLittleProximal: return RightLittleProximal;
+ case HumanBodyBones.RightLittleIntermediate: return RightLittleIntermediate;
+ case HumanBodyBones.RightLittleDistal: return RightLittleDistal;
+ #endregion
+
+ }
+
+ return null;
+ }
+
+ IEnumerable<(Transform, HumanBodyBones)> BoneMap
+ {
+ get
+ {
+ if (Hips != null) { yield return (Hips, HumanBodyBones.Hips); }
+
+ #region leg
+ if (LeftUpperLeg != null) { yield return (LeftUpperLeg, HumanBodyBones.LeftUpperLeg); }
+ if (RightUpperLeg != null) { yield return (RightUpperLeg, HumanBodyBones.RightUpperLeg); }
+ if (LeftLowerLeg != null) { yield return (LeftLowerLeg, HumanBodyBones.LeftLowerLeg); }
+ if (RightLowerLeg != null) { yield return (RightLowerLeg, HumanBodyBones.RightLowerLeg); }
+ if (LeftFoot != null) { yield return (LeftFoot, HumanBodyBones.LeftFoot); }
+ if (RightFoot != null) { yield return (RightFoot, HumanBodyBones.RightFoot); }
+ if (LeftToes != null) { yield return (LeftToes, HumanBodyBones.LeftToes); }
+ if (RightToes != null) { yield return (RightToes, HumanBodyBones.RightToes); }
+ #endregion
+
+ #region spine
+ if (Spine != null) { yield return (Spine, HumanBodyBones.Spine); }
+ if (Chest != null) { yield return (Chest, HumanBodyBones.Chest); }
+ if (UpperChest != null) { yield return (UpperChest, HumanBodyBones.UpperChest); }
+ if (Neck != null) { yield return (Neck, HumanBodyBones.Neck); }
+ if (Head != null) { yield return (Head, HumanBodyBones.Head); }
+ if (LeftEye != null) { yield return (LeftEye, HumanBodyBones.LeftEye); }
+ if (RightEye != null) { yield return (RightEye, HumanBodyBones.RightEye); }
+ if (Jaw != null) { yield return (Jaw, HumanBodyBones.Jaw); }
+ #endregion
+
+ #region arm
+ if (LeftShoulder != null) { yield return (LeftShoulder, HumanBodyBones.LeftShoulder); }
+ if (RightShoulder != null) { yield return (RightShoulder, HumanBodyBones.RightShoulder); }
+ if (LeftUpperArm != null) { yield return (LeftUpperArm, HumanBodyBones.LeftUpperArm); }
+ if (RightUpperArm != null) { yield return (RightUpperArm, HumanBodyBones.RightUpperArm); }
+ if (LeftLowerArm != null) { yield return (LeftLowerArm, HumanBodyBones.LeftLowerArm); }
+ if (RightLowerArm != null) { yield return (RightLowerArm, HumanBodyBones.RightLowerArm); }
+ if (LeftHand != null) { yield return (LeftHand, HumanBodyBones.LeftHand); }
+ if (RightHand != null) { yield return (RightHand, HumanBodyBones.RightHand); }
+ #endregion
+
+ #region fingers
+ if (LeftThumbProximal != null) { yield return (LeftThumbProximal, HumanBodyBones.LeftThumbProximal); }
+ if (LeftThumbIntermediate != null) { yield return (LeftThumbIntermediate, HumanBodyBones.LeftThumbIntermediate); }
+ if (LeftThumbDistal != null) { yield return (LeftThumbDistal, HumanBodyBones.LeftThumbDistal); }
+ if (LeftIndexProximal != null) { yield return (LeftIndexProximal, HumanBodyBones.LeftIndexProximal); }
+ if (LeftIndexIntermediate != null) { yield return (LeftIndexIntermediate, HumanBodyBones.LeftIndexIntermediate); }
+ if (LeftIndexDistal != null) { yield return (LeftIndexDistal, HumanBodyBones.LeftIndexDistal); }
+ if (LeftMiddleProximal != null) { yield return (LeftMiddleProximal, HumanBodyBones.LeftMiddleProximal); }
+ if (LeftMiddleIntermediate != null) { yield return (LeftMiddleIntermediate, HumanBodyBones.LeftMiddleIntermediate); }
+ if (LeftMiddleDistal != null) { yield return (LeftMiddleDistal, HumanBodyBones.LeftMiddleDistal); }
+ if (LeftRingProximal != null) { yield return (LeftRingProximal, HumanBodyBones.LeftRingProximal); }
+ if (LeftRingIntermediate != null) { yield return (LeftRingIntermediate, HumanBodyBones.LeftRingIntermediate); }
+ if (LeftRingDistal != null) { yield return (LeftRingDistal, HumanBodyBones.LeftRingDistal); }
+ if (LeftLittleProximal != null) { yield return (LeftLittleProximal, HumanBodyBones.LeftLittleProximal); }
+ if (LeftLittleIntermediate != null) { yield return (LeftLittleIntermediate, HumanBodyBones.LeftLittleIntermediate); }
+ if (LeftLittleDistal != null) { yield return (LeftLittleDistal, HumanBodyBones.LeftLittleDistal); }
+ if (RightThumbProximal != null) { yield return (RightThumbProximal, HumanBodyBones.RightThumbProximal); }
+ if (RightThumbIntermediate != null) { yield return (RightThumbIntermediate, HumanBodyBones.RightThumbIntermediate); }
+ if (RightThumbDistal != null) { yield return (RightThumbDistal, HumanBodyBones.RightThumbDistal); }
+ if (RightIndexProximal != null) { yield return (RightIndexProximal, HumanBodyBones.RightIndexProximal); }
+ if (RightIndexIntermediate != null) { yield return (RightIndexIntermediate, HumanBodyBones.RightIndexIntermediate); }
+ if (RightIndexDistal != null) { yield return (RightIndexDistal, HumanBodyBones.RightIndexDistal); }
+ if (RightMiddleProximal != null) { yield return (RightMiddleProximal, HumanBodyBones.RightMiddleProximal); }
+ if (RightMiddleIntermediate != null) { yield return (RightMiddleIntermediate, HumanBodyBones.RightMiddleIntermediate); }
+ if (RightMiddleDistal != null) { yield return (RightMiddleDistal, HumanBodyBones.RightMiddleDistal); }
+ if (RightRingProximal != null) { yield return (RightRingProximal, HumanBodyBones.RightRingProximal); }
+ if (RightRingIntermediate != null) { yield return (RightRingIntermediate, HumanBodyBones.RightRingIntermediate); }
+ if (RightRingDistal != null) { yield return (RightRingDistal, HumanBodyBones.RightRingDistal); }
+ if (RightLittleProximal != null) { yield return (RightLittleProximal, HumanBodyBones.RightLittleProximal); }
+ if (RightLittleIntermediate != null) { yield return (RightLittleIntermediate, HumanBodyBones.RightLittleIntermediate); }
+ if (RightLittleDistal != null) { yield return (RightLittleDistal, HumanBodyBones.RightLittleDistal); }
+ #endregion
+ }
+ }
+
+ /// <summary>
+ /// nodes からボーンを割り当てる
+ /// </summary>
+ /// <param name="nodes"></param>
+ public void AssignBones(IEnumerable<(HumanBodyBones, Transform)> nodes)
+ {
+ foreach (var (key, value) in nodes)
+ {
+ if (key == HumanBodyBones.LastBone)
+ {
+ continue;
+ }
+ if (value is null)
+ {
+ continue;
+ }
+
+ switch (key)
+ {
+ case HumanBodyBones.Hips: m_Hips = value; break;
+
+ #region leg
+ case HumanBodyBones.LeftUpperLeg: m_LeftUpperLeg = value; break;
+ case HumanBodyBones.RightUpperLeg: m_RightUpperLeg = value; break;
+ case HumanBodyBones.LeftLowerLeg: m_LeftLowerLeg = value; break;
+ case HumanBodyBones.RightLowerLeg: m_RightLowerLeg = value; break;
+ case HumanBodyBones.LeftFoot: m_LeftFoot = value; break;
+ case HumanBodyBones.RightFoot: m_RightFoot = value; break;
+ case HumanBodyBones.LeftToes: m_LeftToes = value; break;
+ case HumanBodyBones.RightToes: m_RightToes = value; break;
+ #endregion
+
+ #region spine
+ case HumanBodyBones.Spine: m_Spine = value; break;
+ case HumanBodyBones.Chest: m_Chest = value; break;
+ case HumanBodyBones.UpperChest: m_UpperChest = value; break;
+ case HumanBodyBones.Neck: m_Neck = value; break;
+ case HumanBodyBones.Head: m_Head = value; break;
+ case HumanBodyBones.LeftEye: m_LeftEye = value; break;
+ case HumanBodyBones.RightEye: m_RightEye = value; break;
+ case HumanBodyBones.Jaw: m_Jaw = value; break;
+ #endregion
+
+ #region arm
+ case HumanBodyBones.LeftShoulder: m_LeftShoulder = value; break;
+ case HumanBodyBones.RightShoulder: m_RightShoulder = value; break;
+ case HumanBodyBones.LeftUpperArm: m_LeftUpperArm = value; break;
+ case HumanBodyBones.RightUpperArm: m_RightUpperArm = value; break;
+ case HumanBodyBones.LeftLowerArm: m_LeftLowerArm = value; break;
+ case HumanBodyBones.RightLowerArm: m_RightLowerArm = value; break;
+ case HumanBodyBones.LeftHand: m_LeftHand = value; break;
+ case HumanBodyBones.RightHand: m_RightHand = value; break;
+ #endregion
+
+ #region fingers
+ case HumanBodyBones.LeftThumbProximal: m_LeftThumbProximal = value; break;
+ case HumanBodyBones.LeftThumbIntermediate: m_LeftThumbIntermediate = value; break;
+ case HumanBodyBones.LeftThumbDistal: m_LeftThumbDistal = value; break;
+ case HumanBodyBones.LeftIndexProximal: m_LeftIndexProximal = value; break;
+ case HumanBodyBones.LeftIndexIntermediate: m_LeftIndexIntermediate = value; break;
+ case HumanBodyBones.LeftIndexDistal: m_LeftIndexDistal = value; break;
+ case HumanBodyBones.LeftMiddleProximal: m_LeftMiddleProximal = value; break;
+ case HumanBodyBones.LeftMiddleIntermediate: m_LeftMiddleIntermediate = value; break;
+ case HumanBodyBones.LeftMiddleDistal: m_LeftMiddleDistal = value; break;
+ case HumanBodyBones.LeftRingProximal: m_LeftRingProximal = value; break;
+ case HumanBodyBones.LeftRingIntermediate: m_LeftRingIntermediate = value; break;
+ case HumanBodyBones.LeftRingDistal: m_LeftRingDistal = value; break;
+ case HumanBodyBones.LeftLittleProximal: m_LeftLittleProximal = value; break;
+ case HumanBodyBones.LeftLittleIntermediate: m_LeftLittleIntermediate = value; break;
+ case HumanBodyBones.LeftLittleDistal: m_LeftLittleDistal = value; break;
+ case HumanBodyBones.RightThumbProximal: m_RightThumbProximal = value; break;
+ case HumanBodyBones.RightThumbIntermediate: m_RightThumbIntermediate = value; break;
+ case HumanBodyBones.RightThumbDistal: m_RightThumbDistal = value; break;
+ case HumanBodyBones.RightIndexProximal: m_RightIndexProximal = value; break;
+ case HumanBodyBones.RightIndexIntermediate: m_RightIndexIntermediate = value; break;
+ case HumanBodyBones.RightIndexDistal: m_RightIndexDistal = value; break;
+ case HumanBodyBones.RightMiddleProximal: m_RightMiddleProximal = value; break;
+ case HumanBodyBones.RightMiddleIntermediate: m_RightMiddleIntermediate = value; break;
+ case HumanBodyBones.RightMiddleDistal: m_RightMiddleDistal = value; break;
+ case HumanBodyBones.RightRingProximal: m_RightRingProximal = value; break;
+ case HumanBodyBones.RightRingIntermediate: m_RightRingIntermediate = value; break;
+ case HumanBodyBones.RightRingDistal: m_RightRingDistal = value; break;
+ case HumanBodyBones.RightLittleProximal: m_RightLittleProximal = value; break;
+ case HumanBodyBones.RightLittleIntermediate: m_RightLittleIntermediate = value; break;
+ case HumanBodyBones.RightLittleDistal: m_RightLittleDistal = value; break;
+ #endregion
+ }
+ }
+ }
+
+ /// <summary>
+ /// Animator から Bone を割り当てる
+ /// </summary>
+ /// <returns></returns>
+ public bool AssignBonesFromAnimator()
+ {
+ var animator = GetComponent<Animator>();
+ if (animator == null)
+ {
+ return false;
+ }
+ var avatar = animator.avatar;
+ if (avatar == null)
+ {
+ return false;
+ }
+ if (!avatar.isValid)
+ {
+ return false;
+ }
+ if (!avatar.isHuman)
+ {
+ return false;
+ }
+
+ var keys = (UnityEngine.HumanBodyBones[])Enum.GetValues(typeof(UnityEngine.HumanBodyBones));
+
+ AssignBones(keys.Select(x =>
+ {
+ if (x == HumanBodyBones.LastBone)
+ {
+ return (HumanBodyBones.LastBone, null);
+ }
+ return ((HumanBodyBones)Enum.Parse(typeof(HumanBodyBones), x.ToString(), true), animator.GetBoneTransform(x));
+ }));
+
+ return true;
+ }
+ }
+}
diff --git a/Assets/ThirdParty/VRM/MeshUtility/Runtime/Humanoid.cs.meta b/Assets/ThirdParty/VRM/MeshUtility/Runtime/Humanoid.cs.meta
new file mode 100644
index 00000000..53fc0f6d
--- /dev/null
+++ b/Assets/ThirdParty/VRM/MeshUtility/Runtime/Humanoid.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 889d98e41c0e8ff48bae50d1a729c2df
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/ThirdParty/VRM/MeshUtility/Runtime/HumanoidLoader.cs b/Assets/ThirdParty/VRM/MeshUtility/Runtime/HumanoidLoader.cs
new file mode 100644
index 00000000..2a5d5252
--- /dev/null
+++ b/Assets/ThirdParty/VRM/MeshUtility/Runtime/HumanoidLoader.cs
@@ -0,0 +1,60 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using UnityEngine;
+
+namespace MeshUtility
+{
+ public static class HumanoidLoader
+ {
+ public static Avatar LoadHumanoidAvatar(Transform root, IEnumerable<(Transform, HumanBodyBones)> boneMap)
+ {
+ var description = new HumanDescription
+ {
+ skeleton = root.GetComponentsInChildren<Transform>()
+ .Select(x => x.ToSkeletonBone()).ToArray(),
+ human = boneMap
+ .Select(x => new HumanBone
+ {
+ boneName = x.Item1.name,
+ humanName = s_humanTranitBoneNameMap[x.Item2],
+ limit = new HumanLimit
+ {
+ useDefaultValues = true,
+ }
+ }).ToArray(),
+
+ armStretch = 0.05f,
+ legStretch = 0.05f,
+ upperArmTwist = 0.5f,
+ lowerArmTwist = 0.5f,
+ upperLegTwist = 0.5f,
+ lowerLegTwist = 0.5f,
+ feetSpacing = 0,
+ hasTranslationDoF = false,
+ };
+
+ return AvatarBuilder.BuildHumanAvatar(root.gameObject, description);
+ }
+
+ static SkeletonBone ToSkeletonBone(this Transform t)
+ {
+ var sb = new SkeletonBone();
+ sb.name = t.name;
+ sb.position = t.localPosition;
+ sb.rotation = t.localRotation;
+ sb.scale = t.localScale;
+ return sb;
+ }
+
+ static HumanBodyBones TraitToHumanBone(string x)
+ {
+ return (HumanBodyBones)Enum.Parse(typeof(HumanBodyBones), x.Replace(" ", ""), true);
+ }
+
+ static readonly Dictionary<HumanBodyBones, string> s_humanTranitBoneNameMap =
+ HumanTrait.BoneName.ToDictionary(
+ x => TraitToHumanBone(x),
+ x => x);
+ }
+}
diff --git a/Assets/ThirdParty/VRM/MeshUtility/Runtime/HumanoidLoader.cs.meta b/Assets/ThirdParty/VRM/MeshUtility/Runtime/HumanoidLoader.cs.meta
new file mode 100644
index 00000000..02965556
--- /dev/null
+++ b/Assets/ThirdParty/VRM/MeshUtility/Runtime/HumanoidLoader.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 12453a111483e4145852e3b057e065d9
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/ThirdParty/VRM/MeshUtility/Runtime/MeshExtensions.cs b/Assets/ThirdParty/VRM/MeshUtility/Runtime/MeshExtensions.cs
new file mode 100644
index 00000000..aa458d52
--- /dev/null
+++ b/Assets/ThirdParty/VRM/MeshUtility/Runtime/MeshExtensions.cs
@@ -0,0 +1,85 @@
+using UnityEngine;
+using System.Linq;
+
+
+namespace MeshUtility
+{
+ public static class MeshExtensions
+ {
+ public static Mesh Copy(this Mesh src, bool copyBlendShape)
+ {
+ var dst = new Mesh();
+ dst.name = src.name + "(copy)";
+#if UNITY_2017_3_OR_NEWER
+ dst.indexFormat = src.indexFormat;
+#endif
+
+ dst.vertices = src.vertices;
+ dst.normals = src.normals;
+ dst.tangents = src.tangents;
+ dst.colors = src.colors;
+ dst.uv = src.uv;
+ dst.uv2 = src.uv2;
+ dst.uv3 = src.uv3;
+ dst.uv4 = src.uv4;
+ dst.boneWeights = src.boneWeights;
+ dst.bindposes = src.bindposes;
+
+ dst.subMeshCount = src.subMeshCount;
+ for (int i = 0; i < dst.subMeshCount; ++i)
+ {
+ dst.SetIndices(src.GetIndices(i), src.GetTopology(i), i);
+ }
+
+ dst.RecalculateBounds();
+
+ if (copyBlendShape)
+ {
+ var vertices = src.vertices;
+ var normals = src.normals;
+#if VRM_NORMALIZE_BLENDSHAPE_TANGENT
+ var tangents = src.tangents.Select(x => (Vector3)x).ToArray();
+#else
+ Vector3[] tangents = null;
+#endif
+
+ for (int i = 0; i < src.blendShapeCount; ++i)
+ {
+ src.GetBlendShapeFrameVertices(i, 0, vertices, normals, tangents);
+ dst.AddBlendShapeFrame(
+ src.GetBlendShapeName(i),
+ src.GetBlendShapeFrameWeight(i, 0),
+ vertices,
+ normals,
+ tangents
+ );
+ }
+ }
+
+ return dst;
+ }
+
+ public static void ApplyRotationAndScale(this Mesh src, Matrix4x4 m)
+ {
+ m.SetColumn(3, new Vector4(0, 0, 0, 1)); // remove translation
+ src.ApplyMatrix(m);
+ }
+
+ public static void ApplyMatrix(this Mesh src, Matrix4x4 m)
+ {
+ src.vertices = src.vertices.Select(x => m.MultiplyPoint(x)).ToArray();
+ if (src.normals != null && src.normals.Length > 0)
+ {
+ src.normals = src.normals.Select(x => m.MultiplyVector(x)).ToArray();
+ }
+ if (src.tangents != null && src.tangents.Length > 0)
+ {
+ src.tangents = src.tangents.Select(x =>
+ {
+ var t = m.MultiplyVector((Vector3)x);
+ return new Vector4(t.x, t.y, t.z, x.w);
+ }).ToArray();
+ }
+ }
+ }
+}
diff --git a/Assets/ThirdParty/VRM/MeshUtility/Runtime/MeshExtensions.cs.meta b/Assets/ThirdParty/VRM/MeshUtility/Runtime/MeshExtensions.cs.meta
new file mode 100644
index 00000000..7485178c
--- /dev/null
+++ b/Assets/ThirdParty/VRM/MeshUtility/Runtime/MeshExtensions.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 4181f0b5e9a271b45b3e995a38202780
+timeCreated: 1532506262
+licenseType: Free
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/ThirdParty/VRM/MeshUtility/Runtime/MeshIntegrationResult.cs b/Assets/ThirdParty/VRM/MeshUtility/Runtime/MeshIntegrationResult.cs
new file mode 100644
index 00000000..91742fc8
--- /dev/null
+++ b/Assets/ThirdParty/VRM/MeshUtility/Runtime/MeshIntegrationResult.cs
@@ -0,0 +1,13 @@
+using System.Collections.Generic;
+using UnityEngine;
+
+namespace MeshUtility
+{
+ [System.Serializable]
+ public class MeshIntegrationResult
+ {
+ public List<SkinnedMeshRenderer> SourceSkinnedMeshRenderers = new List<SkinnedMeshRenderer>();
+ public List<MeshRenderer> SourceMeshRenderers = new List<MeshRenderer>();
+ public SkinnedMeshRenderer IntegratedRenderer;
+ }
+}
diff --git a/Assets/ThirdParty/VRM/MeshUtility/Runtime/MeshIntegrationResult.cs.meta b/Assets/ThirdParty/VRM/MeshUtility/Runtime/MeshIntegrationResult.cs.meta
new file mode 100644
index 00000000..5f32450b
--- /dev/null
+++ b/Assets/ThirdParty/VRM/MeshUtility/Runtime/MeshIntegrationResult.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: e1c66a21d479b3e4a92eedd622d27f4f
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/ThirdParty/VRM/MeshUtility/Runtime/MeshIntegrator.cs b/Assets/ThirdParty/VRM/MeshUtility/Runtime/MeshIntegrator.cs
new file mode 100644
index 00000000..34ba7005
--- /dev/null
+++ b/Assets/ThirdParty/VRM/MeshUtility/Runtime/MeshIntegrator.cs
@@ -0,0 +1,253 @@
+using System.Collections.Generic;
+using System.Linq;
+using UnityEngine;
+
+namespace MeshUtility
+{
+ public class MeshIntegrator
+ {
+ public struct SubMesh
+ {
+ public List<int> Indices;
+ public Material Material;
+ }
+
+ public class BlendShape
+ {
+ public int VertexOffset;
+ public string Name;
+ public float FrameWeight;
+ public Vector3[] Positions;
+ public Vector3[] Normals;
+ public Vector3[] Tangents;
+ }
+
+// public List<SkinnedMeshRenderer> Renderers { get; private set; }
+ public List<Vector3> Positions { get; private set; }
+ public List<Vector3> Normals { get; private set; }
+ public List<Vector2> UV { get; private set; }
+ public List<Vector4> Tangents { get; private set; }
+ public List<BoneWeight> BoneWeights { get; private set; }
+
+ public List<SubMesh> SubMeshes
+ {
+ get;
+ private set;
+ }
+
+ public List<Matrix4x4> BindPoses { get; private set; }
+ public List<Transform> Bones { get; private set; }
+
+ public List<BlendShape> BlendShapes { get; private set; }
+ public void AddBlendShapesToMesh(Mesh mesh)
+ {
+ Dictionary<string, BlendShape> map = new Dictionary<string, BlendShape>();
+
+ foreach (var x in BlendShapes)
+ {
+ BlendShape bs = null;
+ if (!map.TryGetValue(x.Name, out bs))
+ {
+ bs = new BlendShape();
+ bs.Positions = new Vector3[Positions.Count];
+ bs.Normals = new Vector3[Normals.Count];
+ bs.Tangents = new Vector3[Tangents.Count];
+ bs.Name = x.Name;
+ bs.FrameWeight = x.FrameWeight;
+ map.Add(x.Name, bs);
+ }
+
+ var j = x.VertexOffset;
+ for (int i = 0; i < x.Positions.Length; ++i, ++j)
+ {
+ bs.Positions[j] = x.Positions[i];
+ bs.Normals[j] = x.Normals[i];
+ bs.Tangents[j] = x.Tangents[i];
+ }
+ }
+
+ foreach (var kv in map)
+ {
+ //Debug.LogFormat("AddBlendShapeFrame: {0}", kv.Key);
+ mesh.AddBlendShapeFrame(kv.Key, kv.Value.FrameWeight,
+ kv.Value.Positions, kv.Value.Normals, kv.Value.Tangents);
+ }
+ }
+
+ public MeshIntegrator()
+ {
+// Renderers = new List<SkinnedMeshRenderer>();
+
+ Positions = new List<Vector3>();
+ Normals = new List<Vector3>();
+ UV = new List<Vector2>();
+ Tangents = new List<Vector4>();
+ BoneWeights = new List<BoneWeight>();
+
+ SubMeshes = new List<SubMesh>();
+
+ BindPoses = new List<Matrix4x4>();
+ Bones = new List<Transform>();
+
+ BlendShapes = new List<BlendShape>();
+ }
+
+ static BoneWeight AddBoneIndexOffset(BoneWeight bw, int boneIndexOffset)
+ {
+ if (bw.weight0 > 0) bw.boneIndex0 += boneIndexOffset;
+ if (bw.weight1 > 0) bw.boneIndex1 += boneIndexOffset;
+ if (bw.weight2 > 0) bw.boneIndex2 += boneIndexOffset;
+ if (bw.weight3 > 0) bw.boneIndex3 += boneIndexOffset;
+ return bw;
+ }
+
+ public void Push(MeshRenderer renderer)
+ {
+ var meshFilter = renderer.GetComponent<MeshFilter>();
+ if (meshFilter == null)
+ {
+ Debug.LogWarningFormat("{0} has no mesh filter", renderer.name);
+ return;
+ }
+ var mesh = meshFilter.sharedMesh;
+ if (mesh == null)
+ {
+ Debug.LogWarningFormat("{0} has no mesh", renderer.name);
+ return;
+ }
+
+ var indexOffset = Positions.Count;
+ var boneIndexOffset = Bones.Count;
+
+ Positions.AddRange(mesh.vertices
+ .Select(x => renderer.transform.TransformPoint(x))
+ );
+ Normals.AddRange(mesh.normals
+ .Select(x => renderer.transform.TransformVector(x))
+ );
+ UV.AddRange(mesh.uv);
+ Tangents.AddRange(mesh.tangents
+ .Select(t =>
+ {
+ var v = renderer.transform.TransformVector(t.x, t.y, t.z);
+ return new Vector4(v.x, v.y, v.z, t.w);
+ })
+ );
+
+ var self = renderer.transform;
+ var bone = self.parent;
+ if (bone == null)
+ {
+ Debug.LogWarningFormat("{0} is root gameobject.", self.name);
+ return;
+ }
+ var bindpose = bone.worldToLocalMatrix;
+
+ BoneWeights.AddRange(Enumerable.Range(0, mesh.vertices.Length)
+ .Select(x => new BoneWeight()
+ {
+ boneIndex0 = Bones.Count,
+ weight0 = 1,
+ })
+ );
+
+ BindPoses.Add(bindpose);
+ Bones.Add(bone);
+
+ for (int i = 0; i < mesh.subMeshCount; ++i)
+ {
+ var indices = mesh.GetIndices(i).Select(x => x + indexOffset);
+ var mat = renderer.sharedMaterials[i];
+ var sameMaterialSubMeshIndex = SubMeshes.FindIndex(x => ReferenceEquals(x.Material, mat));
+ if (sameMaterialSubMeshIndex >= 0)
+ {
+ SubMeshes[sameMaterialSubMeshIndex].Indices.AddRange(indices);
+ }
+ else
+ {
+ SubMeshes.Add(new SubMesh
+ {
+ Indices = indices.ToList(),
+ Material = mat,
+ });
+ }
+ }
+ }
+
+ public void Push(SkinnedMeshRenderer renderer)
+ {
+ var mesh = renderer.sharedMesh;
+ if (mesh == null)
+ {
+ Debug.LogWarningFormat("{0} has no mesh", renderer.name);
+ return;
+ }
+
+// Renderers.Add(renderer);
+
+ var indexOffset = Positions.Count;
+ var boneIndexOffset = Bones.Count;
+
+ Positions.AddRange(mesh.vertices);
+ Normals.AddRange(mesh.normals);
+ UV.AddRange(mesh.uv);
+ Tangents.AddRange(mesh.tangents);
+
+ if (mesh.vertexCount == mesh.boneWeights.Length)
+ {
+ BoneWeights.AddRange(mesh.boneWeights.Select(x => AddBoneIndexOffset(x, boneIndexOffset)).ToArray());
+ BindPoses.AddRange(mesh.bindposes);
+ Bones.AddRange(renderer.bones);
+ }
+ else
+ {
+ // Bone Count 0 の SkinnedMeshRenderer
+ var rigidBoneWeight = new BoneWeight
+ {
+ boneIndex0 = boneIndexOffset,
+ weight0 = 1f,
+ };
+ BoneWeights.AddRange(Enumerable.Range(0, mesh.vertexCount).Select(x => rigidBoneWeight).ToArray());
+ BindPoses.Add(renderer.transform.localToWorldMatrix);
+ Bones.Add(renderer.transform);
+ }
+
+ for (int i = 0; i < mesh.subMeshCount; ++i)
+ {
+ var indices = mesh.GetIndices(i).Select(x => x + indexOffset);
+ var mat = renderer.sharedMaterials[i];
+ var sameMaterialSubMeshIndex = SubMeshes.FindIndex(x => ReferenceEquals(x.Material, mat));
+ if (sameMaterialSubMeshIndex >= 0)
+ {
+ SubMeshes[sameMaterialSubMeshIndex].Indices.AddRange(indices);
+ }
+ else
+ {
+ SubMeshes.Add(new SubMesh
+ {
+ Indices = indices.ToList(),
+ Material = mat,
+ });
+ }
+ }
+
+ for (int i = 0; i < mesh.blendShapeCount; ++i)
+ {
+ var positions = (Vector3[])mesh.vertices.Clone();
+ var normals = (Vector3[])mesh.normals.Clone();
+ var tangents = mesh.tangents.Select(x => (Vector3)x).ToArray();
+
+ mesh.GetBlendShapeFrameVertices(i, 0, positions, normals, tangents);
+ BlendShapes.Add(new BlendShape
+ {
+ VertexOffset = indexOffset,
+ FrameWeight = mesh.GetBlendShapeFrameWeight(i, 0),
+ Name = mesh.GetBlendShapeName(i),
+ Positions = positions,
+ Normals = normals,
+ Tangents = tangents,
+ });
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/Assets/ThirdParty/VRM/MeshUtility/Runtime/MeshIntegrator.cs.meta b/Assets/ThirdParty/VRM/MeshUtility/Runtime/MeshIntegrator.cs.meta
new file mode 100644
index 00000000..15921c89
--- /dev/null
+++ b/Assets/ThirdParty/VRM/MeshUtility/Runtime/MeshIntegrator.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: 547dd57b50bf4820a570336659345084
+timeCreated: 1560168946 \ No newline at end of file
diff --git a/Assets/ThirdParty/VRM/MeshUtility/Runtime/MeshIntegratorUtility.cs b/Assets/ThirdParty/VRM/MeshUtility/Runtime/MeshIntegratorUtility.cs
new file mode 100644
index 00000000..cfb1742e
--- /dev/null
+++ b/Assets/ThirdParty/VRM/MeshUtility/Runtime/MeshIntegratorUtility.cs
@@ -0,0 +1,140 @@
+using System.Collections.Generic;
+using System.Linq;
+using UnityEngine;
+
+namespace MeshUtility
+{
+ public static class MeshIntegratorUtility
+ {
+ /// <summary>
+ /// go を root としたヒエラルキーから Renderer を集めて、統合された Mesh 作成する
+ /// </summary>
+ /// <param name="go"></param>
+ /// <param name="onlyBlendShapeRenderers">BlendShapeを保持するSkinnedMeshRendererのみ/BlendShapeを保持しないSkinnedMeshRenderer + MeshRenderer</param>
+ /// <returns></returns>
+ public static MeshIntegrationResult Integrate(GameObject go, bool onlyBlendShapeRenderers)
+ {
+ var result = new MeshIntegrationResult();
+
+ var meshNode = new GameObject();
+ if (onlyBlendShapeRenderers)
+ {
+ meshNode.name = "MeshIntegrator(BlendShape)";
+ }
+ else
+ {
+ meshNode.name = "MeshIntegrator";
+ }
+ meshNode.transform.SetParent(go.transform, false);
+
+ // レンダラから情報を集める
+ var integrator = new MeshUtility.MeshIntegrator();
+
+ if (onlyBlendShapeRenderers)
+ {
+ foreach (var x in EnumerateSkinnedMeshRenderer(go.transform, true))
+ {
+ integrator.Push(x);
+ result.SourceSkinnedMeshRenderers.Add(x);
+ }
+ }
+ else
+ {
+ foreach (var x in EnumerateSkinnedMeshRenderer(go.transform, false))
+ {
+ integrator.Push(x);
+ result.SourceSkinnedMeshRenderers.Add(x);
+ }
+
+ foreach (var x in EnumerateMeshRenderer(go.transform))
+ {
+ integrator.Push(x);
+ result.SourceMeshRenderers.Add(x);
+ }
+ }
+
+ var mesh = new Mesh();
+ mesh.name = "integrated";
+
+ if (integrator.Positions.Count > ushort.MaxValue)
+ {
+ Debug.LogFormat("exceed 65535 vertices: {0}", integrator.Positions.Count);
+ mesh.indexFormat = UnityEngine.Rendering.IndexFormat.UInt32;
+ }
+
+ mesh.vertices = integrator.Positions.ToArray();
+ mesh.normals = integrator.Normals.ToArray();
+ mesh.uv = integrator.UV.ToArray();
+ mesh.tangents = integrator.Tangents.ToArray();
+ mesh.boneWeights = integrator.BoneWeights.ToArray();
+ mesh.subMeshCount = integrator.SubMeshes.Count;
+ for (var i = 0; i < integrator.SubMeshes.Count; ++i)
+ {
+ mesh.SetIndices(integrator.SubMeshes[i].Indices.ToArray(), MeshTopology.Triangles, i);
+ }
+ mesh.bindposes = integrator.BindPoses.ToArray();
+
+ if (onlyBlendShapeRenderers)
+ {
+ integrator.AddBlendShapesToMesh(mesh);
+ }
+
+ var integrated = meshNode.AddComponent<SkinnedMeshRenderer>();
+ integrated.sharedMesh = mesh;
+ integrated.sharedMaterials = integrator.SubMeshes.Select(x => x.Material).ToArray();
+ integrated.bones = integrator.Bones.ToArray();
+ result.IntegratedRenderer = integrated;
+
+ return result;
+ }
+
+ public static IEnumerable<SkinnedMeshRenderer> EnumerateSkinnedMeshRenderer(Transform root, bool hasBlendShape)
+ {
+ foreach (var x in Traverse(root))
+ {
+ var renderer = x.GetComponent<SkinnedMeshRenderer>();
+ if (renderer != null &&
+ renderer.gameObject.activeInHierarchy &&
+ renderer.sharedMesh != null &&
+ renderer.enabled &&
+ renderer.sharedMesh.blendShapeCount > 0 == hasBlendShape)
+ {
+ yield return renderer;
+ }
+ }
+ }
+
+ public static IEnumerable<MeshRenderer> EnumerateMeshRenderer(Transform root)
+ {
+ foreach (var x in Traverse(root))
+ {
+ var renderer = x.GetComponent<MeshRenderer>();
+ var filter = x.GetComponent<MeshFilter>();
+
+ if (renderer != null &&
+ filter != null &&
+ renderer.gameObject.activeInHierarchy &&
+ filter.sharedMesh != null)
+ {
+ yield return renderer;
+ }
+ }
+ }
+
+ private static IEnumerable<Transform> Traverse(Transform parent)
+ {
+ if (parent.gameObject.activeSelf)
+ {
+ yield return parent;
+
+ foreach (Transform child in parent)
+ {
+ foreach (var x in Traverse(child))
+ {
+ yield return x;
+ }
+ }
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/Assets/ThirdParty/VRM/MeshUtility/Runtime/MeshIntegratorUtility.cs.meta b/Assets/ThirdParty/VRM/MeshUtility/Runtime/MeshIntegratorUtility.cs.meta
new file mode 100644
index 00000000..b9075e71
--- /dev/null
+++ b/Assets/ThirdParty/VRM/MeshUtility/Runtime/MeshIntegratorUtility.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: a982d9d30c0145038245b0214dc2f2e4
+timeCreated: 1560190306 \ No newline at end of file
diff --git a/Assets/ThirdParty/VRM/MeshUtility/Runtime/MeshUtility.asmdef b/Assets/ThirdParty/VRM/MeshUtility/Runtime/MeshUtility.asmdef
new file mode 100644
index 00000000..f161fcaf
--- /dev/null
+++ b/Assets/ThirdParty/VRM/MeshUtility/Runtime/MeshUtility.asmdef
@@ -0,0 +1,3 @@
+{
+ "name": "MeshUtility"
+}
diff --git a/Assets/ThirdParty/VRM/MeshUtility/Runtime/MeshUtility.asmdef.meta b/Assets/ThirdParty/VRM/MeshUtility/Runtime/MeshUtility.asmdef.meta
new file mode 100644
index 00000000..4085faa9
--- /dev/null
+++ b/Assets/ThirdParty/VRM/MeshUtility/Runtime/MeshUtility.asmdef.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: 71ab1919192903d44971eedbc26b24d1
+AssemblyDefinitionImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/ThirdParty/VRM/MeshUtility/Runtime/UnityExtensions.cs b/Assets/ThirdParty/VRM/MeshUtility/Runtime/UnityExtensions.cs
new file mode 100644
index 00000000..a772980d
--- /dev/null
+++ b/Assets/ThirdParty/VRM/MeshUtility/Runtime/UnityExtensions.cs
@@ -0,0 +1,319 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using UnityEngine;
+#if UNITY_EDITOR
+using UnityEditor;
+#endif
+
+
+namespace MeshUtility
+{
+ public struct PosRot
+ {
+ public Vector3 Position;
+ public Quaternion Rotation;
+
+ public static PosRot FromGlobalTransform(Transform t)
+ {
+ return new PosRot
+ {
+ Position = t.position,
+ Rotation = t.rotation,
+ };
+ }
+ }
+
+ public class BlendShape
+ {
+ public string Name;
+
+ public BlendShape(string name)
+ {
+ Name = name;
+ }
+
+ public List<Vector3> Positions = new List<Vector3>();
+ public List<Vector3> Normals = new List<Vector3>();
+ public List<Vector3> Tangents = new List<Vector3>();
+ }
+
+ public static class UnityExtensions
+ {
+ public static Vector4 ReverseZ(this Vector4 v)
+ {
+ return new Vector4(v.x, v.y, -v.z, v.w);
+ }
+
+ public static Vector3 ReverseZ(this Vector3 v)
+ {
+ return new Vector3(v.x, v.y, -v.z);
+ }
+
+ [Obsolete]
+ public static Vector2 ReverseY(this Vector2 v)
+ {
+ return new Vector2(v.x, -v.y);
+ }
+
+ public static Vector2 ReverseUV(this Vector2 v)
+ {
+ return new Vector2(v.x, 1.0f - v.y);
+ }
+
+ public static Quaternion ReverseZ(this Quaternion q)
+ {
+ float angle;
+ Vector3 axis;
+ q.ToAngleAxis(out angle, out axis);
+ return Quaternion.AngleAxis(-angle, ReverseZ(axis));
+ }
+
+ public static Matrix4x4 Matrix4x4FromColumns(Vector4 c0, Vector4 c1, Vector4 c2, Vector4 c3)
+ {
+#if UNITY_2017_1_OR_NEWER
+ return new Matrix4x4(c0, c1, c2, c3);
+#else
+ var m = default(Matrix4x4);
+ m.SetColumn(0, c0);
+ m.SetColumn(1, c1);
+ m.SetColumn(2, c2);
+ m.SetColumn(3, c3);
+ return m;
+#endif
+ }
+
+ public static Matrix4x4 Matrix4x4FromRotation(Quaternion q)
+ {
+#if UNITY_2017_1_OR_NEWER
+ return Matrix4x4.Rotate(q);
+#else
+ var m = default(Matrix4x4);
+ m.SetTRS(Vector3.zero, q, Vector3.one);
+ return m;
+#endif
+ }
+
+ public static Matrix4x4 ReverseZ(this Matrix4x4 m)
+ {
+ m.SetTRS(m.ExtractPosition().ReverseZ(), m.ExtractRotation().ReverseZ(), m.ExtractScale());
+ return m;
+ }
+
+ public static Matrix4x4 MatrixFromArray(float[] values)
+ {
+ var m = new Matrix4x4();
+ m.m00 = values[0];
+ m.m10 = values[1];
+ m.m20 = values[2];
+ m.m30 = values[3];
+ m.m01 = values[4];
+ m.m11 = values[5];
+ m.m21 = values[6];
+ m.m31 = values[7];
+ m.m02 = values[8];
+ m.m12 = values[9];
+ m.m22 = values[10];
+ m.m32 = values[11];
+ m.m03 = values[12];
+ m.m13 = values[13];
+ m.m23 = values[14];
+ m.m33 = values[15];
+ return m;
+ }
+
+ // https://forum.unity.com/threads/how-to-assign-matrix4x4-to-transform.121966/
+ public static Quaternion ExtractRotation(this Matrix4x4 matrix)
+ {
+ Vector3 forward;
+ forward.x = matrix.m02;
+ forward.y = matrix.m12;
+ forward.z = matrix.m22;
+
+ Vector3 upwards;
+ upwards.x = matrix.m01;
+ upwards.y = matrix.m11;
+ upwards.z = matrix.m21;
+
+ return Quaternion.LookRotation(forward, upwards);
+ }
+
+ public static Vector3 ExtractPosition(this Matrix4x4 matrix)
+ {
+ Vector3 position;
+ position.x = matrix.m03;
+ position.y = matrix.m13;
+ position.z = matrix.m23;
+ return position;
+ }
+
+ public static Vector3 ExtractScale(this Matrix4x4 matrix)
+ {
+ Vector3 scale;
+ scale.x = new Vector4(matrix.m00, matrix.m10, matrix.m20, matrix.m30).magnitude;
+ scale.y = new Vector4(matrix.m01, matrix.m11, matrix.m21, matrix.m31).magnitude;
+ scale.z = new Vector4(matrix.m02, matrix.m12, matrix.m22, matrix.m32).magnitude;
+ return scale;
+ }
+
+ public static string RelativePathFrom(this Transform self, Transform root)
+ {
+ var path = new List<String>();
+ for (var current = self; current != null; current = current.parent)
+ {
+ if (current == root)
+ {
+ return String.Join("/", path.ToArray());
+ }
+
+ path.Insert(0, current.name);
+ }
+
+ throw new Exception("no RelativePath");
+ }
+
+ public static Transform GetChildByName(this Transform self, string childName)
+ {
+ foreach (Transform child in self)
+ {
+ if (child.name == childName)
+ {
+ return child;
+ }
+ }
+
+ throw new KeyNotFoundException();
+ }
+
+ public static Transform GetFromPath(this Transform self, string path)
+ {
+ var current = self;
+
+ var split = path.Split('/');
+
+ foreach (var childName in split)
+ {
+ current = current.GetChildByName(childName);
+ }
+
+ return current;
+ }
+
+ public static IEnumerable<Transform> GetChildren(this Transform self)
+ {
+ foreach (Transform child in self)
+ {
+ yield return child;
+ }
+ }
+
+ public static IEnumerable<Transform> Traverse(this Transform t)
+ {
+ yield return t;
+ foreach (Transform x in t)
+ {
+ foreach (Transform y in x.Traverse())
+ {
+ yield return y;
+ }
+ }
+ }
+
+ [Obsolete("Use FindDescendant(name)")]
+ public static Transform FindDescenedant(this Transform t, string name)
+ {
+ return FindDescendant(t, name);
+ }
+
+ public static Transform FindDescendant(this Transform t, string name)
+ {
+ return t.Traverse().First(x => x.name == name);
+ }
+
+ public static IEnumerable<Transform> Ancestors(this Transform t)
+ {
+ yield return t;
+ if (t.parent != null)
+ {
+ foreach (Transform x in t.parent.Ancestors())
+ {
+ yield return x;
+ }
+ }
+ }
+
+ public static float[] ToArray(this Quaternion q)
+ {
+ return new float[] { q.x, q.y, q.z, q.w };
+ }
+
+ public static float[] ToArray(this Vector3 v)
+ {
+ return new float[] { v.x, v.y, v.z };
+ }
+
+ public static float[] ToArray(this Vector4 v)
+ {
+ return new float[] { v.x, v.y, v.z, v.w };
+ }
+
+ public static float[] ToArray(this Color c)
+ {
+ return new float[] { c.r, c.g, c.b, c.a };
+ }
+
+ public static void ReverseZRecursive(this Transform root)
+ {
+ var globalMap = root.Traverse().ToDictionary(x => x, x => PosRot.FromGlobalTransform(x));
+
+ foreach (var x in root.Traverse())
+ {
+ x.position = globalMap[x].Position.ReverseZ();
+ x.rotation = globalMap[x].Rotation.ReverseZ();
+ }
+ }
+
+ public static Mesh GetSharedMesh(this Transform t)
+ {
+ var meshFilter = t.GetComponent<MeshFilter>();
+ if (meshFilter != null)
+ {
+ return meshFilter.sharedMesh;
+ }
+
+ var skinnedMeshRenderer = t.GetComponent<SkinnedMeshRenderer>();
+ if (skinnedMeshRenderer != null)
+ {
+ return skinnedMeshRenderer.sharedMesh;
+ }
+
+ return null;
+ }
+
+ public static Material[] GetSharedMaterials(this Transform t)
+ {
+ var renderer = t.GetComponent<Renderer>();
+ if (renderer != null)
+ {
+ return renderer.sharedMaterials;
+ }
+
+ return new Material[] { };
+ }
+
+ public static bool Has<T>(this Transform transform, T t) where T : Component
+ {
+ return transform.GetComponent<T>() == t;
+ }
+
+ public static T GetOrAddComponent<T>(this GameObject go) where T : Component
+ {
+ var c = go.GetComponent<T>();
+ if (c != null)
+ {
+ return c;
+ }
+ return go.AddComponent<T>();
+ }
+ }
+}
diff --git a/Assets/ThirdParty/VRM/MeshUtility/Runtime/UnityExtensions.cs.meta b/Assets/ThirdParty/VRM/MeshUtility/Runtime/UnityExtensions.cs.meta
new file mode 100644
index 00000000..07785c58
--- /dev/null
+++ b/Assets/ThirdParty/VRM/MeshUtility/Runtime/UnityExtensions.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 5294813527b3278458026afc820dd63d
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/ThirdParty/VRM/MeshUtility/Runtime/UnityPath.cs b/Assets/ThirdParty/VRM/MeshUtility/Runtime/UnityPath.cs
new file mode 100644
index 00000000..24404741
--- /dev/null
+++ b/Assets/ThirdParty/VRM/MeshUtility/Runtime/UnityPath.cs
@@ -0,0 +1,435 @@
+using System;
+using System.IO;
+using UnityEngine;
+using System.Collections.Generic;
+#if UNITY_EDITOR
+using UnityEditor;
+#endif
+
+
+namespace MeshUtility
+{
+ /// <summary>
+ /// relative path from Unity project root.
+ /// For AssetDatabase.
+ /// </summary>
+ public struct UnityPath
+ {
+ #region UnityPath
+ public string Value
+ {
+ get;
+ private set;
+ }
+
+ public override string ToString()
+ {
+ return string.Format("unity://{0}", Value);
+ }
+
+ public bool IsNull
+ {
+ get { return Value == null; }
+ }
+
+ public bool IsUnderAssetsFolder
+ {
+ get
+ {
+ if (IsNull)
+ {
+ return false;
+ }
+ return Value == "Assets" || Value.StartsWith("Assets/");
+ }
+ }
+
+ public bool IsStreamingAsset
+ {
+ get
+ {
+ if (IsNull)
+ {
+ return false;
+ }
+
+ return FullPath.StartsWith(Application.streamingAssetsPath + "/");
+ }
+ }
+
+ public string FileName
+ {
+ get { return Path.GetFileName(Value); }
+ }
+
+ public string FileNameWithoutExtension
+ {
+ get { return Path.GetFileNameWithoutExtension(Value); }
+ }
+
+ public string Extension
+ {
+ get { return Path.GetExtension(Value); }
+ }
+
+ public UnityPath Parent
+ {
+ get
+ {
+ if (IsNull)
+ {
+ return default(UnityPath);
+ }
+
+ return new UnityPath(Path.GetDirectoryName(Value));
+ }
+ }
+
+ public bool HasParent
+ {
+ get
+ {
+ return !string.IsNullOrEmpty(Value);
+ }
+ }
+
+ static readonly char[] EscapeChars = new char[]
+ {
+ '\\',
+ '/',
+ ':',
+ '*',
+ '?',
+ '"',
+ '<',
+ '>',
+ '|',
+ };
+
+ static string EscapeFilePath(string path)
+ {
+ foreach (var x in EscapeChars)
+ {
+ path = path.Replace(x, '+');
+ }
+ return path;
+ }
+
+ public UnityPath Child(string name)
+ {
+ if (IsNull)
+ {
+ throw new NotImplementedException();
+ }
+ else if (Value == "")
+ {
+ return new UnityPath(name);
+ }
+ else
+ {
+ return new UnityPath(Value + "/" + name);
+ }
+ }
+
+ public override int GetHashCode()
+ {
+ if (IsNull)
+ {
+ return 0;
+ }
+ return Value.GetHashCode();
+ }
+
+ public override bool Equals(object obj)
+ {
+ if(obj is UnityPath)
+ {
+ var rhs = (UnityPath)obj;
+ if(Value==null && rhs.Value == null)
+ {
+ return true;
+ }
+ else if (Value == null)
+ {
+ return false;
+ }
+ else if (rhs.Value == null)
+ {
+ return false;
+ }
+ else
+ {
+ return Value == rhs.Value;
+ }
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ /// <summary>
+ /// Remove extension and add suffix
+ /// </summary>
+ /// <param name="prefabPath"></param>
+ /// <param name="suffix"></param>
+ /// <returns></returns>
+ public UnityPath GetAssetFolder(string suffix)
+ {
+ if (!IsUnderAssetsFolder)
+ {
+ throw new NotImplementedException();
+ }
+
+ return new UnityPath(
+ string.Format("{0}/{1}{2}",
+ Parent.Value,
+ FileNameWithoutExtension,
+ suffix
+ ));
+ }
+
+ UnityPath(string value) : this()
+ {
+ Value = value.Replace("\\", "/");
+ }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="unityPath">Relative from unity current path. GetParent(Application.dataPath)</param>
+ /// <returns></returns>
+ public static UnityPath FromUnityPath(string unityPath)
+ {
+ if (String.IsNullOrEmpty(unityPath))
+ {
+ return new UnityPath
+ {
+ Value=""
+ };
+ }
+ return FromFullpath(Path.GetFullPath(unityPath));
+ }
+ #endregion
+
+ #region FullPath
+ static string s_basePath;
+ static string BaseFullPath
+ {
+ get
+ {
+ if (string.IsNullOrEmpty(s_basePath))
+ {
+ s_basePath = Path.GetFullPath(Application.dataPath + "/..").Replace("\\", "/");
+ }
+ return s_basePath;
+ }
+ }
+
+ static string AssetFullPath
+ {
+ get
+ {
+ return BaseFullPath + "/Assets";
+ }
+ }
+
+ public string FullPath
+ {
+ get
+ {
+ if (IsNull)
+ {
+ throw new NotImplementedException();
+ }
+ return Path.Combine(BaseFullPath, Value).Replace("\\", "/");
+ }
+ }
+
+ public bool IsFileExists
+ {
+ get { return File.Exists(FullPath); }
+ }
+
+ public bool IsDirectoryExists
+ {
+ get { return Directory.Exists(FullPath); }
+ }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="fullPath">C:/path/to/file</param>
+ /// <returns></returns>
+ public static UnityPath FromFullpath(string fullPath)
+ {
+ if(fullPath == null)
+ {
+ fullPath = "";
+ }
+ fullPath = fullPath.Replace("\\", "/");
+
+ if (fullPath == BaseFullPath) {
+ return new UnityPath
+ {
+ Value=""
+ };
+ }
+ else if(fullPath.StartsWith(BaseFullPath + "/"))
+ {
+ return new UnityPath(fullPath.Substring(BaseFullPath.Length + 1));
+ }
+ else
+ {
+ return default(UnityPath);
+ }
+ }
+
+ public static bool IsUnderAssetFolder(string fullPath)
+ {
+ return fullPath.Replace("\\", "/").StartsWith(AssetFullPath);
+ }
+ #endregion
+
+ [Obsolete("Use TraverseDir()")]
+ public IEnumerable<UnityPath> TravserseDir()
+ {
+ return TraverseDir();
+ }
+
+ public IEnumerable<UnityPath> TraverseDir()
+ {
+ if (IsDirectoryExists)
+ {
+ yield return this;
+
+ foreach(var child in ChildDirs)
+ {
+ foreach(var x in child.TraverseDir())
+ {
+ yield return x;
+ }
+ }
+ }
+ }
+
+ public IEnumerable<UnityPath> ChildDirs
+ {
+ get
+ {
+ foreach(var x in Directory.GetDirectories(FullPath))
+ {
+ yield return UnityPath.FromFullpath(x);
+ }
+ }
+ }
+
+ public IEnumerable<UnityPath> ChildFiles
+ {
+ get
+ {
+ foreach (var x in Directory.GetFiles(FullPath))
+ {
+ yield return UnityPath.FromFullpath(x);
+ }
+ }
+ }
+
+#if UNITY_EDITOR
+ public T GetImporter<T>() where T : AssetImporter
+ {
+ return AssetImporter.GetAtPath(Value) as T;
+ }
+
+ public static UnityPath FromAsset(UnityEngine.Object asset)
+ {
+ return new UnityPath(AssetDatabase.GetAssetPath(asset));
+ }
+
+ public void ImportAsset()
+ {
+ if (!IsUnderAssetsFolder)
+ {
+ throw new NotImplementedException();
+ }
+ AssetDatabase.ImportAsset(Value);
+ }
+
+ public void EnsureFolder()
+ {
+ if (IsNull)
+ {
+ throw new NotImplementedException();
+ }
+
+ if (HasParent)
+ {
+ Parent.EnsureFolder();
+ }
+
+ if (!IsDirectoryExists)
+ {
+ var parent = Parent;
+ // ensure parent
+ parent.ImportAsset();
+ // create
+ AssetDatabase.CreateFolder(
+ parent.Value,
+ Path.GetFileName(Value)
+ );
+ ImportAsset();
+ }
+ }
+
+ public UnityEngine.Object[] GetSubAssets()
+ {
+ if (!IsUnderAssetsFolder)
+ {
+ throw new NotImplementedException();
+ }
+
+ return AssetDatabase.LoadAllAssetsAtPath(Value);
+ }
+
+ public void CreateAsset(UnityEngine.Object o)
+ {
+ if (!IsUnderAssetsFolder)
+ {
+ throw new NotImplementedException();
+ }
+
+ AssetDatabase.CreateAsset(o, Value);
+ }
+
+ public void AddObjectToAsset(UnityEngine.Object o)
+ {
+ if (!IsUnderAssetsFolder)
+ {
+ throw new NotImplementedException();
+ }
+
+ AssetDatabase.AddObjectToAsset(o, Value);
+ }
+
+ public T LoadAsset<T>() where T : UnityEngine.Object
+ {
+ if (!IsUnderAssetsFolder)
+ {
+ throw new NotImplementedException();
+ }
+
+ return AssetDatabase.LoadAssetAtPath<T>(Value);
+ }
+
+ public UnityPath GenerateUniqueAssetPath()
+ {
+ if (!IsUnderAssetsFolder)
+ {
+ throw new NotImplementedException();
+ }
+
+ return new UnityPath(AssetDatabase.GenerateUniqueAssetPath(Value));
+ }
+ #endif
+ }
+}
diff --git a/Assets/ThirdParty/VRM/MeshUtility/Runtime/UnityPath.cs.meta b/Assets/ThirdParty/VRM/MeshUtility/Runtime/UnityPath.cs.meta
new file mode 100644
index 00000000..f64923d8
--- /dev/null
+++ b/Assets/ThirdParty/VRM/MeshUtility/Runtime/UnityPath.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 7b7af908694806c469d62ce0b5b2f06a
+timeCreated: 1532326996
+licenseType: Free
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/ThirdParty/VRM/MeshUtility/package.json b/Assets/ThirdParty/VRM/MeshUtility/package.json
new file mode 100644
index 00000000..1bb826ba
--- /dev/null
+++ b/Assets/ThirdParty/VRM/MeshUtility/package.json
@@ -0,0 +1,13 @@
+{
+ "name": "com.vrmc.meshutility",
+ "version": "0.61.0",
+ "displayName": "MeshUtility",
+ "unity": "2018.4",
+ "description": "MeshUtility is a package for mesh separation, etc. \n\nCheck out the latest information here: <https://github.com/vrm-c/UniVRM/tree/master/Assets/MeshUtility>",
+ "keywords": [
+ "mesh"
+ ],
+ "author": {
+ "name": "VRM Consortium"
+ }
+}
diff --git a/Assets/ThirdParty/VRM/MeshUtility/package.json.meta b/Assets/ThirdParty/VRM/MeshUtility/package.json.meta
new file mode 100644
index 00000000..e590e57a
--- /dev/null
+++ b/Assets/ThirdParty/VRM/MeshUtility/package.json.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: 8ae0f09270317494b8fe54cf2858ffc4
+TextScriptImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant: