├── Scripts ├── Chigiri.MeshHoleShrinker.asmdef ├── Chigiri.MeshHoleShrinker.asmdef.meta ├── MeshHoleShrinker.cs.meta └── MeshHoleShrinker.cs ├── README.en.md.meta ├── README.md.meta ├── package.json.meta ├── Editor.meta ├── Materials.meta ├── Prefabs.meta ├── Prefabs ├── MeshHoleShrinker.prefab.meta ├── Internal │ ├── MeshSnapshot.prefab.meta │ └── MeshSnapshot.prefab ├── Internal.meta ├── Presets.meta ├── Presets │ ├── MeshHoleShrinker-Almond-1.01.prefab.meta │ ├── MeshHoleShrinker-Maple-1.1.prefab.meta │ ├── MeshHoleShrinker-Machina-1.3-PC.prefab.meta │ ├── MeshHoleShrinker-Mimino-1.0.1.prefab.meta │ ├── MeshHoleShrinker-Machina-1.3-PC.prefab │ ├── MeshHoleShrinker-Maple-1.1.prefab │ ├── MeshHoleShrinker-Mimino-1.0.1.prefab │ └── MeshHoleShrinker-Almond-1.01.prefab └── MeshHoleShrinker.prefab ├── Scripts.meta ├── Editor ├── Chigiri.MeshHoleShrinker.Editor.asmdef.meta ├── Chigiri.MeshHoleShrinker.Editor.asmdef ├── Helper.cs.meta ├── MeshHoleShrinkerEditor.cs.meta ├── Helper.cs └── MeshHoleShrinkerEditor.cs ├── Materials ├── MeshHoleShrinker.UI.mat.meta └── MeshHoleShrinker.UI.mat ├── package.json ├── .gitignore ├── LICENSE ├── README.en.md ├── .github └── workflows │ └── main.yml ├── .gitattributes └── README.md /Scripts/Chigiri.MeshHoleShrinker.asmdef: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Chigiri.MeshHoleShrinker.Scripts" 3 | } 4 | -------------------------------------------------------------------------------- /README.en.md.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 99e76a2be4a35c94eb251933786ba944 3 | TextScriptImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /README.md.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 37f1329168a2d2946803555febebe7c0 3 | TextScriptImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /package.json.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 1367bdb30776cce4abb00136401145f2 3 | TextScriptImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Editor.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 22a9843e1a5cd9a4ebf31d73601dfa53 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Materials.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: f7f61cd68332e804da9121713d541800 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Prefabs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 227b2414a81a0dc44ac656bab388bb57 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Prefabs/MeshHoleShrinker.prefab.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 272fdb9e09fc6d34e89748854b0ff3a1 3 | PrefabImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Scripts.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: ae8093b0aa0d66647a06205669e6ec0f 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Prefabs/Internal/MeshSnapshot.prefab.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 9dc0aa4daff5a7d4a8485a8dd6379648 3 | PrefabImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Prefabs/Internal.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 7715e123b602d2e4fbf1c35b1e6d0984 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Prefabs/Presets.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 447ced0d2eebef043b28b8e3d87f55e3 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Prefabs/Presets/MeshHoleShrinker-Almond-1.01.prefab.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 07071ea3309488e43a8e5c15da372fb2 3 | PrefabImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Prefabs/Presets/MeshHoleShrinker-Maple-1.1.prefab.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: ba89042257d96f840a1d2f5abd0fdadb 3 | PrefabImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Scripts/Chigiri.MeshHoleShrinker.asmdef.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 3bbe340ba59407943ac66cb45470343a 3 | AssemblyDefinitionImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Prefabs/Presets/MeshHoleShrinker-Machina-1.3-PC.prefab.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: bbdf2b70a273fa5498002ddbf493f703 3 | PrefabImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Prefabs/Presets/MeshHoleShrinker-Mimino-1.0.1.prefab.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: bc05a68d5379abd4db4931bf594a9dc9 3 | PrefabImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Editor/Chigiri.MeshHoleShrinker.Editor.asmdef.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 2a740655039f6374dbb0b161921d3eb7 3 | AssemblyDefinitionImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Materials/MeshHoleShrinker.UI.mat.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 9165404ef7a7fb84e8106f0244a53911 3 | NativeFormatImporter: 4 | externalObjects: {} 5 | mainObjectFileID: 0 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Editor/Chigiri.MeshHoleShrinker.Editor.asmdef: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Chigiri.MeshHoleShrinker.Editor", 3 | "references": [ 4 | "Chigiri.MeshHoleShrinker.Scripts" 5 | ], 6 | "includePlatforms": [ 7 | "Editor" 8 | ], 9 | "autoReferenced": true 10 | } 11 | -------------------------------------------------------------------------------- /Editor/Helper.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 70b21e4d9a922804490770826bafe209 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Scripts/MeshHoleShrinker.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 0b5c7d26826d9f54a827fb75ec24aaaa 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Editor/MeshHoleShrinkerEditor.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: a5fd92df7e00dce4194465e6ab05c7e2 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "com.github.chigirits.meshholeshrinker", 3 | "displayName": "MeshHoleShrinker", 4 | "version": "1.2.1", 5 | "unity": "2019.4", 6 | "description": "Create a new shape key to shrink the hole on your mesh.", 7 | "keywords": ["mesh", "blendshape"], 8 | "category": "Utility", 9 | "dependencies": {}, 10 | "author": { "name": "Chigiri Tsutsumi", "email": "chigirits@gmail.com", "url": "https://twitter.com/chigiri_vrc" }, 11 | "license": "MIT", 12 | "private": true 13 | } 14 | -------------------------------------------------------------------------------- /Scripts/MeshHoleShrinker.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | 3 | namespace Chigiri.MeshHoleShrinker 4 | { 5 | 6 | public class MeshHoleShrinker : MonoBehaviour 7 | { 8 | public SkinnedMeshRenderer targetRenderer; 9 | public Mesh sourceMesh; 10 | public string newName = "shrink_hole"; 11 | public float scale = 0.5f; 12 | public Vector3 offset = Vector3.zero; 13 | public float epsilon = 1e-3f; 14 | public bool useMeshCollider = false; 15 | public GameObject meshSnapshotPrefab; 16 | 17 | public string _lastSavedPath; 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | [Ll]ibrary/ 2 | [Tt]emp/ 3 | [Oo]bj/ 4 | [Bb]uild/ 5 | [Bb]uilds/ 6 | [Ll]ogs/ 7 | 8 | # Uncomment this line if you wish to ignore the asset store tools plugin 9 | # [Aa]ssets/AssetStoreTools* 10 | 11 | # Visual Studio cache directory 12 | .vs/ 13 | 14 | # Gradle cache directory 15 | .gradle/ 16 | 17 | # Autogenerated VS/MD/Consulo solution and project files 18 | ExportedObj/ 19 | .consulo/ 20 | *.csproj 21 | *.unityproj 22 | *.sln 23 | *.suo 24 | *.tmp 25 | *.user 26 | *.userprefs 27 | *.pidb 28 | *.booproj 29 | *.svd 30 | *.pdb 31 | *.mdb 32 | *.opendb 33 | *.VC.db 34 | 35 | # Unity3D generated meta files 36 | *.pidb.meta 37 | *.pdb.meta 38 | *.mdb.meta 39 | 40 | # Unity3D generated file on crash reports 41 | sysinfo.txt 42 | 43 | # Builds 44 | *.apk 45 | *.unitypackage 46 | 47 | # Crashlytics generated file 48 | crashlytics-build.properties 49 | 50 | ## 51 | 52 | LICENSE.meta 53 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2020 TSUTSUMI Chigiri 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 14 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 15 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 16 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 17 | DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 18 | OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE 19 | OR OTHER DEALINGS IN THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /README.en.md: -------------------------------------------------------------------------------- 1 | # MeshHoleShrinker 2 | 3 | A Unity editor extension that adds a shape key to shrink a hole in a mesh and save it as a new mesh. 4 | 5 | This is useful in Unity for filling in the gaps at the joint between your avatar's head and the other model's body. 6 | 7 | ![demo](https://repository-images.githubusercontent.com/295406109/a2eb0680-f6d5-11ea-9672-da464eeef28f) 8 | 9 | ## Required Environment 10 | 11 | Unity 2018.4 or later 12 | 13 | ## How to Import 14 | 15 | ### By .unitypackage file 16 | 17 | Download the latest version of `MeshHoleShrinker-vX.X.X.unitypackage` from [Releases page](https://github.com/chigirits/MeshHoleShrinker/releases) and import it into your Unity project. 18 | 19 | ### By Unity Package Manager 20 | 21 | 1. Open `Packages/manifest.json` in your Unity project with a text editor. 22 | 2. Add the following key-value to the object `dependencies`. 23 | 24 | ``` 25 | "com.github.chigirits.MeshHoleShrinker": "https://github.com/chigirits/MeshHoleShrinker.git", 26 | ``` 27 | 28 | In this case, look for the prefabs and presets shown in the following descriptions from `Packages/MeshHoleShrinker/Assets/Chigiri/MeshHoleShrinker/...`, not from `Assets/Chigiri/MeshHoleShrinker/...`. 29 | 30 | ## Usage 31 | 32 | 1. Place an avatar in the scene and hide all but the head. 33 | 2. Selecting "Chigiri/Create MeshHoleShrinker" from the menu places a MeshHoleShrinker in the top level of the hierarchy. Some [presets](#Presets) for avatars sold at Booth are available. 34 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | tags: 6 | - 'v*' 7 | 8 | jobs: 9 | build: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - name: Setenv 13 | run: | 14 | echo "::set-env name=RELEASE_VERSION::$(echo ${GITHUB_REF#refs/tags/})" 15 | 16 | - name: Checkout 17 | uses: actions/checkout@v2 18 | 19 | - name: Prepare Build 20 | run: | 21 | mkdir -p project/Assets/Chigiri/MeshHoleShrinker build 22 | cp -a {Editor,Materials,Prefabs,Scripts,README.md}{,.meta} LICENSE project/Assets/Chigiri/MeshHoleShrinker/ 23 | 24 | cat <project/Assets/Chigiri.meta 25 | fileFormatVersion: 2 26 | guid: e9cc3dda85f79b140bbf7d079362bf77 27 | folderAsset: yes 28 | DefaultImporter: 29 | externalObjects: {} 30 | userData: 31 | assetBundleName: 32 | assetBundleVariant: 33 | EOT 34 | 35 | cat <project/Assets/Chigiri/MeshHoleShrinker.meta 36 | fileFormatVersion: 2 37 | guid: e9cc3dda85f79b140bbf7d079362bf77 38 | folderAsset: yes 39 | DefaultImporter: 40 | externalObjects: {} 41 | userData: 42 | assetBundleName: 43 | assetBundleVariant: 44 | EOT 45 | 46 | cat <project/Assets/Chigiri/MeshHoleShrinker/LICENSE.meta 47 | fileFormatVersion: 2 48 | guid: 71caf702a2804744998175de7cd24991 49 | DefaultImporter: 50 | externalObjects: {} 51 | userData: 52 | assetBundleName: 53 | assetBundleVariant: 54 | EOT 55 | 56 | cd project 57 | find Assets -name \*.meta > ../metaList 58 | cd .. 59 | 60 | - name: create-unitypackage 61 | uses: pCYSl5EDgo/create-unitypackage@v1 62 | with: 63 | project-folder: ./project/ 64 | package-path: build/MeshHoleShrinker-${{ env.RELEASE_VERSION }}.unitypackage 65 | include-files: metaList 66 | 67 | - name: Upload artifact 68 | uses: actions/upload-artifact@v1.0.0 69 | with: 70 | name: unitypackage 71 | path: build/MeshHoleShrinker-${{ env.RELEASE_VERSION }}.unitypackage 72 | 73 | - name: Release 74 | uses: fnkr/github-action-ghr@v1 75 | if: | 76 | !contains(github.ref, '-') 77 | env: 78 | GHR_PATH: build/MeshHoleShrinker-${{ env.RELEASE_VERSION }}.unitypackage 79 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 80 | -------------------------------------------------------------------------------- /Materials/MeshHoleShrinker.UI.mat: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!21 &2100000 4 | Material: 5 | serializedVersion: 6 6 | m_ObjectHideFlags: 0 7 | m_CorrespondingSourceObject: {fileID: 0} 8 | m_PrefabInstance: {fileID: 0} 9 | m_PrefabAsset: {fileID: 0} 10 | m_Name: MeshHoleShrinker.UI 11 | m_Shader: {fileID: 10760, guid: 0000000000000000f000000000000000, type: 0} 12 | m_ShaderKeywords: _ALPHAPREMULTIPLY_ON _GLOSSYREFLECTIONS_OFF _SPECULARHIGHLIGHTS_OFF 13 | m_LightmapFlags: 6 14 | m_EnableInstancingVariants: 0 15 | m_DoubleSidedGI: 0 16 | m_CustomRenderQueue: -1 17 | stringTagMap: {} 18 | disabledShaderPasses: [] 19 | m_SavedProperties: 20 | serializedVersion: 3 21 | m_TexEnvs: 22 | - _BumpMap: 23 | m_Texture: {fileID: 0} 24 | m_Scale: {x: 1, y: 1} 25 | m_Offset: {x: 0, y: 0} 26 | - _DetailAlbedoMap: 27 | m_Texture: {fileID: 0} 28 | m_Scale: {x: 1, y: 1} 29 | m_Offset: {x: 0, y: 0} 30 | - _DetailMask: 31 | m_Texture: {fileID: 0} 32 | m_Scale: {x: 1, y: 1} 33 | m_Offset: {x: 0, y: 0} 34 | - _DetailNormalMap: 35 | m_Texture: {fileID: 0} 36 | m_Scale: {x: 1, y: 1} 37 | m_Offset: {x: 0, y: 0} 38 | - _EmissionMap: 39 | m_Texture: {fileID: 0} 40 | m_Scale: {x: 1, y: 1} 41 | m_Offset: {x: 0, y: 0} 42 | - _MainTex: 43 | m_Texture: {fileID: 0} 44 | m_Scale: {x: 1, y: 1} 45 | m_Offset: {x: 0, y: 0} 46 | - _MetallicGlossMap: 47 | m_Texture: {fileID: 0} 48 | m_Scale: {x: 1, y: 1} 49 | m_Offset: {x: 0, y: 0} 50 | - _OcclusionMap: 51 | m_Texture: {fileID: 0} 52 | m_Scale: {x: 1, y: 1} 53 | m_Offset: {x: 0, y: 0} 54 | - _ParallaxMap: 55 | m_Texture: {fileID: 0} 56 | m_Scale: {x: 1, y: 1} 57 | m_Offset: {x: 0, y: 0} 58 | m_Floats: 59 | - _BumpScale: 1 60 | - _ColorMask: 15 61 | - _Cutoff: 0.5 62 | - _DetailNormalMapScale: 1 63 | - _DstBlend: 10 64 | - _GlossMapScale: 1 65 | - _Glossiness: 0 66 | - _GlossyReflections: 0 67 | - _Metallic: 0 68 | - _Mode: 3 69 | - _OcclusionStrength: 1 70 | - _Parallax: 0.02 71 | - _SmoothnessTextureChannel: 0 72 | - _SpecularHighlights: 0 73 | - _SrcBlend: 1 74 | - _Stencil: 0 75 | - _StencilComp: 8 76 | - _StencilOp: 0 77 | - _StencilReadMask: 255 78 | - _StencilWriteMask: 255 79 | - _UVSec: 0 80 | - _UseUIAlphaClip: 0 81 | - _ZWrite: 0 82 | m_Colors: 83 | - _Color: {r: 0, g: 1, b: 0.7529412, a: 0.2509804} 84 | - _EmissionColor: {r: 0, g: 0, b: 0, a: 1} 85 | -------------------------------------------------------------------------------- /Editor/Helper.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | using UnityEngine; 4 | using System.Text.RegularExpressions; 5 | 6 | public class Helper 7 | { 8 | 9 | public static string Chomp(string s) 10 | { 11 | if (s.EndsWith("\n")) return s.Substring(0, s.Length - 1); 12 | return s; 13 | } 14 | 15 | public static string SanitizeFileName(string name) 16 | { 17 | var reg = new Regex("[\\/:\\*\\?<>\\|\\\"]"); 18 | return reg.Replace(name, "_"); 19 | } 20 | 21 | // From https://forum.unity.com/threads/bakemesh-scales-wrong.442212/#post-2860559 22 | public static Mesh GetPosedMesh(SkinnedMeshRenderer skin, Mesh mesh) 23 | { 24 | float epsilon = 0.00001f; 25 | var vertices = mesh.vertices; 26 | var newVertices = new Vector3[vertices.Length]; 27 | 28 | for (int i = 0; i < vertices.Length; i++) 29 | { 30 | var w = mesh.boneWeights[i]; 31 | 32 | if (epsilon < Mathf.Abs(w.weight0)) 33 | { 34 | var p = mesh.bindposes[w.boneIndex0].MultiplyPoint3x4(vertices[i]); 35 | var q = skin.bones[w.boneIndex0].transform.localToWorldMatrix.MultiplyPoint3x4(p); 36 | newVertices[i] += skin.transform.InverseTransformPoint(q) * w.weight0; 37 | } 38 | if (epsilon < Mathf.Abs(w.weight1)) 39 | { 40 | var p = mesh.bindposes[w.boneIndex1].MultiplyPoint3x4(vertices[i]); 41 | var q = skin.bones[w.boneIndex1].transform.localToWorldMatrix.MultiplyPoint3x4(p); 42 | newVertices[i] += skin.transform.InverseTransformPoint(q) * w.weight1; 43 | } 44 | if (epsilon < Mathf.Abs(w.weight2)) 45 | { 46 | var p = mesh.bindposes[w.boneIndex2].MultiplyPoint3x4(vertices[i]); 47 | var q = skin.bones[w.boneIndex2].transform.localToWorldMatrix.MultiplyPoint3x4(p); 48 | newVertices[i] += skin.transform.InverseTransformPoint(q) * w.weight2; 49 | } 50 | if (epsilon < Mathf.Abs(w.weight3)) 51 | { 52 | var p = mesh.bindposes[w.boneIndex3].MultiplyPoint3x4(vertices[i]); 53 | var q = skin.bones[w.boneIndex3].transform.localToWorldMatrix.MultiplyPoint3x4(p); 54 | newVertices[i] += skin.transform.InverseTransformPoint(q) * w.weight3; 55 | } 56 | } 57 | 58 | var result = new Mesh(); 59 | result.vertices = newVertices; 60 | result.triangles = skin.sharedMesh.triangles; 61 | result.RecalculateBounds(); 62 | return result; 63 | } 64 | 65 | } 66 | -------------------------------------------------------------------------------- /Prefabs/Presets/MeshHoleShrinker-Machina-1.3-PC.prefab: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!1001 &3091149302252960243 4 | PrefabInstance: 5 | m_ObjectHideFlags: 0 6 | serializedVersion: 2 7 | m_Modification: 8 | m_TransformParent: {fileID: 0} 9 | m_Modifications: 10 | - target: {fileID: 2513171326369980129, guid: 272fdb9e09fc6d34e89748854b0ff3a1, 11 | type: 3} 12 | propertyPath: m_Name 13 | value: MeshHoleShrinker 14 | objectReference: {fileID: 0} 15 | - target: {fileID: 2513171326369980131, guid: 272fdb9e09fc6d34e89748854b0ff3a1, 16 | type: 3} 17 | propertyPath: m_LocalPosition.x 18 | value: 0 19 | objectReference: {fileID: 0} 20 | - target: {fileID: 2513171326369980131, guid: 272fdb9e09fc6d34e89748854b0ff3a1, 21 | type: 3} 22 | propertyPath: m_LocalPosition.y 23 | value: 1.1775 24 | objectReference: {fileID: 0} 25 | - target: {fileID: 2513171326369980131, guid: 272fdb9e09fc6d34e89748854b0ff3a1, 26 | type: 3} 27 | propertyPath: m_LocalPosition.z 28 | value: -0.0207 29 | objectReference: {fileID: 0} 30 | - target: {fileID: 2513171326369980131, guid: 272fdb9e09fc6d34e89748854b0ff3a1, 31 | type: 3} 32 | propertyPath: m_LocalRotation.x 33 | value: 0.12615569 34 | objectReference: {fileID: 0} 35 | - target: {fileID: 2513171326369980131, guid: 272fdb9e09fc6d34e89748854b0ff3a1, 36 | type: 3} 37 | propertyPath: m_LocalRotation.y 38 | value: 0 39 | objectReference: {fileID: 0} 40 | - target: {fileID: 2513171326369980131, guid: 272fdb9e09fc6d34e89748854b0ff3a1, 41 | type: 3} 42 | propertyPath: m_LocalRotation.z 43 | value: 0 44 | objectReference: {fileID: 0} 45 | - target: {fileID: 2513171326369980131, guid: 272fdb9e09fc6d34e89748854b0ff3a1, 46 | type: 3} 47 | propertyPath: m_LocalRotation.w 48 | value: 0.9920105 49 | objectReference: {fileID: 0} 50 | - target: {fileID: 2513171326369980131, guid: 272fdb9e09fc6d34e89748854b0ff3a1, 51 | type: 3} 52 | propertyPath: m_RootOrder 53 | value: 0 54 | objectReference: {fileID: 0} 55 | - target: {fileID: 2513171326369980131, guid: 272fdb9e09fc6d34e89748854b0ff3a1, 56 | type: 3} 57 | propertyPath: m_LocalEulerAnglesHint.x 58 | value: 14.495 59 | objectReference: {fileID: 0} 60 | - target: {fileID: 2513171326369980131, guid: 272fdb9e09fc6d34e89748854b0ff3a1, 61 | type: 3} 62 | propertyPath: m_LocalEulerAnglesHint.y 63 | value: 0 64 | objectReference: {fileID: 0} 65 | - target: {fileID: 2513171326369980131, guid: 272fdb9e09fc6d34e89748854b0ff3a1, 66 | type: 3} 67 | propertyPath: m_LocalEulerAnglesHint.z 68 | value: 0 69 | objectReference: {fileID: 0} 70 | - target: {fileID: 2513171326369980131, guid: 272fdb9e09fc6d34e89748854b0ff3a1, 71 | type: 3} 72 | propertyPath: m_LocalScale.x 73 | value: 0.07178226 74 | objectReference: {fileID: 0} 75 | - target: {fileID: 2513171326369980131, guid: 272fdb9e09fc6d34e89748854b0ff3a1, 76 | type: 3} 77 | propertyPath: m_LocalScale.z 78 | value: 0.079608 79 | objectReference: {fileID: 0} 80 | m_RemovedComponents: [] 81 | m_SourcePrefab: {fileID: 100100000, guid: 272fdb9e09fc6d34e89748854b0ff3a1, type: 3} 82 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # * text=auto 2 | 3 | # Unity files 4 | *.meta -text merge=unityyamlmerge diff 5 | *.unity -text merge=unityyamlmerge diff 6 | *.asset -text merge=unityyamlmerge diff 7 | *.prefab -text merge=unityyamlmerge diff 8 | *.mat -text merge=unityyamlmerge diff 9 | *.anim -text merge=unityyamlmerge diff 10 | *.controller -text merge=unityyamlmerge diff 11 | *.overrideController -text merge=unityyamlmerge diff 12 | *.physicMaterial -text merge=unityyamlmerge diff 13 | *.physicsMaterial2D -text merge=unityyamlmerge diff 14 | *.playable -text merge=unityyamlmerge diff 15 | *.mask -text merge=unityyamlmerge diff 16 | *.brush -text merge=unityyamlmerge diff 17 | *.flare -text merge=unityyamlmerge diff 18 | *.fontsettings -text merge=unityyamlmerge diff 19 | *.guiskin -text merge=unityyamlmerge diff 20 | *.giparams -text merge=unityyamlmerge diff 21 | *.renderTexture -text merge=unityyamlmerge diff 22 | *.spriteatlas -text merge=unityyamlmerge diff 23 | *.terrainlayer -text merge=unityyamlmerge diff 24 | *.mixer -text merge=unityyamlmerge diff 25 | *.shadervariants -text merge=unityyamlmerge diff 26 | 27 | # Image formats 28 | *.psd filter=lfs diff=lfs merge=lfs -text 29 | *.jpg filter=lfs diff=lfs merge=lfs -text 30 | *.png filter=lfs diff=lfs merge=lfs -text 31 | *.gif filter=lfs diff=lfs merge=lfs -text 32 | *.bmp filter=lfs diff=lfs merge=lfs -text 33 | *.tga filter=lfs diff=lfs merge=lfs -text 34 | *.tiff filter=lfs diff=lfs merge=lfs -text 35 | *.tif filter=lfs diff=lfs merge=lfs -text 36 | *.iff filter=lfs diff=lfs merge=lfs -text 37 | *.pict filter=lfs diff=lfs merge=lfs -text 38 | *.dds filter=lfs diff=lfs merge=lfs -text 39 | *.xcf filter=lfs diff=lfs merge=lfs -text 40 | 41 | # Audio formats 42 | *.mp3 filter=lfs diff=lfs merge=lfs -text 43 | *.ogg filter=lfs diff=lfs merge=lfs -text 44 | *.wav filter=lfs diff=lfs merge=lfs -text 45 | *.aiff filter=lfs diff=lfs merge=lfs -text 46 | *.aif filter=lfs diff=lfs merge=lfs -text 47 | *.mod filter=lfs diff=lfs merge=lfs -text 48 | *.it filter=lfs diff=lfs merge=lfs -text 49 | *.s3m filter=lfs diff=lfs merge=lfs -text 50 | *.xm filter=lfs diff=lfs merge=lfs -text 51 | 52 | # Video formats 53 | *.mov filter=lfs diff=lfs merge=lfs -text 54 | *.avi filter=lfs diff=lfs merge=lfs -text 55 | *.asf filter=lfs diff=lfs merge=lfs -text 56 | *.mpg filter=lfs diff=lfs merge=lfs -text 57 | *.mpeg filter=lfs diff=lfs merge=lfs -text 58 | *.mp4 filter=lfs diff=lfs merge=lfs -text 59 | 60 | # 3D formats 61 | *.fbx filter=lfs diff=lfs merge=lfs -text 62 | *.obj filter=lfs diff=lfs merge=lfs -text 63 | *.max filter=lfs diff=lfs merge=lfs -text 64 | *.blend filter=lfs diff=lfs merge=lfs -text 65 | *.dae filter=lfs diff=lfs merge=lfs -text 66 | *.mb filter=lfs diff=lfs merge=lfs -text 67 | *.ma filter=lfs diff=lfs merge=lfs -text 68 | *.3ds filter=lfs diff=lfs merge=lfs -text 69 | *.dfx filter=lfs diff=lfs merge=lfs -text 70 | *.c4d filter=lfs diff=lfs merge=lfs -text 71 | *.lwo filter=lfs diff=lfs merge=lfs -text 72 | *.lwo2 filter=lfs diff=lfs merge=lfs -text 73 | *.abc filter=lfs diff=lfs merge=lfs -text 74 | *.3dm filter=lfs diff=lfs merge=lfs -text 75 | 76 | # Build 77 | *.dll filter=lfs diff=lfs merge=lfs -text 78 | *.pdb filter=lfs diff=lfs merge=lfs -text 79 | *.mdb filter=lfs diff=lfs merge=lfs -text 80 | 81 | # Packaging 82 | *.zip filter=lfs diff=lfs merge=lfs -text 83 | *.7z filter=lfs diff=lfs merge=lfs -text 84 | *.gz filter=lfs diff=lfs merge=lfs -text 85 | *.rar filter=lfs diff=lfs merge=lfs -text 86 | *.tar filter=lfs diff=lfs merge=lfs -text 87 | -------------------------------------------------------------------------------- /Prefabs/Presets/MeshHoleShrinker-Maple-1.1.prefab: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!1001 &9163831318957819997 4 | PrefabInstance: 5 | m_ObjectHideFlags: 0 6 | serializedVersion: 2 7 | m_Modification: 8 | m_TransformParent: {fileID: 0} 9 | m_Modifications: 10 | - target: {fileID: 0} 11 | propertyPath: targetMesh 12 | value: 13 | objectReference: {fileID: 0} 14 | - target: {fileID: 2513171326369980129, guid: 272fdb9e09fc6d34e89748854b0ff3a1, 15 | type: 3} 16 | propertyPath: m_Name 17 | value: MeshHoleShrinker-Maple-1.1 18 | objectReference: {fileID: 0} 19 | - target: {fileID: 2513171326369980131, guid: 272fdb9e09fc6d34e89748854b0ff3a1, 20 | type: 3} 21 | propertyPath: m_LocalPosition.x 22 | value: 0 23 | objectReference: {fileID: 0} 24 | - target: {fileID: 2513171326369980131, guid: 272fdb9e09fc6d34e89748854b0ff3a1, 25 | type: 3} 26 | propertyPath: m_LocalPosition.y 27 | value: 1.019 28 | objectReference: {fileID: 0} 29 | - target: {fileID: 2513171326369980131, guid: 272fdb9e09fc6d34e89748854b0ff3a1, 30 | type: 3} 31 | propertyPath: m_LocalPosition.z 32 | value: 0.0014 33 | objectReference: {fileID: 0} 34 | - target: {fileID: 2513171326369980131, guid: 272fdb9e09fc6d34e89748854b0ff3a1, 35 | type: 3} 36 | propertyPath: m_LocalRotation.x 37 | value: 0.17025805 38 | objectReference: {fileID: 0} 39 | - target: {fileID: 2513171326369980131, guid: 272fdb9e09fc6d34e89748854b0ff3a1, 40 | type: 3} 41 | propertyPath: m_LocalRotation.y 42 | value: -0 43 | objectReference: {fileID: 0} 44 | - target: {fileID: 2513171326369980131, guid: 272fdb9e09fc6d34e89748854b0ff3a1, 45 | type: 3} 46 | propertyPath: m_LocalRotation.z 47 | value: -0 48 | objectReference: {fileID: 0} 49 | - target: {fileID: 2513171326369980131, guid: 272fdb9e09fc6d34e89748854b0ff3a1, 50 | type: 3} 51 | propertyPath: m_LocalRotation.w 52 | value: 0.98539954 53 | objectReference: {fileID: 0} 54 | - target: {fileID: 2513171326369980131, guid: 272fdb9e09fc6d34e89748854b0ff3a1, 55 | type: 3} 56 | propertyPath: m_RootOrder 57 | value: 0 58 | objectReference: {fileID: 0} 59 | - target: {fileID: 2513171326369980131, guid: 272fdb9e09fc6d34e89748854b0ff3a1, 60 | type: 3} 61 | propertyPath: m_LocalEulerAnglesHint.x 62 | value: 19.606 63 | objectReference: {fileID: 0} 64 | - target: {fileID: 2513171326369980131, guid: 272fdb9e09fc6d34e89748854b0ff3a1, 65 | type: 3} 66 | propertyPath: m_LocalEulerAnglesHint.y 67 | value: 0 68 | objectReference: {fileID: 0} 69 | - target: {fileID: 2513171326369980131, guid: 272fdb9e09fc6d34e89748854b0ff3a1, 70 | type: 3} 71 | propertyPath: m_LocalEulerAnglesHint.z 72 | value: 0 73 | objectReference: {fileID: 0} 74 | - target: {fileID: 2513171326369980131, guid: 272fdb9e09fc6d34e89748854b0ff3a1, 75 | type: 3} 76 | propertyPath: m_LocalScale.z 77 | value: 0.06306246 78 | objectReference: {fileID: 0} 79 | - target: {fileID: 2513171326369980131, guid: 272fdb9e09fc6d34e89748854b0ff3a1, 80 | type: 3} 81 | propertyPath: m_LocalScale.x 82 | value: 0.048763815 83 | objectReference: {fileID: 0} 84 | m_RemovedComponents: [] 85 | m_SourcePrefab: {fileID: 100100000, guid: 272fdb9e09fc6d34e89748854b0ff3a1, type: 3} 86 | -------------------------------------------------------------------------------- /Prefabs/Presets/MeshHoleShrinker-Mimino-1.0.1.prefab: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!1001 &3342620599786445127 4 | PrefabInstance: 5 | m_ObjectHideFlags: 0 6 | serializedVersion: 2 7 | m_Modification: 8 | m_TransformParent: {fileID: 0} 9 | m_Modifications: 10 | - target: {fileID: 2513171326369980129, guid: 272fdb9e09fc6d34e89748854b0ff3a1, 11 | type: 3} 12 | propertyPath: m_Name 13 | value: MeshHoleShrinker-Mimino-1.0.1 14 | objectReference: {fileID: 0} 15 | - target: {fileID: 2513171326369980131, guid: 272fdb9e09fc6d34e89748854b0ff3a1, 16 | type: 3} 17 | propertyPath: m_LocalPosition.x 18 | value: 0 19 | objectReference: {fileID: 0} 20 | - target: {fileID: 2513171326369980131, guid: 272fdb9e09fc6d34e89748854b0ff3a1, 21 | type: 3} 22 | propertyPath: m_LocalPosition.y 23 | value: 1.1107 24 | objectReference: {fileID: 0} 25 | - target: {fileID: 2513171326369980131, guid: 272fdb9e09fc6d34e89748854b0ff3a1, 26 | type: 3} 27 | propertyPath: m_LocalPosition.z 28 | value: 0.0163 29 | objectReference: {fileID: 0} 30 | - target: {fileID: 2513171326369980131, guid: 272fdb9e09fc6d34e89748854b0ff3a1, 31 | type: 3} 32 | propertyPath: m_LocalRotation.x 33 | value: 0.13876037 34 | objectReference: {fileID: 0} 35 | - target: {fileID: 2513171326369980131, guid: 272fdb9e09fc6d34e89748854b0ff3a1, 36 | type: 3} 37 | propertyPath: m_LocalRotation.y 38 | value: -0 39 | objectReference: {fileID: 0} 40 | - target: {fileID: 2513171326369980131, guid: 272fdb9e09fc6d34e89748854b0ff3a1, 41 | type: 3} 42 | propertyPath: m_LocalRotation.z 43 | value: -0 44 | objectReference: {fileID: 0} 45 | - target: {fileID: 2513171326369980131, guid: 272fdb9e09fc6d34e89748854b0ff3a1, 46 | type: 3} 47 | propertyPath: m_LocalRotation.w 48 | value: 0.99032605 49 | objectReference: {fileID: 0} 50 | - target: {fileID: 2513171326369980131, guid: 272fdb9e09fc6d34e89748854b0ff3a1, 51 | type: 3} 52 | propertyPath: m_RootOrder 53 | value: 0 54 | objectReference: {fileID: 0} 55 | - target: {fileID: 2513171326369980131, guid: 272fdb9e09fc6d34e89748854b0ff3a1, 56 | type: 3} 57 | propertyPath: m_LocalEulerAnglesHint.x 58 | value: 15.952001 59 | objectReference: {fileID: 0} 60 | - target: {fileID: 2513171326369980131, guid: 272fdb9e09fc6d34e89748854b0ff3a1, 61 | type: 3} 62 | propertyPath: m_LocalEulerAnglesHint.y 63 | value: 0 64 | objectReference: {fileID: 0} 65 | - target: {fileID: 2513171326369980131, guid: 272fdb9e09fc6d34e89748854b0ff3a1, 66 | type: 3} 67 | propertyPath: m_LocalEulerAnglesHint.z 68 | value: 0 69 | objectReference: {fileID: 0} 70 | - target: {fileID: 2513171326369980131, guid: 272fdb9e09fc6d34e89748854b0ff3a1, 71 | type: 3} 72 | propertyPath: m_LocalScale.x 73 | value: 0.07160037 74 | objectReference: {fileID: 0} 75 | - target: {fileID: 2513171326369980131, guid: 272fdb9e09fc6d34e89748854b0ff3a1, 76 | type: 3} 77 | propertyPath: m_LocalScale.z 78 | value: 0.08959757 79 | objectReference: {fileID: 0} 80 | - target: {fileID: 6865199450278234314, guid: 272fdb9e09fc6d34e89748854b0ff3a1, 81 | type: 3} 82 | propertyPath: targetMesh 83 | value: 84 | objectReference: {fileID: 0} 85 | m_RemovedComponents: [] 86 | m_SourcePrefab: {fileID: 100100000, guid: 272fdb9e09fc6d34e89748854b0ff3a1, type: 3} 87 | -------------------------------------------------------------------------------- /Prefabs/Presets/MeshHoleShrinker-Almond-1.01.prefab: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!1001 &5516482164299221238 4 | PrefabInstance: 5 | m_ObjectHideFlags: 0 6 | serializedVersion: 2 7 | m_Modification: 8 | m_TransformParent: {fileID: 0} 9 | m_Modifications: 10 | - target: {fileID: 2513171326369980129, guid: 272fdb9e09fc6d34e89748854b0ff3a1, 11 | type: 3} 12 | propertyPath: m_Name 13 | value: MeshHoleShrinker-Almond-1.01 14 | objectReference: {fileID: 0} 15 | - target: {fileID: 2513171326369980131, guid: 272fdb9e09fc6d34e89748854b0ff3a1, 16 | type: 3} 17 | propertyPath: m_LocalPosition.x 18 | value: -0 19 | objectReference: {fileID: 0} 20 | - target: {fileID: 2513171326369980131, guid: 272fdb9e09fc6d34e89748854b0ff3a1, 21 | type: 3} 22 | propertyPath: m_LocalPosition.y 23 | value: 1.0735 24 | objectReference: {fileID: 0} 25 | - target: {fileID: 2513171326369980131, guid: 272fdb9e09fc6d34e89748854b0ff3a1, 26 | type: 3} 27 | propertyPath: m_LocalPosition.z 28 | value: -0.0282 29 | objectReference: {fileID: 0} 30 | - target: {fileID: 2513171326369980131, guid: 272fdb9e09fc6d34e89748854b0ff3a1, 31 | type: 3} 32 | propertyPath: m_LocalRotation.x 33 | value: 0.20610547 34 | objectReference: {fileID: 0} 35 | - target: {fileID: 2513171326369980131, guid: 272fdb9e09fc6d34e89748854b0ff3a1, 36 | type: 3} 37 | propertyPath: m_LocalRotation.y 38 | value: 1.00485916e-14 39 | objectReference: {fileID: 0} 40 | - target: {fileID: 2513171326369980131, guid: 272fdb9e09fc6d34e89748854b0ff3a1, 41 | type: 3} 42 | propertyPath: m_LocalRotation.z 43 | value: -8.4703295e-22 44 | objectReference: {fileID: 0} 45 | - target: {fileID: 2513171326369980131, guid: 272fdb9e09fc6d34e89748854b0ff3a1, 46 | type: 3} 47 | propertyPath: m_LocalRotation.w 48 | value: 0.9785298 49 | objectReference: {fileID: 0} 50 | - target: {fileID: 2513171326369980131, guid: 272fdb9e09fc6d34e89748854b0ff3a1, 51 | type: 3} 52 | propertyPath: m_RootOrder 53 | value: 0 54 | objectReference: {fileID: 0} 55 | - target: {fileID: 2513171326369980131, guid: 272fdb9e09fc6d34e89748854b0ff3a1, 56 | type: 3} 57 | propertyPath: m_LocalEulerAnglesHint.x 58 | value: 23.788002 59 | objectReference: {fileID: 0} 60 | - target: {fileID: 2513171326369980131, guid: 272fdb9e09fc6d34e89748854b0ff3a1, 61 | type: 3} 62 | propertyPath: m_LocalEulerAnglesHint.y 63 | value: 0 64 | objectReference: {fileID: 0} 65 | - target: {fileID: 2513171326369980131, guid: 272fdb9e09fc6d34e89748854b0ff3a1, 66 | type: 3} 67 | propertyPath: m_LocalEulerAnglesHint.z 68 | value: 0 69 | objectReference: {fileID: 0} 70 | - target: {fileID: 2513171326369980131, guid: 272fdb9e09fc6d34e89748854b0ff3a1, 71 | type: 3} 72 | propertyPath: m_LocalScale.x 73 | value: 0.05787142 74 | objectReference: {fileID: 0} 75 | - target: {fileID: 2513171326369980131, guid: 272fdb9e09fc6d34e89748854b0ff3a1, 76 | type: 3} 77 | propertyPath: m_LocalScale.y 78 | value: 0.00519775 79 | objectReference: {fileID: 0} 80 | - target: {fileID: 2513171326369980131, guid: 272fdb9e09fc6d34e89748854b0ff3a1, 81 | type: 3} 82 | propertyPath: m_LocalScale.z 83 | value: 0.07285367 84 | objectReference: {fileID: 0} 85 | m_RemovedComponents: [] 86 | m_SourcePrefab: {fileID: 100100000, guid: 272fdb9e09fc6d34e89748854b0ff3a1, type: 3} 87 | -------------------------------------------------------------------------------- /Prefabs/Internal/MeshSnapshot.prefab: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!1 &6482372250897581944 4 | GameObject: 5 | m_ObjectHideFlags: 0 6 | m_CorrespondingSourceObject: {fileID: 0} 7 | m_PrefabInstance: {fileID: 0} 8 | m_PrefabAsset: {fileID: 0} 9 | serializedVersion: 6 10 | m_Component: 11 | - component: {fileID: 6482372250897581951} 12 | - component: {fileID: 6482372250897581949} 13 | - component: {fileID: 6482372250897581950} 14 | m_Layer: 0 15 | m_Name: MeshSnapshot 16 | m_TagString: Untagged 17 | m_Icon: {fileID: 0} 18 | m_NavMeshLayer: 0 19 | m_StaticEditorFlags: 0 20 | m_IsActive: 1 21 | --- !u!4 &6482372250897581951 22 | Transform: 23 | m_ObjectHideFlags: 0 24 | m_CorrespondingSourceObject: {fileID: 0} 25 | m_PrefabInstance: {fileID: 0} 26 | m_PrefabAsset: {fileID: 0} 27 | m_GameObject: {fileID: 6482372250897581944} 28 | m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} 29 | m_LocalPosition: {x: 0, y: 0, z: 0} 30 | m_LocalScale: {x: 1, y: 1, z: 1} 31 | m_Children: [] 32 | m_Father: {fileID: 0} 33 | m_RootOrder: 0 34 | m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} 35 | --- !u!33 &6482372250897581949 36 | MeshFilter: 37 | m_ObjectHideFlags: 0 38 | m_CorrespondingSourceObject: {fileID: 0} 39 | m_PrefabInstance: {fileID: 0} 40 | m_PrefabAsset: {fileID: 0} 41 | m_GameObject: {fileID: 6482372250897581944} 42 | m_Mesh: {fileID: 0} 43 | --- !u!23 &6482372250897581950 44 | MeshRenderer: 45 | m_ObjectHideFlags: 0 46 | m_CorrespondingSourceObject: {fileID: 0} 47 | m_PrefabInstance: {fileID: 0} 48 | m_PrefabAsset: {fileID: 0} 49 | m_GameObject: {fileID: 6482372250897581944} 50 | m_Enabled: 1 51 | m_CastShadows: 0 52 | m_ReceiveShadows: 0 53 | m_DynamicOccludee: 1 54 | m_MotionVectors: 1 55 | m_LightProbeUsage: 0 56 | m_ReflectionProbeUsage: 0 57 | m_RenderingLayerMask: 1 58 | m_RendererPriority: 0 59 | m_Materials: 60 | - {fileID: 2100000, guid: 9165404ef7a7fb84e8106f0244a53911, type: 2} 61 | - {fileID: 2100000, guid: 9165404ef7a7fb84e8106f0244a53911, type: 2} 62 | - {fileID: 2100000, guid: 9165404ef7a7fb84e8106f0244a53911, type: 2} 63 | - {fileID: 2100000, guid: 9165404ef7a7fb84e8106f0244a53911, type: 2} 64 | - {fileID: 2100000, guid: 9165404ef7a7fb84e8106f0244a53911, type: 2} 65 | - {fileID: 2100000, guid: 9165404ef7a7fb84e8106f0244a53911, type: 2} 66 | - {fileID: 2100000, guid: 9165404ef7a7fb84e8106f0244a53911, type: 2} 67 | - {fileID: 2100000, guid: 9165404ef7a7fb84e8106f0244a53911, type: 2} 68 | - {fileID: 2100000, guid: 9165404ef7a7fb84e8106f0244a53911, type: 2} 69 | - {fileID: 2100000, guid: 9165404ef7a7fb84e8106f0244a53911, type: 2} 70 | - {fileID: 2100000, guid: 9165404ef7a7fb84e8106f0244a53911, type: 2} 71 | - {fileID: 2100000, guid: 9165404ef7a7fb84e8106f0244a53911, type: 2} 72 | - {fileID: 2100000, guid: 9165404ef7a7fb84e8106f0244a53911, type: 2} 73 | - {fileID: 2100000, guid: 9165404ef7a7fb84e8106f0244a53911, type: 2} 74 | - {fileID: 2100000, guid: 9165404ef7a7fb84e8106f0244a53911, type: 2} 75 | - {fileID: 2100000, guid: 9165404ef7a7fb84e8106f0244a53911, type: 2} 76 | - {fileID: 2100000, guid: 9165404ef7a7fb84e8106f0244a53911, type: 2} 77 | - {fileID: 2100000, guid: 9165404ef7a7fb84e8106f0244a53911, type: 2} 78 | - {fileID: 2100000, guid: 9165404ef7a7fb84e8106f0244a53911, type: 2} 79 | - {fileID: 2100000, guid: 9165404ef7a7fb84e8106f0244a53911, type: 2} 80 | m_StaticBatchInfo: 81 | firstSubMesh: 0 82 | subMeshCount: 0 83 | m_StaticBatchRoot: {fileID: 0} 84 | m_ProbeAnchor: {fileID: 0} 85 | m_LightProbeVolumeOverride: {fileID: 0} 86 | m_ScaleInLightmap: 1 87 | m_PreserveUVs: 0 88 | m_IgnoreNormalsForChartDetection: 0 89 | m_ImportantGI: 0 90 | m_StitchLightmapSeams: 0 91 | m_SelectedEditorRenderState: 3 92 | m_MinimumChartSize: 4 93 | m_AutoUVMaxDistance: 0.5 94 | m_AutoUVMaxAngle: 89 95 | m_LightmapParameters: {fileID: 0} 96 | m_SortingLayerID: 0 97 | m_SortingLayer: 0 98 | m_SortingOrder: 0 99 | -------------------------------------------------------------------------------- /Prefabs/MeshHoleShrinker.prefab: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!1 &2513171326369980129 4 | GameObject: 5 | m_ObjectHideFlags: 0 6 | m_CorrespondingSourceObject: {fileID: 0} 7 | m_PrefabInstance: {fileID: 0} 8 | m_PrefabAsset: {fileID: 0} 9 | serializedVersion: 6 10 | m_Component: 11 | - component: {fileID: 2513171326369980131} 12 | - component: {fileID: 2285031009762507834} 13 | m_Layer: 0 14 | m_Name: MeshHoleShrinker 15 | m_TagString: Untagged 16 | m_Icon: {fileID: 0} 17 | m_NavMeshLayer: 0 18 | m_StaticEditorFlags: 0 19 | m_IsActive: 1 20 | --- !u!4 &2513171326369980131 21 | Transform: 22 | m_ObjectHideFlags: 0 23 | m_CorrespondingSourceObject: {fileID: 0} 24 | m_PrefabInstance: {fileID: 0} 25 | m_PrefabAsset: {fileID: 0} 26 | m_GameObject: {fileID: 2513171326369980129} 27 | m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} 28 | m_LocalPosition: {x: 0, y: 1, z: 0} 29 | m_LocalScale: {x: 0.1, y: 0.01, z: 0.1} 30 | m_Children: 31 | - {fileID: 2513171326405631575} 32 | m_Father: {fileID: 0} 33 | m_RootOrder: 0 34 | m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} 35 | --- !u!114 &2285031009762507834 36 | MonoBehaviour: 37 | m_ObjectHideFlags: 0 38 | m_CorrespondingSourceObject: {fileID: 0} 39 | m_PrefabInstance: {fileID: 0} 40 | m_PrefabAsset: {fileID: 0} 41 | m_GameObject: {fileID: 2513171326369980129} 42 | m_Enabled: 1 43 | m_EditorHideFlags: 0 44 | m_Script: {fileID: 11500000, guid: 0b5c7d26826d9f54a827fb75ec24aaaa, type: 3} 45 | m_Name: 46 | m_EditorClassIdentifier: 47 | targetMesh: {fileID: 0} 48 | newName: shrink_hole 49 | scale: 0.5 50 | epsilon: 0.001 51 | meshSnapshotPrefab: {fileID: 6482372250897581944, guid: 9dc0aa4daff5a7d4a8485a8dd6379648, 52 | type: 3} 53 | --- !u!1 &2513171326405631579 54 | GameObject: 55 | m_ObjectHideFlags: 0 56 | m_CorrespondingSourceObject: {fileID: 0} 57 | m_PrefabInstance: {fileID: 0} 58 | m_PrefabAsset: {fileID: 0} 59 | serializedVersion: 6 60 | m_Component: 61 | - component: {fileID: 2513171326405631575} 62 | - component: {fileID: 2513171326405631572} 63 | - component: {fileID: 2513171326405631573} 64 | - component: {fileID: 2513171326405631578} 65 | m_Layer: 0 66 | m_Name: Cylinder 67 | m_TagString: Untagged 68 | m_Icon: {fileID: 0} 69 | m_NavMeshLayer: 0 70 | m_StaticEditorFlags: 0 71 | m_IsActive: 1 72 | --- !u!4 &2513171326405631575 73 | Transform: 74 | m_ObjectHideFlags: 0 75 | m_CorrespondingSourceObject: {fileID: 0} 76 | m_PrefabInstance: {fileID: 0} 77 | m_PrefabAsset: {fileID: 0} 78 | m_GameObject: {fileID: 2513171326405631579} 79 | m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} 80 | m_LocalPosition: {x: 0, y: 0, z: 0} 81 | m_LocalScale: {x: 1, y: 1, z: 1} 82 | m_Children: [] 83 | m_Father: {fileID: 2513171326369980131} 84 | m_RootOrder: 0 85 | m_LocalEulerAnglesHint: {x: 21.825, y: 0, z: 0} 86 | --- !u!33 &2513171326405631572 87 | MeshFilter: 88 | m_ObjectHideFlags: 0 89 | m_CorrespondingSourceObject: {fileID: 0} 90 | m_PrefabInstance: {fileID: 0} 91 | m_PrefabAsset: {fileID: 0} 92 | m_GameObject: {fileID: 2513171326405631579} 93 | m_Mesh: {fileID: 10206, guid: 0000000000000000e000000000000000, type: 0} 94 | --- !u!23 &2513171326405631573 95 | MeshRenderer: 96 | m_ObjectHideFlags: 0 97 | m_CorrespondingSourceObject: {fileID: 0} 98 | m_PrefabInstance: {fileID: 0} 99 | m_PrefabAsset: {fileID: 0} 100 | m_GameObject: {fileID: 2513171326405631579} 101 | m_Enabled: 1 102 | m_CastShadows: 0 103 | m_ReceiveShadows: 0 104 | m_DynamicOccludee: 1 105 | m_MotionVectors: 1 106 | m_LightProbeUsage: 0 107 | m_ReflectionProbeUsage: 0 108 | m_RenderingLayerMask: 1 109 | m_RendererPriority: 0 110 | m_Materials: 111 | - {fileID: 2100000, guid: 9165404ef7a7fb84e8106f0244a53911, type: 2} 112 | m_StaticBatchInfo: 113 | firstSubMesh: 0 114 | subMeshCount: 0 115 | m_StaticBatchRoot: {fileID: 0} 116 | m_ProbeAnchor: {fileID: 0} 117 | m_LightProbeVolumeOverride: {fileID: 0} 118 | m_ScaleInLightmap: 1 119 | m_PreserveUVs: 0 120 | m_IgnoreNormalsForChartDetection: 0 121 | m_ImportantGI: 0 122 | m_StitchLightmapSeams: 0 123 | m_SelectedEditorRenderState: 3 124 | m_MinimumChartSize: 4 125 | m_AutoUVMaxDistance: 0.5 126 | m_AutoUVMaxAngle: 89 127 | m_LightmapParameters: {fileID: 0} 128 | m_SortingLayerID: 0 129 | m_SortingLayer: 0 130 | m_SortingOrder: 0 131 | --- !u!64 &2513171326405631578 132 | MeshCollider: 133 | m_ObjectHideFlags: 0 134 | m_CorrespondingSourceObject: {fileID: 0} 135 | m_PrefabInstance: {fileID: 0} 136 | m_PrefabAsset: {fileID: 0} 137 | m_GameObject: {fileID: 2513171326405631579} 138 | m_Material: {fileID: 0} 139 | m_IsTrigger: 1 140 | m_Enabled: 1 141 | serializedVersion: 3 142 | m_Convex: 1 143 | m_CookingOptions: 14 144 | m_Mesh: {fileID: 10206, guid: 0000000000000000e000000000000000, type: 0} 145 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MeshHoleShrinker 2 | 3 | メッシュに開いた穴を縮めるためのシェイプキーを追加し、新しいメッシュとして保存するUnityエディタ拡張です。 4 | 5 | Unity上でアバター頭部を他の素体に接合するとき、接合部にすきまが開いてしまうのを防ぐなどの用途に有用です。 6 | 7 | ![image](https://repository-images.githubusercontent.com/295406109/4b4c2c80-fccd-11ea-8092-23c8dc4f2910) 8 | 9 | ## 動作環境 10 | 11 | Unity 2018.4 以降 12 | 13 | ## インポート手順 14 | 15 | ### unitypackageをインポートする方法 16 | 17 | [Releasesページ](https://github.com/chigirits/MeshHoleShrinker/releases) より最新版の `MeshHoleShrinker-vX.X.X.unitypackage` をダウンロードし、Unityにインポートする 18 | 19 | ### パッケージマネージャを用いる方法 20 | 21 | 1. インポート先プロジェクトの `Packages/manifest.json` をテキストエディタ等で開く 22 | 2. `dependencies` オブジェクト内に以下の要素を追加 23 | 24 | ``` 25 | "com.github.chigirits.meshholeshrinker": "https://github.com/chigirits/MeshHoleShrinker.git", 26 | ``` 27 | 28 | こちらの方法でインポートした場合、以下の説明文中で示される本パッケージのプレハブやプリセットは `Assets/Chigiri/MeshHoleShrinker/...` 下ではなく `Packages/MeshHoleShrinker/Assets/Chigiri/MeshHoleShrinker/...` 下から選択してください。 29 | 30 | ## 使い方 31 | 32 | 1. シーンにアバターを配置し、頭部以外を非表示にしてください。 33 | 2. 「メニュー/Chigiri/Create MeshHoleShrinker」を選択すると、ヒエラルキーのトップレベルに MeshHoleShrinker が配置されます(一部販売モデルは[プリセット](#プリセットについて)を利用できますのでそちらをご利用ください)。 34 | 3. MeshHoleShrinker の `Target` に、アバター頭部の SkinnedMeshRenderer(一般的には Body オブジェクト)を指定してください。
35 | このとき、対象にアタッチされているメッシュが `Source Mesh` に自動的にセットされます。 36 | 4. `New Shape Key Name` に追加するシェイプキーの名前を指定してください(通常はデフォルトのままで問題ありません)。 37 | 38 | ![usage-01](https://user-images.githubusercontent.com/61717977/93324194-87583b00-f850-11ea-857b-50700a16e84b.png) 39 | 5. Shaded Wireframe 表示にした状態で MeshHoleShrinker の位置・角度・スケールを変更し、縮めたい穴を構成する頂点が半透明の円筒にすべて含まれるように調整してください。 40 | 41 | ![usage-02](https://user-images.githubusercontent.com/61717977/93084788-89df5700-f6cf-11ea-8d8b-5166c0bbc20a.png)
42 | 穴の辺ループ上にない頂点や舌などを巻き込まないよう注意し、必要十分な頂点が含まれているかを全方位から眺めて確認してください。
43 | ![usage-03](https://user-images.githubusercontent.com/61717977/93084790-8a77ed80-f6cf-11ea-9f0a-491ec3954c05.png) 44 | 6. `Process And Save As...` ボタンを押して、生成された新しいメッシュを保存してください。 45 | 46 | ![usage-04](https://user-images.githubusercontent.com/61717977/93324199-88896800-f850-11ea-85b9-c7173f566ba7.png) 47 | 48 | 49 | 保存が完了すると、`Target` の SkinnedMeshRenderer に新しいメッシュがアタッチされます。 50 | この差し替えられたメッシュに新しいシェイプキーがウェイト100で追加されていることを確認してください。 51 | 52 | ![usage-05](https://repository-images.githubusercontent.com/295406109/a2eb0680-f6d5-11ea-9672-da464eeef28f) 53 | 54 | このとき、穴が均一に縮んでいないなど期待した結果と異なる場合は Undo して 5. からやり直してください。必要な頂点がすべて含まれていないと円形に縮まず、余計な頂点が含まれていると捻じれが起こりやすいです。 55 | 56 | ### 処理後の調整 57 | 58 | 追加されたシェイプキーのウェイトは、必要最低限の値に設定することを推奨します。ウェイトを大きくし過ぎる(穴を小さくし過ぎる)と、穴の周辺ポリゴンが重なり合うなど表示上の不都合が発生しやすいです。 59 | 60 | ### プリセットについて 61 | 62 | 以下の販売モデルは、あらかじめ位置合わせ済みのプリセットを `Assets/Chigiri/MeshHoleShrinker/Prefabs/Presets/` 下に用意しています。モデルのプレハブを未加工のまま原点に配置した状態で適用してください。 63 | 64 | - [みみの v1.0.1](https://booth.pm/ja/items/1336133) 65 | - [アーモンド v1.01](https://booth.pm/ja/items/2012982) 66 | - [メープル v1.1](https://booth.pm/ja/items/1948102) 67 | - [まき菜 v1.3 PC版](https://booth.pm/ja/items/1748933) 68 | 69 | 他のモデルについては、各自 **ご自分のモデルへの適用時の `Transform` コンポーネントのスクリーンショットを [#MeshHoleShrinker](https://twitter.com/search?q=%23MeshHoleShrinker&src=typed_query) タグで Twitter に共有** することをおすすめします。 70 | 71 | なお、私が所持しているモデルしか確認が取れないため、プリセット追加に関する Pull Request は原則として Reject させていただきます。 72 | 73 | ## 注意事項 74 | 75 | - **Undo すると `Target` のメッシュが消える場合があります**。これは、複数回続けて `Process And Save As...` を行うと発生する現象で、直前に保存したメッシュを上書きすると上書き前のメッシュが復元できなくなるために起こります。通常は `Revert Target` を押すことで適用前の状態に戻すことができます。 76 | - **`Target` にシアー(回転後に各軸で異なる値のスケール)がかかっている場合、頂点の範囲を正常に特定できません**。対象オブジェクトをヒエラルキーのルートに置いた状態で位置合わせをしてからお試しください。 77 | - 既存のブレンドシェイプで位置が変わっている頂点が円筒に含まれている場合、位置合わせがうまく行かない場合があります。ただ、一般的なアバターモデルでは首まわりの頂点位置が変化するようなブレンドシェイプは存在しないため、通常は問題になることはありません。不安な方は位置合わせ時に `Target` のブレンドシェイプ量をあらかじめすべて `0` にしてください。 78 | - 通常は楕円形に近い穴しかきれいに範囲指定できません(仕様です)。特殊な形状の穴を縮める際は、`Advanced > Use MeshCollider` にチェックを入れた上で、`MeshHoleShrinker` 内 `Cylinder` オブジェクトの `MeshCollider` および `MeshFilter` に指定されているメッシュを `Cube` 等の任意の形状に変更することで選択できる場合がありますが、素直に Blender で作業した方が確実かもしれません。 79 | - 法線の向きには影響がありません。 80 | 81 | ## Tips 82 | 83 | - `Scale` を `0` にすると穴を完全にふさぐことができます。 84 | - 穴の中心点を微調整したい場合は `Offset` に移動量を指定してください。 85 | - `Scale` を `1` にして `Offset` を指定すると、頂点が平行移動するシェイプキーを作成することができます。 86 | - プレハブ内に含まれる `Cylinder` を複製して他の箇所に位置合わせすると、複数の頂点群を一度に処理することができます。 87 | 88 | ## ライセンス 89 | 90 | [MIT License](./LICENSE)
91 | ©2020 TSUTSUMI Chigiri 92 | 93 | - このソフトウェアは商用・非商用問わず無償で利用できますが、無保証です。利用に際して発生する問題については、作者は一切の責任を負いません。 94 | - コードを再利用する際は、著作権表示と上記リンク先のライセンス条文を同梱する必要があります。詳しくは条文(英語)をお読みください。 95 | 96 | ## 更新履歴 97 | 98 | - v1.2.0 99 | - 複数の円筒を一度に処理 100 | - 最後に保存したファイルパスを次回保存時のデフォルトパスとする 101 | - Cylinder 自体の Transform を変更すると正常に範囲を特定できない問題を修正 102 | - リファクタリング 103 | - v1.1.0 104 | - UIの改善 105 | - Source Mesh を Target とは独立して保持し、リトライ時の手間を軽減 106 | - 保存ダイアログの初期ディレクトリを Source Mesh と同一に 107 | - Revert Target ボタンを追加 108 | - ツールチップ表示 109 | - 精度の向上 110 | - Skinned Mesh Renderer のスナップショット作成を BakeMesh よりも高精度な方法に変更 111 | - 頂点範囲の判定をデフォルトで数学的な円筒を用いるよう変更 112 | - 機能追加 113 | - Offset プロパティを追加 114 | - v1.0.1 115 | - unitypackage に含まれるファイルのパスを修正 116 | - v1.0.0 117 | - 初回リリース 118 | -------------------------------------------------------------------------------- /Editor/MeshHoleShrinkerEditor.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.IO; 5 | using System.Text.RegularExpressions; 6 | using UnityEngine; 7 | using UnityEditor; 8 | 9 | namespace Chigiri.MeshHoleShrinker.Editor 10 | { 11 | 12 | [CustomEditor(typeof(MeshHoleShrinker))] 13 | public class MeshHoleShrinkerEditor : UnityEditor.Editor 14 | { 15 | 16 | SerializedProperty targetRenderer; 17 | SerializedProperty sourceMesh; 18 | SerializedProperty newName; 19 | SerializedProperty scale; 20 | SerializedProperty offset; 21 | SerializedProperty epsilon; 22 | SerializedProperty useMeshCollider; 23 | SerializedProperty meshSnapshotPrefab; 24 | 25 | SkinnedMeshRenderer prevTargetRenderer; 26 | bool isAdvancedOpen; 27 | float sqrEpsilon; 28 | 29 | [MenuItem("Chigiri/Create MeshHoleShrinker")] 30 | public static void CreateMeshHoleShrinker() 31 | { 32 | var path = AssetDatabase.GUIDToAssetPath("272fdb9e09fc6d34e89748854b0ff3a1"); 33 | var prefab = AssetDatabase.LoadAssetAtPath(path); 34 | var instance = PrefabUtility.InstantiatePrefab(prefab) as GameObject; 35 | instance.transform.SetAsLastSibling(); 36 | Undo.RegisterCreatedObjectUndo(instance, "Create MeshHoleShrinker"); 37 | } 38 | 39 | private void OnEnable() 40 | { 41 | targetRenderer = serializedObject.FindProperty("targetRenderer"); 42 | sourceMesh = serializedObject.FindProperty("sourceMesh"); 43 | newName = serializedObject.FindProperty("newName"); 44 | scale = serializedObject.FindProperty("scale"); 45 | offset = serializedObject.FindProperty("offset"); 46 | epsilon = serializedObject.FindProperty("epsilon"); 47 | useMeshCollider = serializedObject.FindProperty("useMeshCollider"); 48 | meshSnapshotPrefab = serializedObject.FindProperty("meshSnapshotPrefab"); 49 | } 50 | 51 | public override void OnInspectorGUI() 52 | { 53 | serializedObject.Update(); 54 | 55 | // Target を変更したときに Source Mesh が空なら自動設定 56 | if (prevTargetRenderer != self.targetRenderer && self.targetRenderer != null && self.sourceMesh == null) 57 | { 58 | self.sourceMesh = self.targetRenderer.sharedMesh; 59 | } 60 | prevTargetRenderer = self.targetRenderer; 61 | 62 | // バリデーション 63 | var error = ""; 64 | error += ValidateTargetRenderer(); 65 | error += ValidateSourceMesh(); 66 | error += ValidateMeshSnapshotPrefab(); 67 | error += ValidateNewName(); 68 | 69 | // UI描画 70 | 71 | EditorGUILayout.PropertyField(targetRenderer, new GUIContent("Target", "操作対象のSkinnedMeshRenderer")); 72 | EditorGUILayout.PropertyField(sourceMesh, new GUIContent("Source Mesh", "オリジナルのメッシュ")); 73 | EditorGUILayout.PropertyField(newName, new GUIContent("New Shape Key Name", "新しく追加するシェイプキーの名前")); 74 | EditorGUILayout.Slider(scale, 0f, 1f, new GUIContent("Scale", "穴のサイズ比率(0で完全にふさがります)")); 75 | EditorGUILayout.PropertyField(offset, new GUIContent("Offset", "穴の中心点を偏らせるオフセット量")); 76 | 77 | isAdvancedOpen = EditorGUILayout.Foldout(isAdvancedOpen, "Advanced"); 78 | if (isAdvancedOpen) 79 | { 80 | EditorGUI.indentLevel++; 81 | { 82 | EditorGUILayout.Slider(epsilon, 1e-5f, 0.1f, new GUIContent("Epsilon")); 83 | EditorGUILayout.PropertyField(useMeshCollider, new GUIContent("Use MeshCollider")); 84 | EditorGUILayout.PropertyField(meshSnapshotPrefab, new GUIContent("MeshSnapshot (DO NOT EDIT)")); 85 | } 86 | EditorGUI.indentLevel--; 87 | } 88 | 89 | if (error != "") 90 | { 91 | EditorGUILayout.HelpBox(Helper.Chomp(error), MessageType.Error, true); 92 | } 93 | 94 | var isRevertTargetEnable = self.targetRenderer != null && self.sourceMesh != null; 95 | if (isRevertTargetEnable) 96 | { 97 | EditorGUILayout.HelpBox("Undo 時にメッシュが消えた場合は Revert Target ボタンを押してください。", MessageType.Info, true); 98 | } 99 | 100 | EditorGUILayout.Space(); 101 | 102 | EditorGUILayout.BeginHorizontal(); 103 | { 104 | EditorGUI.BeginDisabledGroup(error != ""); 105 | { 106 | if (GUILayout.Button(new GUIContent("Process And Save As...", "新しいメッシュを生成し、保存ダイアログを表示します。"))) DoProcess(); 107 | } 108 | EditorGUI.EndDisabledGroup(); 109 | 110 | EditorGUI.BeginDisabledGroup(!isRevertTargetEnable); 111 | { 112 | if (GUILayout.Button(new GUIContent("Revert Target", "Target の SkinnedMeshRenderer にアタッチされていたメッシュを元に戻します。"))) RevertTarget(); 113 | } 114 | EditorGUI.EndDisabledGroup(); 115 | } 116 | EditorGUILayout.EndHorizontal(); 117 | 118 | EditorGUILayout.Space(); 119 | 120 | serializedObject.ApplyModifiedProperties(); 121 | } 122 | 123 | string ValidateTargetRenderer() 124 | { 125 | if (self.targetRenderer == null) 126 | { 127 | return "Target に操作対象となる SkinnedMeshRenderer を指定してください。\n"; 128 | } 129 | return ""; 130 | } 131 | 132 | string ValidateSourceMesh() 133 | { 134 | if (self.sourceMesh == null) 135 | { 136 | return "Source Mesh に操作対象となるメッシュを指定してください(通常は Target の SkinnedMeshRenderer にもともとアタッチされていたメッシュです)。\n"; 137 | } 138 | return ""; 139 | } 140 | 141 | string ValidateMeshSnapshotPrefab() 142 | { 143 | if (self.meshSnapshotPrefab == null) 144 | { 145 | return "MeshSnapshot のラベル部分を右クリックし、Revert してください。\n"; 146 | } 147 | return ""; 148 | } 149 | 150 | string ValidateNewName() 151 | { 152 | if (newName.stringValue == "") 153 | { 154 | return "New Shape Key Name に新しいシェイプキーの名前を指定してください。\n"; 155 | } 156 | if (self.sourceMesh != null && 0 <= self.sourceMesh.GetBlendShapeIndex(self.newName)) 157 | { 158 | return "New Shape Key Name に指定されているシェイプキーは既に存在します。別の名前を指定してください。\n"; 159 | } 160 | return ""; 161 | } 162 | 163 | MeshHoleShrinker self 164 | { 165 | get { return target as MeshHoleShrinker; } 166 | } 167 | 168 | void DoProcess() 169 | { 170 | // 新しいメッシュを作成 171 | if (self.sourceMesh == null) return; 172 | var resultMesh = AddBlendShape(self.sourceMesh); 173 | if (resultMesh == null) return; 174 | resultMesh.name = self.sourceMesh.name + ".HoleShrinkable"; 175 | 176 | // 保存ダイアログを表示 177 | string dir = self._lastSavedPath; 178 | if (dir == "") dir = AssetDatabase.GetAssetPath(self.targetRenderer.sharedMesh); 179 | if (dir == "") dir = AssetDatabase.GetAssetPath(self.sourceMesh); 180 | dir = dir == "" ? "Assets" : Path.GetDirectoryName(dir); 181 | var newName = Path.GetFileName(self._lastSavedPath); 182 | if (newName == "") newName = resultMesh.name; 183 | string path = EditorUtility.SaveFilePanel("Save the new mesh as", dir, Helper.SanitizeFileName(newName), "asset"); 184 | if (path.Length == 0) return; 185 | 186 | // 保存 187 | if (!path.StartsWith(Application.dataPath)) 188 | { 189 | Debug.LogError("Invalid path: Path must be under " + Application.dataPath); 190 | return; 191 | } 192 | path = path.Replace(Application.dataPath, "Assets"); 193 | AssetDatabase.CreateAsset(resultMesh, path); 194 | Debug.Log("Asset exported: " + path); 195 | self._lastSavedPath = path; 196 | 197 | // Targetのメッシュを差し替えてシェイプキーのウェイトを設定 198 | Undo.RecordObject(self.targetRenderer, "Process (MeshHoleShrinker)"); 199 | self.targetRenderer.sharedMesh = resultMesh; 200 | int index = resultMesh.GetBlendShapeIndex(self.newName); 201 | self.targetRenderer.SetBlendShapeWeight(index, 100f); 202 | // Selection.activeGameObject = self.targetRenderer.gameObject; 203 | } 204 | 205 | bool HitTest(Collider collider, Vector3 p) 206 | { 207 | Vector3 q; 208 | 209 | if (self.useMeshCollider) 210 | { 211 | q = collider.ClosestPoint(p); 212 | return (q - p).sqrMagnitude < sqrEpsilon; 213 | } 214 | 215 | q = collider.transform.InverseTransformPoint(p); 216 | if (1f < Mathf.Abs(q.y)) return false; 217 | return Mathf.Sqrt(q.x * q.x + q.z * q.z) <= 0.5f; 218 | } 219 | 220 | Mesh AddBlendShape(Mesh baseMesh) 221 | { 222 | sqrEpsilon = self.epsilon * self.epsilon; 223 | 224 | // SkinnedMeshRenderer の現在の形状を MeshRenderer に変換 225 | var snapshot = Instantiate(self.meshSnapshotPrefab).GetComponent(); 226 | snapshot.transform.parent = null; 227 | snapshot.transform.position = self.targetRenderer.transform.position; 228 | snapshot.transform.rotation = self.targetRenderer.transform.rotation; 229 | snapshot.transform.localScale = self.targetRenderer.transform.lossyScale; 230 | var snapshotMesh = Helper.GetPosedMesh(self.targetRenderer, self.sourceMesh); 231 | snapshot.sharedMesh = snapshotMesh; 232 | 233 | // 範囲内の点群の中心座標を算出 234 | var colliders = self.transform.GetComponentsInChildren(); 235 | var centers = new Vector3[colliders.Length]; 236 | for (var i = 0; i < colliders.Length; i++) 237 | { 238 | var collider = colliders[i]; 239 | Debug.Log(collider.transform.name); 240 | var center = Vector3.zero; 241 | var pointNum = 0; 242 | for (var j = 0; j < baseMesh.vertexCount; j++) 243 | { 244 | var p = snapshot.transform.TransformPoint(snapshotMesh.vertices[j]); 245 | if (HitTest(collider, p)) 246 | { 247 | center += baseMesh.vertices[j]; 248 | pointNum++; 249 | } 250 | } 251 | if (0 < pointNum) center /= pointNum; 252 | centers[i] = center; 253 | } 254 | 255 | // 新しいシェイプキーを作成 256 | Mesh ret = Instantiate(baseMesh); 257 | ret.name = baseMesh.name; 258 | var src = Instantiate(ret); 259 | var vertices = new Vector3[baseMesh.vertexCount]; 260 | for (var i = 0; i < colliders.Length; i++) 261 | { 262 | var collider = colliders[i]; 263 | var center = centers[i]; 264 | for (var j = 0; j < baseMesh.vertexCount; j++) 265 | { 266 | var p = snapshot.transform.TransformPoint(snapshotMesh.vertices[j]); 267 | if (HitTest(collider, p)) 268 | { 269 | vertices[j] += (center - baseMesh.vertices[j]) * (1f - self.scale) + self.offset; 270 | } 271 | } 272 | } 273 | ret.AddBlendShapeFrame(self.newName, 100f, vertices, null, null); 274 | 275 | DestroyImmediate(snapshot.gameObject); 276 | return ret; 277 | } 278 | 279 | void RevertTarget() 280 | { 281 | Undo.RecordObject(self.targetRenderer, "Revert Target (MeshHoleShrinker)"); 282 | self.targetRenderer.sharedMesh = self.sourceMesh; 283 | } 284 | 285 | } 286 | 287 | } 288 | --------------------------------------------------------------------------------