├── Deformers ├── packages.config ├── Properties │ └── AssemblyInfo.cs ├── Deformers.csproj └── Deformers.cs ├── nuget.config ├── Deformers.sln ├── README.md ├── .gitattributes └── .gitignore /Deformers/packages.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /nuget.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /Deformers.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.30523.141 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Deformers", "Deformers\Deformers.csproj", "{49FB735D-DF67-44B7-8790-59E1B3C0AB5D}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {49FB735D-DF67-44B7-8790-59E1B3C0AB5D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {49FB735D-DF67-44B7-8790-59E1B3C0AB5D}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {49FB735D-DF67-44B7-8790-59E1B3C0AB5D}.Release|Any CPU.ActiveCfg = Release|Any CPU 17 | {49FB735D-DF67-44B7-8790-59E1B3C0AB5D}.Release|Any CPU.Build.0 = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | GlobalSection(ExtensibilityGlobals) = postSolution 23 | SolutionGuid = {B2B201CF-2F43-4055-B8C2-3E3B2EC30791} 24 | EndGlobalSection 25 | EndGlobal 26 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Illusion_Deformers 2 | 3 | HS2 for now. 4 | Copy the .dll to BepInEx\Plugins and the .zipmod to (my)mods. 5 | 6 | "Squeezer", "Bulger", "Mover", "Rotator" accessories in the "Arms" category. 7 | 8 | - "Adjustment 01" is the selector: move around and scale to set the area that should be deformed. There's a sphere/capsule attached to give you an idea which area is being deformed. You can turn it completely transparent with the color option once it's in place. 9 | - "Adjustment 02" is for adjusting the deformation: Position changes the offset, Scale X is the strength, Scale Y is the falloff. The values aren't restricted so you can make glitchy eldritch monsters, but in general you probably want low values here, under 2. With the capsule variants, scale Z controls how much the deformation is based on the center of the capsule (z=1) vs the axis of the capsule (z=0). 10 | - You can add multiple deformers, order is top to bottom. Each deformer uses the result of the previous deformers as the base. 11 | - Switch the accessory's "Filter"-Material shader from "Standard" to something else to only deform renderers with that shader (with Material Editor). Switch to "Clothes True" to only deform clothes and not skin for example. Also helps with performance. 12 | - Deformers can be accessed, adjusted and used for animations in studio with HSPE. Just search for "move" bones. 13 | 14 | Quick demo: 15 | https://streamable.com/ed2qkz 16 | -------------------------------------------------------------------------------- /Deformers/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("Deformers")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("Deformers")] 13 | [assembly: AssemblyCopyright("Copyright © 2021")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("49fb735d-df67-44b7-8790-59e1b3c0ab5d")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /Deformers/Deformers.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {49FB735D-DF67-44B7-8790-59E1B3C0AB5D} 8 | Library 9 | Properties 10 | Deformers 11 | Deformers 12 | v4.6 13 | 512 14 | true 15 | 16 | 17 | 18 | 19 | true 20 | full 21 | false 22 | bin\Debug\ 23 | DEBUG;TRACE 24 | prompt 25 | 4 26 | true 27 | 28 | 29 | pdbonly 30 | true 31 | bin\Release\ 32 | TRACE 33 | prompt 34 | 4 35 | true 36 | 37 | 38 | 39 | ..\Libs\0Harmony.dll 40 | 41 | 42 | ..\Libs\Assembly-CSharp.dll 43 | 44 | 45 | ..\Libs\Assembly-CSharp-firstpass.dll 46 | 47 | 48 | ..\Libs\BepInEx.dll 49 | 50 | 51 | ..\Libs\BepInEx.Harmony.dll 52 | 53 | 54 | ..\Libs\HS2API.dll 55 | 56 | 57 | ..\Libs\HS2_ExtensibleSaveFormat.dll 58 | 59 | 60 | 61 | 62 | ..\packages\System.ValueTuple.4.5.0\lib\netstandard1.0\System.ValueTuple.dll 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | ..\Libs\Unity.Burst.dll 72 | 73 | 74 | ..\Libs\Unity.Mathematics.dll 75 | 76 | 77 | ..\Libs\UnityEngine.dll 78 | 79 | 80 | ..\Libs\UnityEngine.AnimationModule.dll 81 | 82 | 83 | ..\Libs\UnityEngine.ClothModule.dll 84 | 85 | 86 | ..\Libs\UnityEngine.CoreModule.dll 87 | 88 | 89 | ..\Libs\UnityEngine.PhysicsModule.dll 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. 104 | 105 | 106 | 107 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.rsuser 8 | *.suo 9 | *.user 10 | *.userosscache 11 | *.sln.docstates 12 | /Libs 13 | 14 | # User-specific files (MonoDevelop/Xamarin Studio) 15 | *.userprefs 16 | 17 | # Build results 18 | [Dd]ebug/ 19 | [Dd]ebugPublic/ 20 | [Rr]elease/ 21 | [Rr]eleases/ 22 | x64/ 23 | x86/ 24 | [Aa][Rr][Mm]/ 25 | [Aa][Rr][Mm]64/ 26 | bld/ 27 | [Bb]in/ 28 | [Oo]bj/ 29 | [Ll]og/ 30 | 31 | # Visual Studio 2015/2017 cache/options directory 32 | .vs/ 33 | # Uncomment if you have tasks that create the project's static files in wwwroot 34 | #wwwroot/ 35 | 36 | # Visual Studio 2017 auto generated files 37 | Generated\ Files/ 38 | 39 | # MSTest test Results 40 | [Tt]est[Rr]esult*/ 41 | [Bb]uild[Ll]og.* 42 | 43 | # NUNIT 44 | *.VisualState.xml 45 | TestResult.xml 46 | 47 | # Build Results of an ATL Project 48 | [Dd]ebugPS/ 49 | [Rr]eleasePS/ 50 | dlldata.c 51 | 52 | # Benchmark Results 53 | BenchmarkDotNet.Artifacts/ 54 | 55 | # .NET Core 56 | project.lock.json 57 | project.fragment.lock.json 58 | artifacts/ 59 | 60 | # StyleCop 61 | StyleCopReport.xml 62 | 63 | # Files built by Visual Studio 64 | *_i.c 65 | *_p.c 66 | *_h.h 67 | *.ilk 68 | *.meta 69 | *.obj 70 | *.iobj 71 | *.pch 72 | *.pdb 73 | *.ipdb 74 | *.pgc 75 | *.pgd 76 | *.rsp 77 | *.sbr 78 | *.tlb 79 | *.tli 80 | *.tlh 81 | *.tmp 82 | *.tmp_proj 83 | *_wpftmp.csproj 84 | *.log 85 | *.vspscc 86 | *.vssscc 87 | .builds 88 | *.pidb 89 | *.svclog 90 | *.scc 91 | 92 | # Chutzpah Test files 93 | _Chutzpah* 94 | 95 | # Visual C++ cache files 96 | ipch/ 97 | *.aps 98 | *.ncb 99 | *.opendb 100 | *.opensdf 101 | *.sdf 102 | *.cachefile 103 | *.VC.db 104 | *.VC.VC.opendb 105 | 106 | # Visual Studio profiler 107 | *.psess 108 | *.vsp 109 | *.vspx 110 | *.sap 111 | 112 | # Visual Studio Trace Files 113 | *.e2e 114 | 115 | # TFS 2012 Local Workspace 116 | $tf/ 117 | 118 | # Guidance Automation Toolkit 119 | *.gpState 120 | 121 | # ReSharper is a .NET coding add-in 122 | _ReSharper*/ 123 | *.[Rr]e[Ss]harper 124 | *.DotSettings.user 125 | 126 | # JustCode is a .NET coding add-in 127 | .JustCode 128 | 129 | # TeamCity is a build add-in 130 | _TeamCity* 131 | 132 | # DotCover is a Code Coverage Tool 133 | *.dotCover 134 | 135 | # AxoCover is a Code Coverage Tool 136 | .axoCover/* 137 | !.axoCover/settings.json 138 | 139 | # Visual Studio code coverage results 140 | *.coverage 141 | *.coveragexml 142 | 143 | # NCrunch 144 | _NCrunch_* 145 | .*crunch*.local.xml 146 | nCrunchTemp_* 147 | 148 | # MightyMoose 149 | *.mm.* 150 | AutoTest.Net/ 151 | 152 | # Web workbench (sass) 153 | .sass-cache/ 154 | 155 | # Installshield output folder 156 | [Ee]xpress/ 157 | 158 | # DocProject is a documentation generator add-in 159 | DocProject/buildhelp/ 160 | DocProject/Help/*.HxT 161 | DocProject/Help/*.HxC 162 | DocProject/Help/*.hhc 163 | DocProject/Help/*.hhk 164 | DocProject/Help/*.hhp 165 | DocProject/Help/Html2 166 | DocProject/Help/html 167 | 168 | # Click-Once directory 169 | publish/ 170 | 171 | # Publish Web Output 172 | *.[Pp]ublish.xml 173 | *.azurePubxml 174 | # Note: Comment the next line if you want to checkin your web deploy settings, 175 | # but database connection strings (with potential passwords) will be unencrypted 176 | *.pubxml 177 | *.publishproj 178 | 179 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 180 | # checkin your Azure Web App publish settings, but sensitive information contained 181 | # in these scripts will be unencrypted 182 | PublishScripts/ 183 | 184 | # NuGet Packages 185 | *.nupkg 186 | # The packages folder can be ignored because of Package Restore 187 | **/[Pp]ackages/* 188 | # except build/, which is used as an MSBuild target. 189 | !**/[Pp]ackages/build/ 190 | # Uncomment if necessary however generally it will be regenerated when needed 191 | #!**/[Pp]ackages/repositories.config 192 | # NuGet v3's project.json files produces more ignorable files 193 | *.nuget.props 194 | *.nuget.targets 195 | 196 | # Microsoft Azure Build Output 197 | csx/ 198 | *.build.csdef 199 | 200 | # Microsoft Azure Emulator 201 | ecf/ 202 | rcf/ 203 | 204 | # Windows Store app package directories and files 205 | AppPackages/ 206 | BundleArtifacts/ 207 | Package.StoreAssociation.xml 208 | _pkginfo.txt 209 | *.appx 210 | 211 | # Visual Studio cache files 212 | # files ending in .cache can be ignored 213 | *.[Cc]ache 214 | # but keep track of directories ending in .cache 215 | !?*.[Cc]ache/ 216 | 217 | # Others 218 | ClientBin/ 219 | ~$* 220 | *~ 221 | *.dbmdl 222 | *.dbproj.schemaview 223 | *.jfm 224 | *.pfx 225 | *.publishsettings 226 | orleans.codegen.cs 227 | 228 | # Including strong name files can present a security risk 229 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 230 | #*.snk 231 | 232 | # Since there are multiple workflows, uncomment next line to ignore bower_components 233 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 234 | #bower_components/ 235 | 236 | # RIA/Silverlight projects 237 | Generated_Code/ 238 | 239 | # Backup & report files from converting an old project file 240 | # to a newer Visual Studio version. Backup files are not needed, 241 | # because we have git ;-) 242 | _UpgradeReport_Files/ 243 | Backup*/ 244 | UpgradeLog*.XML 245 | UpgradeLog*.htm 246 | ServiceFabricBackup/ 247 | *.rptproj.bak 248 | 249 | # SQL Server files 250 | *.mdf 251 | *.ldf 252 | *.ndf 253 | 254 | # Business Intelligence projects 255 | *.rdl.data 256 | *.bim.layout 257 | *.bim_*.settings 258 | *.rptproj.rsuser 259 | *- Backup*.rdl 260 | 261 | # Microsoft Fakes 262 | FakesAssemblies/ 263 | 264 | # GhostDoc plugin setting file 265 | *.GhostDoc.xml 266 | 267 | # Node.js Tools for Visual Studio 268 | .ntvs_analysis.dat 269 | node_modules/ 270 | 271 | # Visual Studio 6 build log 272 | *.plg 273 | 274 | # Visual Studio 6 workspace options file 275 | *.opt 276 | 277 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 278 | *.vbw 279 | 280 | # Visual Studio LightSwitch build output 281 | **/*.HTMLClient/GeneratedArtifacts 282 | **/*.DesktopClient/GeneratedArtifacts 283 | **/*.DesktopClient/ModelManifest.xml 284 | **/*.Server/GeneratedArtifacts 285 | **/*.Server/ModelManifest.xml 286 | _Pvt_Extensions 287 | 288 | # Paket dependency manager 289 | .paket/paket.exe 290 | paket-files/ 291 | 292 | # FAKE - F# Make 293 | .fake/ 294 | 295 | # JetBrains Rider 296 | .idea/ 297 | *.sln.iml 298 | 299 | # CodeRush personal settings 300 | .cr/personal 301 | 302 | # Python Tools for Visual Studio (PTVS) 303 | __pycache__/ 304 | *.pyc 305 | 306 | # Cake - Uncomment if you are using it 307 | # tools/** 308 | # !tools/packages.config 309 | 310 | # Tabs Studio 311 | *.tss 312 | 313 | # Telerik's JustMock configuration file 314 | *.jmconfig 315 | 316 | # BizTalk build output 317 | *.btp.cs 318 | *.btm.cs 319 | *.odx.cs 320 | *.xsd.cs 321 | 322 | # OpenCover UI analysis results 323 | OpenCover/ 324 | 325 | # Azure Stream Analytics local run output 326 | ASALocalRun/ 327 | 328 | # MSBuild Binary and Structured Log 329 | *.binlog 330 | 331 | # NVidia Nsight GPU debugger configuration file 332 | *.nvuser 333 | 334 | # MFractors (Xamarin productivity tool) working folder 335 | .mfractor/ 336 | 337 | # Local History for Visual Studio 338 | .localhistory/ 339 | 340 | # BeatPulse healthcheck temp database 341 | healthchecksdb -------------------------------------------------------------------------------- /Deformers/Deformers.cs: -------------------------------------------------------------------------------- 1 | using AIChara; 2 | using BepInEx; 3 | using BepInEx.Logging; 4 | using ExtensibleSaveFormat; 5 | using HarmonyLib; 6 | using KKAPI; 7 | using KKAPI.Chara; 8 | using KKAPI.Maker; 9 | using MessagePack; 10 | using System; 11 | using System.Collections; 12 | using System.Collections.Generic; 13 | using System.Reflection; 14 | using UnityEngine; 15 | using Unity.Jobs; 16 | using UnityEngine.Jobs; 17 | using Unity.Collections; 18 | using Unity.Burst; 19 | 20 | [BepInDependency(KoikatuAPI.GUID, KoikatuAPI.VersionConst)] 21 | [BepInPlugin(GUID, "Deformers", Version)] 22 | public class Deformers : BaseUnityPlugin 23 | { 24 | public const string GUID = "dainty.deformers"; 25 | public const string Version = "0.6"; 26 | internal static new ManualLogSource Logger; 27 | void Awake() 28 | { 29 | Logger = base.Logger; 30 | CharacterApi.RegisterExtraBehaviour(GUID); 31 | Harmony.CreateAndPatchAll(typeof(Hooks)); 32 | AccessoriesApi.AccessoryTransferred += AccCopy; //copying destroys clothing renderer references, somehow 33 | } 34 | void AccCopy(object sender, AccessoryTransferEventArgs e) 35 | { 36 | ChaControl chaCtrl = MakerAPI.GetCharacterControl(); 37 | DeformersController deformersController = chaCtrl.GetComponent(); 38 | chaCtrl.StartCoroutine(deformersController.GetAllRenderers(false, true)); 39 | } 40 | 41 | class Hooks 42 | { 43 | [HarmonyPostfix] 44 | [HarmonyPatch(typeof(ChaControl), nameof(ChaControl.ChangeClothes), new Type[] { typeof(int), typeof(int), typeof(bool) })] 45 | private static void ChangeClothesHook(ChaControl __instance, int kind, int id) 46 | { 47 | DeformersController deformersController = __instance.GetComponent(); 48 | __instance.StartCoroutine(deformersController.GetAllRenderers()); 49 | } 50 | 51 | [HarmonyPostfix] 52 | [HarmonyPatch(typeof(ChaControl), nameof(ChaControl.ChangeHair), new Type[] { typeof(int), typeof(int), typeof(bool) })] 53 | private static void ChangeHairHook(ChaControl __instance, int kind, int id) 54 | { 55 | DeformersController deformersController = __instance.GetComponent(); 56 | __instance.StartCoroutine(deformersController.GetAllRenderers()); 57 | } 58 | 59 | [HarmonyPostfix] 60 | [HarmonyPatch(typeof(ChaControl), nameof(ChaControl.ChangeHead), new Type[] { typeof(int), typeof(bool) })] 61 | private static void ChangeHeadHook(ChaControl __instance, int _headId, bool forceChange) 62 | { 63 | DeformersController deformersController = __instance.GetComponent(); 64 | __instance.StartCoroutine(deformersController.GetAllRenderers()); 65 | } 66 | [HarmonyPostfix] 67 | [HarmonyPatch(typeof(ChaControl), nameof(ChaControl.ChangeAccessory), new Type[] { typeof(int), typeof(int), typeof(int), typeof(string), typeof(bool) })] 68 | private static void ChangeAccessoryHook(ChaControl __instance, int slotNo, int type, int id, string parentKey, bool forceChange) 69 | { 70 | DeformersController deformersController = __instance.GetComponent(); 71 | __instance.StartCoroutine(deformersController.GetAllRenderers()); 72 | } 73 | } 74 | } 75 | 76 | 77 | 78 | public class DeformersController : CharaCustomFunctionController 79 | { 80 | public Component[] Renderers { get; private set; } 81 | public Dictionary OrigMeshes { get; private set; } 82 | public List DeformerList { get; set; } 83 | List origVertices = new List(); 84 | List newVertices = new List(); 85 | List bakedVertices = new List(); 86 | Mesh bakedMesh = new Mesh(); 87 | private bool loaded = false; 88 | private float loadedTime = 0f; 89 | private List normals = new List(); 90 | private List newNormals = new List(); 91 | public Dictionary NormalDiffs { get; set; } 92 | 93 | public Dictionary DuplicateVectors { get; set; } 94 | public Dictionary> ResultList = new Dictionary>(); 95 | 96 | private string GetPartialHierarchyPath(Transform transform) 97 | { 98 | string path = transform.name; 99 | while (true) 100 | { 101 | if (transform.parent == null || transform.parent == this.transform) 102 | { 103 | break; 104 | } 105 | transform = transform.parent; 106 | path = transform.name + "/" + path; 107 | } 108 | return path; 109 | } 110 | protected override void OnCardBeingSaved(GameMode currentGameMode) 111 | { 112 | PluginData deformData = new PluginData(); 113 | 114 | foreach (Component renderer in Renderers) 115 | { 116 | if (renderer == null) 117 | { 118 | continue; 119 | } 120 | Mesh sharedMesh = GetMesh(renderer); 121 | if (sharedMesh == null) 122 | { 123 | continue; 124 | } 125 | if (!OrigMeshes.ContainsKey(sharedMesh)) 126 | { 127 | continue; 128 | } 129 | if (!sharedMesh.isReadable) 130 | { 131 | continue; 132 | } 133 | List savedVertices = new List(); 134 | sharedMesh.GetVertices(newVertices); 135 | OrigMeshes[sharedMesh].GetVertices(origVertices); 136 | for (var j = 0; j < newVertices.Count; j++) 137 | { 138 | if (newVertices[j] != origVertices[j]) 139 | { 140 | savedVertices.Add(new float[] { j, newVertices[j].x, newVertices[j].y, newVertices[j].z }); 141 | } 142 | } 143 | 144 | if (savedVertices.Count > 0) 145 | { 146 | if (deformData.data.ContainsKey(GetPartialHierarchyPath(renderer.transform) + newVertices.Count)) 147 | { 148 | continue; 149 | } 150 | deformData.data.Add(GetPartialHierarchyPath(renderer.transform) + newVertices.Count, MessagePackSerializer.Serialize(savedVertices, MessagePack.Resolvers.ContractlessStandardResolver.Instance)); 151 | } 152 | } 153 | deformData.version = 1; 154 | if (deformData.data.Count > 0) 155 | { 156 | SetExtendedData(deformData); 157 | } 158 | else 159 | { 160 | SetExtendedData(null); 161 | } 162 | } 163 | 164 | protected override void OnReload(GameMode currentGameMode, bool maintainState) 165 | { 166 | OrigMeshes = new Dictionary(); 167 | NormalDiffs = new Dictionary(); 168 | DuplicateVectors = new Dictionary(); 169 | loaded = false; 170 | StartCoroutine(GetAllRenderers(true)); 171 | } 172 | 173 | protected override void OnCoordinateBeingLoaded(ChaFileCoordinate coordinate) 174 | { 175 | StartCoroutine(GetAllRenderers(false, true)); 176 | } 177 | 178 | public Mesh GetMesh(Component renderer) 179 | { 180 | if (renderer is SkinnedMeshRenderer skinnedMeshRenderer) 181 | { 182 | return skinnedMeshRenderer.sharedMesh; 183 | } 184 | if (renderer is MeshRenderer meshRenderer) 185 | { 186 | if (meshRenderer.material.name.StartsWith("Filter")) //dumb way of not deforming deformers 187 | { 188 | return null; 189 | } 190 | return meshRenderer.GetComponent().sharedMesh; 191 | } 192 | return null; 193 | } 194 | 195 | public void SetMesh(Component renderer, Mesh mesh) 196 | { 197 | if (renderer is SkinnedMeshRenderer skinnedMeshRenderer) 198 | { 199 | skinnedMeshRenderer.sharedMesh = mesh; 200 | if (skinnedMeshRenderer.gameObject.GetComponent() != null) 201 | { 202 | CopyCloth(skinnedMeshRenderer.gameObject); 203 | } 204 | } 205 | if (renderer is MeshRenderer meshRenderer) 206 | { 207 | meshRenderer.GetComponent().sharedMesh = mesh; 208 | } 209 | } 210 | public static void CopyCloth(GameObject renderer) //cloth component bugs out if you replace the mesh and then disable and enable the gameobject 211 | { 212 | GameObject copy = Instantiate(renderer); 213 | Cloth clothCopy = copy.GetComponent(); 214 | 215 | DestroyImmediate(renderer.GetComponent()); 216 | Cloth clothOrig = renderer.AddComponent(); 217 | 218 | string name = renderer.name; 219 | 220 | Transform ancestor = clothOrig.transform; 221 | while (ancestor.parent != null) 222 | { 223 | ancestor = ancestor.parent; 224 | ancestor.gameObject.SetActive(true); 225 | if (clothOrig.gameObject.activeInHierarchy == true) 226 | { 227 | break; 228 | } 229 | } 230 | foreach (PropertyInfo x in typeof(Cloth).GetProperties()) 231 | { 232 | if (x.CanWrite) 233 | x.SetValue(clothOrig, x.GetValue(clothCopy)); 234 | } 235 | clothOrig.clothSolverFrequency = clothCopy.clothSolverFrequency; 236 | renderer.name = name; 237 | 238 | copy.SetActive(false); 239 | Destroy(copy); 240 | } 241 | 242 | public IEnumerator GetAllRenderers(bool reload = false, bool deform = false) 243 | { 244 | yield return new WaitForSeconds(0.5f); //renderers/meshes get replaced by plugins at some point, I tried hooking the load manually and setting priority to last, doesn't work. Something async I guess. 245 | 246 | Renderers = transform.GetComponentsInChildren(typeof(Renderer), true); 247 | foreach (Component renderer in Renderers) 248 | { 249 | Mesh sharedMesh = GetMesh(renderer); 250 | if (sharedMesh == null) 251 | { 252 | continue; 253 | } 254 | if (OrigMeshes.ContainsKey(sharedMesh)) 255 | { 256 | continue; 257 | } 258 | Mesh copyMesh = Instantiate(sharedMesh); 259 | if (!sharedMesh.isReadable) 260 | { 261 | Deformers.Logger.LogWarning("Cannot deform " + sharedMesh.name + ", not read/write enabled."); 262 | copyMesh = sharedMesh; 263 | } 264 | OrigMeshes.Add(copyMesh, sharedMesh); 265 | String name = sharedMesh.name; 266 | copyMesh.name = name; 267 | SetMesh(renderer, copyMesh); 268 | 269 | if (!sharedMesh.isReadable) 270 | { 271 | continue; 272 | } 273 | copyMesh.GetNormals(normals); 274 | copyMesh.RecalculateNormals(); 275 | copyMesh.GetNormals(newNormals); 276 | Quaternion[] normalDiffs = new Quaternion[newNormals.Count]; 277 | for (int i = 0; i < normals.Count; i++) 278 | { 279 | normalDiffs[i] = Quaternion.FromToRotation(newNormals[i], normals[i]); 280 | } 281 | NormalDiffs.Add(copyMesh, normalDiffs); 282 | copyMesh.SetNormals(normals); 283 | 284 | Dictionary duplicateCheck = new Dictionary(); 285 | sharedMesh.GetVertices(origVertices); 286 | int[] duplicates = new int[origVertices.Count]; 287 | for (int i = 0; i < origVertices.Count; i++) 288 | { 289 | if (duplicateCheck.ContainsKey(origVertices[i])) 290 | { 291 | duplicates[i] = duplicateCheck[origVertices[i]]; 292 | } 293 | else 294 | { 295 | duplicateCheck.Add(origVertices[i], i); 296 | } 297 | } 298 | DuplicateVectors.Add(copyMesh, duplicates); 299 | } 300 | 301 | if (reload) 302 | { 303 | PluginData deformData = GetExtendedData(); 304 | if (deformData != null) 305 | { 306 | foreach (Component renderer in Renderers) 307 | { 308 | if (renderer == null) 309 | { 310 | continue; 311 | } 312 | Mesh sharedMesh = GetMesh(renderer); 313 | if (sharedMesh == null) 314 | { 315 | continue; 316 | } 317 | if (!sharedMesh.isReadable) 318 | { 319 | continue; 320 | } 321 | sharedMesh.GetVertices(newVertices); 322 | if (deformData.data.TryGetValue(GetPartialHierarchyPath(renderer.transform) + newVertices.Count, out object t)) 323 | { 324 | List savedVertices = MessagePackSerializer.Deserialize>((byte[])t, MessagePack.Resolvers.ContractlessStandardResolver.Instance); 325 | for (var i = 0; i < savedVertices.Count; i++) 326 | { 327 | float[] savedVertex = savedVertices[i]; 328 | newVertices[(int)savedVertex[0]] = new Vector3(savedVertex[1], savedVertex[2], savedVertex[3]); 329 | } 330 | 331 | sharedMesh.SetVertices(newVertices); 332 | 333 | sharedMesh.RecalculateNormals(); 334 | sharedMesh.GetNormals(newNormals); 335 | NativeArray nativeNewNormals = new NativeArray(newNormals.ToArray(), Allocator.Temp); 336 | NativeArray nativeReadOnlyNewNormals = new NativeArray(nativeNewNormals, Allocator.Temp); 337 | Quaternion[] normalDiffs = NormalDiffs[sharedMesh]; 338 | NativeArray nativeNormalDiffs = new NativeArray(normalDiffs, Allocator.Temp); 339 | int[] duplicates = DuplicateVectors[sharedMesh]; 340 | NativeArray nativeDuplicates = new NativeArray(duplicates, Allocator.Temp); 341 | 342 | NormalDiffsJob normalDiffsJob = new NormalDiffsJob 343 | { 344 | nativeNewNormals = nativeNewNormals, 345 | nativeReadOnlyNewNormals = nativeReadOnlyNewNormals, 346 | nativeNormalDiffs = nativeNormalDiffs 347 | }; 348 | JobHandle diffsHandle = normalDiffsJob.Schedule(nativeNewNormals.Length, 32); 349 | 350 | DuplicatesJob duplicatesJob = new DuplicatesJob 351 | { 352 | nativeNewNormals = nativeNewNormals, 353 | nativeReadOnlyNewNormals = nativeReadOnlyNewNormals, 354 | nativeDuplicates = nativeDuplicates 355 | }; 356 | JobHandle duplicatesHandle = duplicatesJob.Schedule(nativeNewNormals.Length, 32, diffsHandle); 357 | duplicatesHandle.Complete(); 358 | newNormals.Clear(); 359 | newNormals.AddRange(nativeNewNormals); 360 | sharedMesh.SetNormals(newNormals); 361 | } 362 | } 363 | } 364 | loaded = true; 365 | loadedTime = Time.time; 366 | } 367 | 368 | if (deform) 369 | { 370 | StartCoroutine(WaitDeform()); 371 | } 372 | } 373 | 374 | public void DeformAll() 375 | { 376 | if (loaded == false) 377 | { 378 | return; 379 | } 380 | if ((Time.time - loadedTime) < 1) 381 | { 382 | return; 383 | } 384 | if (DeformerList == null || Renderers == null) 385 | { 386 | return; 387 | } 388 | NativeArray HandeList = new NativeArray(Renderers.Length, Allocator.Temp); 389 | for (int i = 0; i < Renderers.Length; i++) { 390 | 391 | Renderer renderer = (Renderer)Renderers[i]; 392 | if (renderer == null) 393 | { 394 | continue; 395 | } 396 | Mesh sharedMesh = GetMesh(renderer); 397 | if (sharedMesh == null) 398 | { 399 | continue; 400 | } 401 | if (!OrigMeshes.ContainsKey(sharedMesh)) 402 | { 403 | continue; 404 | } 405 | if (!sharedMesh.isReadable) 406 | { 407 | continue; 408 | } 409 | 410 | OrigMeshes[sharedMesh].GetVertices(newVertices); 411 | sharedMesh.SetVertices(newVertices); 412 | OrigMeshes[sharedMesh].GetNormals(normals); 413 | sharedMesh.SetNormals(normals); 414 | 415 | bool skip = true; 416 | foreach (Deformer deformer in DeformerList) 417 | { 418 | if (deformer.FilterMaterial.shader.name != "Standard") 419 | { 420 | foreach (Material material in ((Renderer)renderer).materials) 421 | { 422 | if (material.shader.name == deformer.FilterMaterial.shader.name) 423 | { 424 | skip = false; 425 | break; 426 | } 427 | } 428 | if (skip == false) break; 429 | } 430 | else 431 | { 432 | skip = false; 433 | break; 434 | } 435 | } 436 | if (skip) continue; 437 | 438 | Transform rendererTransform = renderer.transform; 439 | Transform parent = rendererTransform.parent; 440 | Vector3 localScale = rendererTransform.localScale; 441 | 442 | Matrix4x4[] boneMatrices = null; 443 | BoneWeight[] boneWeights = null; 444 | NativeArray nativeNewVertices = new NativeArray(newVertices.ToArray(), Allocator.Temp); 445 | NativeArray nativeboneMatrices = default; 446 | NativeArray nativeBoneWeights = default; 447 | 448 | Matrix4x4 rootBoneWorldToLocalMatrix = new Matrix4x4(); 449 | bool skinned = false; 450 | 451 | if (renderer is SkinnedMeshRenderer skinnedMeshRenderer) 452 | { 453 | skinned = true; 454 | 455 | rendererTransform.parent = null; 456 | localScale = rendererTransform.localScale; 457 | rendererTransform.localScale = Vector3.one; 458 | 459 | Transform[] skinnedBones = skinnedMeshRenderer.bones; 460 | boneMatrices = new Matrix4x4[skinnedBones.Length]; 461 | boneWeights = skinnedMeshRenderer.sharedMesh.boneWeights; 462 | Matrix4x4[] meshBindposes = skinnedMeshRenderer.sharedMesh.bindposes; 463 | 464 | if (boneWeights.Length > 0) 465 | { 466 | skinnedMeshRenderer.BakeMesh(bakedMesh); 467 | bakedMesh.GetVertices(bakedVertices); 468 | 469 | for (int j = 0; j < boneMatrices.Length; j++) 470 | { 471 | if (skinnedBones[j] != null && meshBindposes[j] != null) 472 | { 473 | boneMatrices[j] = skinnedBones[j].localToWorldMatrix * meshBindposes[j]; 474 | } 475 | else 476 | { 477 | boneMatrices[j] = Matrix4x4.identity; 478 | } 479 | } 480 | nativeboneMatrices = new NativeArray(boneMatrices, Allocator.Temp); 481 | nativeBoneWeights = new NativeArray(boneWeights, Allocator.Temp); 482 | } 483 | else 484 | { 485 | bakedVertices = new List(newVertices); 486 | Transform rootBone = skinnedMeshRenderer.rootBone; 487 | rootBoneWorldToLocalMatrix = rootBone.worldToLocalMatrix; 488 | for (int j = 0; j < bakedVertices.Count; j++) 489 | { 490 | bakedVertices[j] = rootBone.TransformPoint(bakedVertices[j]); 491 | bakedVertices[j] = rendererTransform.InverseTransformPoint(bakedVertices[j]); 492 | } 493 | } 494 | } 495 | else if (renderer is MeshRenderer meshRenderer) 496 | { 497 | bakedVertices = new List(newVertices); 498 | for (int j = 0; j < bakedVertices.Count; j++) 499 | { 500 | bakedVertices[j] = rendererTransform.TransformPoint(bakedVertices[j]); 501 | } 502 | } 503 | else 504 | { 505 | continue; 506 | } 507 | 508 | NativeArray nativeBakedVertices = new NativeArray(bakedVertices.ToArray(), Allocator.Temp); 509 | NativeArray deformed = new NativeArray(1, Allocator.Temp); 510 | deformed[0] = false; 511 | NativeArray nativeNormals = new NativeArray(normals.ToArray(), Allocator.Temp); 512 | foreach (Deformer deformer in DeformerList) 513 | { 514 | if (!deformer.gameObject.activeInHierarchy) 515 | { 516 | continue; 517 | } 518 | if (deformer.FilterMaterial.shader.name != "Standard") 519 | { 520 | foreach (Material material in (renderer).materials) 521 | { 522 | if (material.shader.name == deformer.FilterMaterial.shader.name) 523 | { 524 | deformer.Deform(nativeNewVertices, nativeBakedVertices, nativeboneMatrices, nativeBoneWeights, rendererTransform.localToWorldMatrix, rendererTransform.worldToLocalMatrix, rootBoneWorldToLocalMatrix, skinned, deformed, nativeNormals); 525 | break; 526 | } 527 | } 528 | } 529 | else 530 | { 531 | deformer.Deform(nativeNewVertices, nativeBakedVertices, nativeboneMatrices, nativeBoneWeights, rendererTransform.localToWorldMatrix, rendererTransform.worldToLocalMatrix, rootBoneWorldToLocalMatrix, skinned, deformed, nativeNormals); 532 | } 533 | } 534 | 535 | rendererTransform.localScale = localScale; 536 | rendererTransform.parent = parent; 537 | if (!deformed[0]) 538 | { 539 | continue; 540 | } 541 | newVertices.Clear(); 542 | newVertices.AddRange(nativeNewVertices); 543 | sharedMesh.SetVertices(newVertices); 544 | 545 | sharedMesh.RecalculateNormals(); 546 | sharedMesh.GetNormals(newNormals); 547 | NativeArray nativeNewNormals = new NativeArray(newNormals.ToArray(), Allocator.Temp); 548 | NativeArray nativeReadOnlyNewNormals = new NativeArray(nativeNewNormals, Allocator.Temp); 549 | Quaternion[] normalDiffs = NormalDiffs[sharedMesh]; 550 | NativeArray nativeNormalDiffs = new NativeArray(normalDiffs, Allocator.Temp); 551 | int[] duplicates = DuplicateVectors[sharedMesh]; 552 | NativeArray nativeDuplicates = new NativeArray(duplicates, Allocator.Temp); 553 | 554 | NormalDiffsJob normalDiffsJob = new NormalDiffsJob 555 | { 556 | nativeNewNormals = nativeNewNormals, 557 | nativeReadOnlyNewNormals = nativeReadOnlyNewNormals, 558 | nativeNormalDiffs = nativeNormalDiffs 559 | }; 560 | JobHandle diffsHandle = normalDiffsJob.Schedule(nativeNewNormals.Length, 32); 561 | 562 | DuplicatesJob duplicatesJob = new DuplicatesJob 563 | { 564 | nativeNewNormals = nativeNewNormals, 565 | nativeReadOnlyNewNormals = nativeReadOnlyNewNormals, 566 | nativeDuplicates = nativeDuplicates 567 | }; 568 | JobHandle duplicatesHandle = duplicatesJob.Schedule(nativeNewNormals.Length, 32, diffsHandle); 569 | HandeList[i] = duplicatesHandle; 570 | ResultList.Add(sharedMesh, nativeNewNormals); 571 | } 572 | JobHandle.CompleteAll(HandeList); 573 | foreach (KeyValuePair> result in ResultList) 574 | { 575 | newNormals.Clear(); 576 | newNormals.AddRange(result.Value); 577 | result.Key.SetNormals(newNormals); 578 | } 579 | ResultList.Clear(); 580 | } 581 | 582 | [BurstCompile] 583 | public struct NormalDiffsJob : IJobParallelFor 584 | { 585 | public NativeArray nativeNewNormals; 586 | public NativeArray nativeReadOnlyNewNormals; 587 | public NativeArray nativeNormalDiffs; 588 | 589 | public void Execute(int index) 590 | { 591 | nativeNewNormals[index] = nativeNormalDiffs[index] * nativeNewNormals[index]; 592 | nativeReadOnlyNewNormals[index] = nativeNewNormals[index]; 593 | } 594 | } 595 | 596 | [BurstCompile] 597 | public struct DuplicatesJob : IJobParallelFor 598 | { 599 | public NativeArray nativeNewNormals; 600 | public NativeArray nativeReadOnlyNewNormals; 601 | public NativeArray nativeDuplicates; 602 | 603 | public void Execute(int index) 604 | { 605 | if (nativeDuplicates[index] != 0) 606 | { 607 | nativeNewNormals[index] = nativeReadOnlyNewNormals[nativeDuplicates[index]]; 608 | } 609 | } 610 | } 611 | 612 | internal void AddDeformer(Deformer deformer) 613 | { 614 | if (DeformerList == null) 615 | { 616 | DeformerList = new List(); 617 | } 618 | DeformerList.Add(deformer); 619 | DeformerList.Sort((x, y) => x.AccessoryIndex.CompareTo(y.AccessoryIndex)); //sort deformers top to bottom 620 | StartCoroutine(WaitDeform()); 621 | } 622 | 623 | internal void RemoveDeformer(Deformer deformer) 624 | { 625 | DeformerList.Remove(deformer); 626 | if (gameObject.activeInHierarchy) 627 | { 628 | StartCoroutine(WaitDeform()); 629 | } 630 | } 631 | internal IEnumerator WaitDeform() //when stuff happens before skinning 632 | { 633 | yield return new WaitForEndOfFrame(); 634 | DeformAll(); 635 | } 636 | } 637 | 638 | public abstract class Deformer : MonoBehaviour 639 | { 640 | public Transform N1; 641 | public Transform N2; 642 | public Transform SphereA; 643 | public Transform SphereB; 644 | private Vector3 oldN1Position = Vector3.zero; 645 | private Vector3 oldN1Rotation = Vector3.zero; 646 | private Vector3 oldN1Scale = Vector3.zero; 647 | private Vector3 oldN2Position = Vector3.zero; 648 | private Vector3 oldN2Rotation = Vector3.zero; 649 | private Vector3 oldN2Scale = Vector3.zero; 650 | public DeformersController deformersController; 651 | public int AccessoryIndex { get; internal set; } 652 | public Material FilterMaterial { get; internal set; } 653 | public string oldShaderName { get; internal set; } 654 | public float radius = 1.09f; 655 | public float falloff = 1; 656 | public float strength = 0.2f; 657 | public float axisWeight = 1f; 658 | public float height = 1f; 659 | public Vector3 point1; 660 | public Vector3 point2; 661 | public Vector3 sphereA; 662 | public Vector3 sphereB; 663 | public SelectorType selectorType = SelectorType.Sphere; 664 | 665 | public enum SelectorType 666 | { 667 | Sphere, 668 | Capsule 669 | } 670 | 671 | void Start() 672 | { 673 | N1 = GetComponent().trfMove01; 674 | N2 = GetComponent().trfMove02; 675 | 676 | FilterMaterial = ((Renderer)N1.GetComponentInChildren(true)).materials[0]; //renderer is disabled when alpha = 0 677 | oldShaderName = FilterMaterial.shader.name; 678 | 679 | oldN1Position = N1.localPosition; 680 | oldN1Rotation = N1.localEulerAngles; 681 | oldN1Scale = N1.localScale; 682 | 683 | oldN2Position = N2.localPosition; 684 | oldN2Rotation = N2.localEulerAngles; 685 | oldN2Scale = N2.localScale; 686 | 687 | Transform ancestor = transform; 688 | while (ancestor.parent != null) 689 | { 690 | ancestor = ancestor.parent; 691 | if (ancestor.GetComponent() != null) 692 | { 693 | deformersController = ancestor.GetComponent(); 694 | break; 695 | } 696 | } 697 | AccessoryIndex = AccessoriesApi.GetAccessoryIndex(deformersController.GetComponent(), gameObject); 698 | deformersController.AddDeformer(this); 699 | } 700 | 701 | void OnDestroy() 702 | { 703 | deformersController.RemoveDeformer(this); 704 | } 705 | 706 | void OnDisable() 707 | { 708 | deformersController.DeformAll(); 709 | } 710 | 711 | void OnEnable() 712 | { 713 | if(deformersController != null) 714 | { 715 | deformersController.DeformAll(); 716 | } 717 | } 718 | 719 | void Update() 720 | { 721 | if (N1.localScale != oldN1Scale) 722 | { 723 | Vector3[,] addMove = deformersController.GetComponent().nowCoordinate.accessory.parts[AccessoryIndex].addMove; 724 | Vector3 scale = N1.localScale; 725 | if (selectorType == SelectorType.Sphere) 726 | { 727 | scale = new Vector3(N1.localScale.x, N1.localScale.x, N1.localScale.x); 728 | N1.localScale = scale; 729 | } 730 | if (selectorType == SelectorType.Capsule) 731 | { 732 | scale = new Vector3(N1.localScale.x, N1.localScale.y, N1.localScale.x); 733 | N1.localScale = scale; 734 | SphereA.localScale = new Vector3(1 / N1.localScale.x, 1 / N1.localScale.y, 1 / N1.localScale.z) * N1.localScale.x; 735 | SphereB.localScale = SphereA.localScale; 736 | } 737 | addMove[0, 2] = scale; 738 | deformersController.GetComponent().nowCoordinate.accessory.parts[AccessoryIndex].addMove = addMove; 739 | N1.localScale = scale; 740 | if (MakerAPI.InsideMaker) 741 | { 742 | AccessoriesApi.GetCvsAccessory().UpdateCustomUI(); 743 | } 744 | deformersController.DeformAll(); 745 | } 746 | else if (N1.localPosition != oldN1Position || N1.localEulerAngles != oldN1Rotation || 747 | N2.localPosition != oldN2Position || N2.localEulerAngles != oldN2Rotation || N2.localScale != oldN2Scale || 748 | oldShaderName != FilterMaterial.shader.name) 749 | { 750 | deformersController.DeformAll(); 751 | } 752 | 753 | oldN1Position = N1.localPosition; 754 | oldN1Rotation = N1.localEulerAngles; 755 | oldN1Scale = N1.localScale; 756 | 757 | oldN2Position = N2.localPosition; 758 | oldN2Rotation = N2.localEulerAngles; 759 | oldN2Scale = N2.localScale; 760 | 761 | oldShaderName = FilterMaterial.shader.name; 762 | } 763 | 764 | public abstract void Deform(NativeArray nativeNewVertices, NativeArray nativeBakedVertices, NativeArray nativeBoneMatrices, NativeArray nativeBoneWeights, Matrix4x4 RendererLocalToWorldMatrix, Matrix4x4 RendererWorldToLocalMatrix, Matrix4x4 RootBoneWorldToLocalMatrix, bool skinned, NativeArray deformed, NativeArray nativeNormals); 765 | 766 | public static Matrix4x4 GetReverseSkinningMatrix(NativeArray boneMatrices, BoneWeight weight) 767 | { 768 | Matrix4x4 bm0; 769 | Matrix4x4 bm1; 770 | Matrix4x4 bm2; 771 | Matrix4x4 bm3; 772 | Matrix4x4 reverseSkinningMatrix = new Matrix4x4(); 773 | bm0 = boneMatrices[weight.boneIndex0].inverse; 774 | bm1 = boneMatrices[weight.boneIndex1].inverse; 775 | bm2 = boneMatrices[weight.boneIndex2].inverse; 776 | bm3 = boneMatrices[weight.boneIndex3].inverse; 777 | 778 | reverseSkinningMatrix.m00 = bm0.m00 * weight.weight0 + bm1.m00 * weight.weight1 + bm2.m00 * weight.weight2 + bm3.m00 * weight.weight3; 779 | reverseSkinningMatrix.m01 = bm0.m01 * weight.weight0 + bm1.m01 * weight.weight1 + bm2.m01 * weight.weight2 + bm3.m01 * weight.weight3; 780 | reverseSkinningMatrix.m02 = bm0.m02 * weight.weight0 + bm1.m02 * weight.weight1 + bm2.m02 * weight.weight2 + bm3.m02 * weight.weight3; 781 | reverseSkinningMatrix.m03 = bm0.m03 * weight.weight0 + bm1.m03 * weight.weight1 + bm2.m03 * weight.weight2 + bm3.m03 * weight.weight3; 782 | 783 | reverseSkinningMatrix.m10 = bm0.m10 * weight.weight0 + bm1.m10 * weight.weight1 + bm2.m10 * weight.weight2 + bm3.m10 * weight.weight3; 784 | reverseSkinningMatrix.m11 = bm0.m11 * weight.weight0 + bm1.m11 * weight.weight1 + bm2.m11 * weight.weight2 + bm3.m11 * weight.weight3; 785 | reverseSkinningMatrix.m12 = bm0.m12 * weight.weight0 + bm1.m12 * weight.weight1 + bm2.m12 * weight.weight2 + bm3.m12 * weight.weight3; 786 | reverseSkinningMatrix.m13 = bm0.m13 * weight.weight0 + bm1.m13 * weight.weight1 + bm2.m13 * weight.weight2 + bm3.m13 * weight.weight3; 787 | 788 | reverseSkinningMatrix.m20 = bm0.m20 * weight.weight0 + bm1.m20 * weight.weight1 + bm2.m20 * weight.weight2 + bm3.m20 * weight.weight3; 789 | reverseSkinningMatrix.m21 = bm0.m21 * weight.weight0 + bm1.m21 * weight.weight1 + bm2.m21 * weight.weight2 + bm3.m21 * weight.weight3; 790 | reverseSkinningMatrix.m22 = bm0.m22 * weight.weight0 + bm1.m22 * weight.weight1 + bm2.m22 * weight.weight2 + bm3.m22 * weight.weight3; 791 | reverseSkinningMatrix.m23 = bm0.m23 * weight.weight0 + bm1.m23 * weight.weight1 + bm2.m23 * weight.weight2 + bm3.m23 * weight.weight3; 792 | 793 | return reverseSkinningMatrix; 794 | } 795 | 796 | public static Vector3 BakedToNewVertex(Vector3 bakedVertex, Matrix4x4 RendererWorldToLocalMatrix, Matrix4x4 RendererLocalToWorldMatrix, Matrix4x4 RootBoneWorldToLocalMatrix, NativeArray boneMatrices, NativeArray boneWeights, int index, bool skinned) 797 | { 798 | Vector3 newVertex; 799 | if (skinned == false) 800 | { 801 | newVertex = RendererWorldToLocalMatrix.MultiplyPoint3x4(bakedVertex); 802 | return newVertex; 803 | } 804 | if (boneWeights.Length > 0) 805 | { 806 | BoneWeight weight = boneWeights[index]; 807 | Matrix4x4 reverseSkinningMatrix = GetReverseSkinningMatrix(boneMatrices, weight); 808 | newVertex = reverseSkinningMatrix.MultiplyPoint3x4(RendererLocalToWorldMatrix.MultiplyPoint3x4(bakedVertex)); 809 | } 810 | else 811 | { 812 | Vector3 v = RendererLocalToWorldMatrix.MultiplyPoint3x4(bakedVertex); 813 | newVertex = RootBoneWorldToLocalMatrix.MultiplyPoint3x4(v); 814 | } 815 | return newVertex; 816 | } 817 | 818 | public void SetDeformParams() 819 | { 820 | radius = N1.localScale.x / 2; 821 | strength = N2.localScale.x; 822 | height = (N1.localScale.y / 2) + radius; 823 | falloff = N2.localScale.y; 824 | axisWeight = N2.localScale.z; 825 | if (falloff == 0.01f) 826 | { 827 | falloff = 0f; 828 | } 829 | if (strength == 0.01f) 830 | { 831 | strength = 0f; 832 | } 833 | if (axisWeight == 0.01f) 834 | { 835 | axisWeight = 0f; 836 | } 837 | } 838 | 839 | public void SetPoints(Matrix4x4 RendererWorldToLocalMatrix, bool skinned) 840 | { 841 | point1 = N1.position; 842 | point2 = N2.position; 843 | if (skinned) 844 | { 845 | point1 = RendererWorldToLocalMatrix.MultiplyPoint3x4(point1); 846 | point2 = RendererWorldToLocalMatrix.MultiplyPoint3x4(point2); 847 | } 848 | if (selectorType == SelectorType.Capsule) 849 | { 850 | sphereA = SphereA.position; 851 | sphereB = SphereB.position; 852 | if (skinned) 853 | { 854 | sphereA = RendererWorldToLocalMatrix.MultiplyPoint3x4(sphereA); 855 | sphereB = RendererWorldToLocalMatrix.MultiplyPoint3x4(sphereB); 856 | } 857 | } 858 | } 859 | } 860 | 861 | public class Expander : Deformer 862 | { 863 | [BurstCompile] 864 | public struct DeformJob : IJobParallelFor 865 | { 866 | public float radius; 867 | public float falloff; 868 | public float strength; 869 | public NativeArray nativeNewVertices; 870 | public NativeArray nativeBakedVertices; 871 | public Vector3 point1; 872 | public Vector3 point2; 873 | public NativeArray nativeboneMatrices; 874 | public NativeArray nativeBoneWeights; 875 | public Matrix4x4 RendererWorldToLocalMatrix; 876 | public Matrix4x4 RendererLocalToWorldMatrix; 877 | public Matrix4x4 RootBoneWorldToLocalMatrix; 878 | public bool skinned; 879 | public NativeArray deformed; 880 | public SelectorType selectorType; 881 | public Vector3 sphereA; 882 | public Vector3 sphereB; 883 | public float height; 884 | public float axisWeight; 885 | public NativeArray nativeNormals; 886 | 887 | public void Execute(int index) 888 | { 889 | if (selectorType == SelectorType.Sphere) 890 | { 891 | float distance = Vector3.Distance(nativeBakedVertices[index], point1); 892 | if (distance < radius) 893 | { 894 | deformed[0] = true; 895 | float factor = 1 - ((distance / radius) * falloff); 896 | nativeBakedVertices[index] = Vector3.Lerp(nativeBakedVertices[index], nativeBakedVertices[index] + (nativeNormals[index].normalized / 10), strength * factor); 897 | nativeNewVertices[index] = BakedToNewVertex(nativeBakedVertices[index], RendererWorldToLocalMatrix, RendererLocalToWorldMatrix, RootBoneWorldToLocalMatrix, nativeboneMatrices, nativeBoneWeights, index, skinned); 898 | } 899 | } 900 | if (selectorType == SelectorType.Capsule) 901 | { 902 | Vector3 sphereVector = sphereB - sphereA; 903 | Vector3 capsuleEndA = sphereA - (radius * sphereVector.normalized); 904 | Vector3 capsuleEndB = sphereB + (radius * sphereVector.normalized); 905 | Vector3 capsuleVector = capsuleEndB - capsuleEndA; 906 | Vector3 p = nativeBakedVertices[index] - capsuleEndA; 907 | float dot = p.x * capsuleVector.x + p.y * capsuleVector.y + p.z * capsuleVector.z; 908 | float lengthsq = capsuleVector.sqrMagnitude; 909 | if ((dot > 0f) && (dot < lengthsq)) 910 | { 911 | Vector3 closestPointOnAxis; 912 | float f = Vector3.Dot(nativeBakedVertices[index] - sphereA, sphereVector.normalized); 913 | if (f < 0) 914 | { 915 | closestPointOnAxis = sphereA; 916 | } 917 | else if (f > sphereVector.magnitude) 918 | { 919 | closestPointOnAxis = sphereB; 920 | } 921 | else closestPointOnAxis = sphereA + (f * sphereVector.normalized); 922 | 923 | float axisDistance = Vector3.Distance(closestPointOnAxis, nativeBakedVertices[index]); 924 | if (axisDistance < radius) 925 | { 926 | deformed[0] = true; 927 | closestPointOnAxis = sphereA + (f * sphereVector.normalized); 928 | axisDistance = Vector3.Distance(closestPointOnAxis, nativeBakedVertices[index]); 929 | float axisFactor = 1 - ((axisDistance / radius) * falloff); 930 | 931 | float centerDistance = Vector3.Distance(point1, nativeBakedVertices[index]); 932 | float centerFactor = 1 - ((centerDistance / height) * falloff); 933 | 934 | float factor = Mathf.Lerp(axisFactor, centerFactor, axisWeight); 935 | nativeBakedVertices[index] = Vector3.Lerp(nativeBakedVertices[index], nativeBakedVertices[index] + (nativeNormals[index].normalized / 10), strength * factor); 936 | nativeNewVertices[index] = BakedToNewVertex(nativeBakedVertices[index], RendererWorldToLocalMatrix, RendererLocalToWorldMatrix, RootBoneWorldToLocalMatrix, nativeboneMatrices, nativeBoneWeights, index, skinned); 937 | } 938 | } 939 | } 940 | } 941 | } 942 | 943 | public override void Deform(NativeArray nativeNewVertices, NativeArray nativeBakedVertices, NativeArray nativeboneMatrices, NativeArray nativeBoneWeights, Matrix4x4 RendererLocalToWorldMatrix, Matrix4x4 RendererWorldToLocalMatrix, Matrix4x4 RootBoneWorldToLocalMatrix, bool skinned, NativeArray deformed, NativeArray nativeNormals) 944 | { 945 | SetDeformParams(); 946 | SetPoints(RendererWorldToLocalMatrix, skinned); 947 | 948 | DeformJob deformJob = new DeformJob 949 | { 950 | nativeNewVertices = nativeNewVertices, 951 | nativeBakedVertices = nativeBakedVertices, 952 | radius = radius, 953 | falloff = falloff, 954 | strength = strength, 955 | point1 = point1, 956 | point2 = point2, 957 | RendererLocalToWorldMatrix = RendererLocalToWorldMatrix, 958 | RendererWorldToLocalMatrix = RendererWorldToLocalMatrix, 959 | RootBoneWorldToLocalMatrix = RootBoneWorldToLocalMatrix, 960 | nativeBoneWeights = nativeBoneWeights, 961 | nativeboneMatrices = nativeboneMatrices, 962 | skinned = skinned, 963 | deformed = deformed, 964 | selectorType = selectorType, 965 | sphereA = sphereA, 966 | sphereB = sphereB, 967 | axisWeight = axisWeight, 968 | height = height, 969 | nativeNormals = nativeNormals 970 | }; 971 | 972 | JobHandle jobHandle = deformJob.Schedule(nativeNewVertices.Length, 32); 973 | jobHandle.Complete(); 974 | } 975 | } 976 | 977 | public class Shrinker : Deformer 978 | { 979 | [BurstCompile] 980 | public struct DeformJob : IJobParallelFor 981 | { 982 | public float radius; 983 | public float falloff; 984 | public float strength; 985 | public NativeArray nativeNewVertices; 986 | public NativeArray nativeBakedVertices; 987 | public Vector3 point1; 988 | public Vector3 point2; 989 | public NativeArray nativeboneMatrices; 990 | public NativeArray nativeBoneWeights; 991 | public Matrix4x4 RendererWorldToLocalMatrix; 992 | public Matrix4x4 RendererLocalToWorldMatrix; 993 | public Matrix4x4 RootBoneWorldToLocalMatrix; 994 | public bool skinned; 995 | public NativeArray deformed; 996 | public SelectorType selectorType; 997 | public Vector3 sphereA; 998 | public Vector3 sphereB; 999 | public float height; 1000 | public float axisWeight; 1001 | public NativeArray nativeNormals; 1002 | 1003 | public void Execute(int index) 1004 | { 1005 | if (selectorType == SelectorType.Sphere) 1006 | { 1007 | float distance = Vector3.Distance(nativeBakedVertices[index], point1); 1008 | if (distance < radius) 1009 | { 1010 | deformed[0] = true; 1011 | float factor = 1 - ((distance / radius) * falloff); 1012 | nativeBakedVertices[index] = Vector3.Lerp(nativeBakedVertices[index], nativeBakedVertices[index] - (nativeNormals[index].normalized/10), strength * factor); 1013 | nativeNewVertices[index] = BakedToNewVertex(nativeBakedVertices[index], RendererWorldToLocalMatrix, RendererLocalToWorldMatrix, RootBoneWorldToLocalMatrix, nativeboneMatrices, nativeBoneWeights, index, skinned); 1014 | } 1015 | } 1016 | if (selectorType == SelectorType.Capsule) 1017 | { 1018 | Vector3 sphereVector = sphereB - sphereA; 1019 | Vector3 capsuleEndA = sphereA - (radius * sphereVector.normalized); 1020 | Vector3 capsuleEndB = sphereB + (radius * sphereVector.normalized); 1021 | Vector3 capsuleVector = capsuleEndB - capsuleEndA; 1022 | Vector3 p = nativeBakedVertices[index] - capsuleEndA; 1023 | float dot = p.x * capsuleVector.x + p.y * capsuleVector.y + p.z * capsuleVector.z; 1024 | float lengthsq = capsuleVector.sqrMagnitude; 1025 | if ((dot > 0f) && (dot < lengthsq)) 1026 | { 1027 | Vector3 closestPointOnAxis; 1028 | float f = Vector3.Dot(nativeBakedVertices[index] - sphereA, sphereVector.normalized); 1029 | if (f < 0) 1030 | { 1031 | closestPointOnAxis = sphereA; 1032 | } 1033 | else if (f > sphereVector.magnitude) 1034 | { 1035 | closestPointOnAxis = sphereB; 1036 | } 1037 | else closestPointOnAxis = sphereA + (f * sphereVector.normalized); 1038 | 1039 | float axisDistance = Vector3.Distance(closestPointOnAxis, nativeBakedVertices[index]); 1040 | if (axisDistance < radius) 1041 | { 1042 | deformed[0] = true; 1043 | closestPointOnAxis = sphereA + (f * sphereVector.normalized); 1044 | axisDistance = Vector3.Distance(closestPointOnAxis, nativeBakedVertices[index]); 1045 | float axisFactor = 1 - ((axisDistance / radius) * falloff); 1046 | 1047 | float centerDistance = Vector3.Distance(point1, nativeBakedVertices[index]); 1048 | float centerFactor = 1 - ((centerDistance / height) * falloff); 1049 | 1050 | float factor = Mathf.Lerp(axisFactor, centerFactor, axisWeight); 1051 | nativeBakedVertices[index] = Vector3.Lerp(nativeBakedVertices[index], nativeBakedVertices[index] - (nativeNormals[index].normalized/10), strength * factor); 1052 | nativeNewVertices[index] = BakedToNewVertex(nativeBakedVertices[index], RendererWorldToLocalMatrix, RendererLocalToWorldMatrix, RootBoneWorldToLocalMatrix, nativeboneMatrices, nativeBoneWeights, index, skinned); 1053 | } 1054 | } 1055 | } 1056 | } 1057 | } 1058 | 1059 | public override void Deform(NativeArray nativeNewVertices, NativeArray nativeBakedVertices, NativeArray nativeboneMatrices, NativeArray nativeBoneWeights, Matrix4x4 RendererLocalToWorldMatrix, Matrix4x4 RendererWorldToLocalMatrix, Matrix4x4 RootBoneWorldToLocalMatrix, bool skinned, NativeArray deformed, NativeArray nativeNormals) 1060 | { 1061 | SetDeformParams(); 1062 | SetPoints(RendererWorldToLocalMatrix, skinned); 1063 | 1064 | DeformJob deformJob = new DeformJob 1065 | { 1066 | nativeNewVertices = nativeNewVertices, 1067 | nativeBakedVertices = nativeBakedVertices, 1068 | radius = radius, 1069 | falloff = falloff, 1070 | strength = strength, 1071 | point1 = point1, 1072 | point2 = point2, 1073 | RendererLocalToWorldMatrix = RendererLocalToWorldMatrix, 1074 | RendererWorldToLocalMatrix = RendererWorldToLocalMatrix, 1075 | RootBoneWorldToLocalMatrix = RootBoneWorldToLocalMatrix, 1076 | nativeBoneWeights = nativeBoneWeights, 1077 | nativeboneMatrices = nativeboneMatrices, 1078 | skinned = skinned, 1079 | deformed = deformed, 1080 | selectorType = selectorType, 1081 | sphereA = sphereA, 1082 | sphereB = sphereB, 1083 | axisWeight = axisWeight, 1084 | height = height, 1085 | nativeNormals = nativeNormals 1086 | }; 1087 | 1088 | JobHandle jobHandle = deformJob.Schedule(nativeNewVertices.Length, 32); 1089 | jobHandle.Complete(); 1090 | } 1091 | } 1092 | 1093 | public class Squeezer : Deformer 1094 | { 1095 | [BurstCompile] 1096 | public struct DeformJob : IJobParallelFor 1097 | { 1098 | public float radius; 1099 | public float falloff; 1100 | public float strength; 1101 | public NativeArray nativeNewVertices; 1102 | public NativeArray nativeBakedVertices; 1103 | public Vector3 point1; 1104 | public Vector3 point2; 1105 | public NativeArray nativeboneMatrices; 1106 | public NativeArray nativeBoneWeights; 1107 | public Matrix4x4 RendererWorldToLocalMatrix; 1108 | public Matrix4x4 RendererLocalToWorldMatrix; 1109 | public Matrix4x4 RootBoneWorldToLocalMatrix; 1110 | public bool skinned; 1111 | public NativeArray deformed; 1112 | public SelectorType selectorType; 1113 | public Vector3 sphereA; 1114 | public Vector3 sphereB; 1115 | public float height; 1116 | public float axisWeight; 1117 | 1118 | public void Execute(int index) 1119 | { 1120 | if(selectorType == SelectorType.Sphere) 1121 | { 1122 | float distance = Vector3.Distance(nativeBakedVertices[index], point1); 1123 | if (distance < radius) 1124 | { 1125 | deformed[0] = true; 1126 | float factor = 1 - ((distance / radius) * falloff); 1127 | nativeBakedVertices[index] = Vector3.Lerp(nativeBakedVertices[index], point2, strength * factor); 1128 | nativeNewVertices[index] = BakedToNewVertex(nativeBakedVertices[index], RendererWorldToLocalMatrix, RendererLocalToWorldMatrix, RootBoneWorldToLocalMatrix, nativeboneMatrices, nativeBoneWeights, index, skinned); 1129 | } 1130 | } 1131 | if (selectorType == SelectorType.Capsule) 1132 | { 1133 | Vector3 sphereVector = sphereB - sphereA; 1134 | Vector3 capsuleEndA = sphereA - (radius * sphereVector.normalized); 1135 | Vector3 capsuleEndB = sphereB + (radius * sphereVector.normalized); 1136 | Vector3 capsuleVector = capsuleEndB - capsuleEndA; 1137 | Vector3 p = nativeBakedVertices[index] - capsuleEndA; 1138 | float dot = p.x * capsuleVector.x + p.y * capsuleVector.y + p.z * capsuleVector.z; 1139 | float lengthsq = capsuleVector.sqrMagnitude; 1140 | if ((dot > 0f) && (dot < lengthsq)) 1141 | { 1142 | Vector3 closestPointOnAxis; 1143 | float f = Vector3.Dot(nativeBakedVertices[index] - sphereA, sphereVector.normalized); 1144 | if (f < 0) 1145 | { 1146 | closestPointOnAxis = sphereA; 1147 | } 1148 | else if (f > sphereVector.magnitude) 1149 | { 1150 | closestPointOnAxis = sphereB; 1151 | } 1152 | else closestPointOnAxis = sphereA + (f * sphereVector.normalized); 1153 | 1154 | float axisDistance = Vector3.Distance(closestPointOnAxis, nativeBakedVertices[index]); 1155 | if (axisDistance < radius) 1156 | { 1157 | deformed[0] = true; 1158 | closestPointOnAxis = sphereA + (f * sphereVector.normalized); 1159 | axisDistance = Vector3.Distance(closestPointOnAxis, nativeBakedVertices[index]); 1160 | float axisFactor = 1 - ((axisDistance / radius) * falloff); 1161 | 1162 | float centerDistance = Vector3.Distance(point1, nativeBakedVertices[index]); 1163 | float centerFactor = 1 - ((centerDistance / height) * falloff); 1164 | 1165 | float factor = Mathf.Lerp(axisFactor, centerFactor, axisWeight); 1166 | closestPointOnAxis = Vector3.Lerp(closestPointOnAxis, point1, axisWeight); 1167 | nativeBakedVertices[index] = Vector3.Lerp(nativeBakedVertices[index], closestPointOnAxis + (point2 - point1), strength * factor); 1168 | nativeNewVertices[index] = BakedToNewVertex(nativeBakedVertices[index], RendererWorldToLocalMatrix, RendererLocalToWorldMatrix, RootBoneWorldToLocalMatrix, nativeboneMatrices, nativeBoneWeights, index, skinned); 1169 | } 1170 | } 1171 | } 1172 | } 1173 | } 1174 | 1175 | public override void Deform(NativeArray nativeNewVertices, NativeArray nativeBakedVertices, NativeArray nativeboneMatrices, NativeArray nativeBoneWeights, Matrix4x4 RendererLocalToWorldMatrix, Matrix4x4 RendererWorldToLocalMatrix, Matrix4x4 RootBoneWorldToLocalMatrix, bool skinned, NativeArray deformed, NativeArray nativeNormals) 1176 | { 1177 | SetDeformParams(); 1178 | SetPoints(RendererWorldToLocalMatrix, skinned); 1179 | 1180 | DeformJob deformJob = new DeformJob 1181 | { 1182 | nativeNewVertices = nativeNewVertices, 1183 | nativeBakedVertices = nativeBakedVertices, 1184 | radius = radius, 1185 | falloff = falloff, 1186 | strength = strength, 1187 | point1 = point1, 1188 | point2 = point2, 1189 | RendererLocalToWorldMatrix = RendererLocalToWorldMatrix, 1190 | RendererWorldToLocalMatrix = RendererWorldToLocalMatrix, 1191 | RootBoneWorldToLocalMatrix = RootBoneWorldToLocalMatrix, 1192 | nativeBoneWeights = nativeBoneWeights, 1193 | nativeboneMatrices = nativeboneMatrices, 1194 | skinned = skinned, 1195 | deformed = deformed, 1196 | selectorType = selectorType, 1197 | sphereA = sphereA, 1198 | sphereB = sphereB, 1199 | axisWeight = axisWeight, 1200 | height = height 1201 | }; 1202 | 1203 | JobHandle jobHandle = deformJob.Schedule(nativeNewVertices.Length, 32); 1204 | jobHandle.Complete(); 1205 | } 1206 | } 1207 | 1208 | public class Bulger : Deformer 1209 | { 1210 | 1211 | [BurstCompile] 1212 | public struct DeformJob : IJobParallelFor 1213 | { 1214 | public float radius; 1215 | public float falloff; 1216 | public float strength; 1217 | public NativeArray nativeNewVertices; 1218 | public NativeArray nativeBakedVertices; 1219 | public Vector3 point1; 1220 | public Vector3 point2; 1221 | public NativeArray nativeboneMatrices; 1222 | public NativeArray nativeBoneWeights; 1223 | public Matrix4x4 RendererWorldToLocalMatrix; 1224 | public Matrix4x4 RendererLocalToWorldMatrix; 1225 | public Matrix4x4 RootBoneWorldToLocalMatrix; 1226 | public bool skinned; 1227 | public NativeArray deformed; 1228 | public SelectorType selectorType; 1229 | public Vector3 sphereA; 1230 | public Vector3 sphereB; 1231 | public float height; 1232 | public float axisWeight; 1233 | 1234 | public void Execute(int index) 1235 | { 1236 | if (selectorType == SelectorType.Sphere) 1237 | { 1238 | float distance = Vector3.Distance(nativeBakedVertices[index], point1); 1239 | if (distance < radius) 1240 | { 1241 | deformed[0] = true; 1242 | Vector3 newPoint = nativeBakedVertices[index] + (nativeBakedVertices[index] - point2); 1243 | float factor = 1 - ((distance / radius) * falloff); 1244 | nativeBakedVertices[index] = Vector3.Lerp(nativeBakedVertices[index], newPoint, strength * factor); 1245 | nativeNewVertices[index] = BakedToNewVertex(nativeBakedVertices[index], RendererWorldToLocalMatrix, RendererLocalToWorldMatrix, RootBoneWorldToLocalMatrix, nativeboneMatrices, nativeBoneWeights, index, skinned); 1246 | } 1247 | } 1248 | if (selectorType == SelectorType.Capsule) 1249 | { 1250 | Vector3 sphereVector = sphereB - sphereA; 1251 | Vector3 capsuleEndA = sphereA - (radius * sphereVector.normalized); 1252 | Vector3 capsuleEndB = sphereB + (radius * sphereVector.normalized); 1253 | Vector3 capsuleVector = capsuleEndB - capsuleEndA; 1254 | Vector3 p = nativeBakedVertices[index] - capsuleEndA; 1255 | float dot = p.x * capsuleVector.x + p.y * capsuleVector.y + p.z * capsuleVector.z; 1256 | float lengthsq = capsuleVector.sqrMagnitude; 1257 | if ((dot > 0f) && (dot < lengthsq)) 1258 | { 1259 | Vector3 closestPointOnAxis; 1260 | float f = Vector3.Dot(nativeBakedVertices[index] - sphereA, sphereVector.normalized); 1261 | if (f < 0) 1262 | { 1263 | closestPointOnAxis = sphereA; 1264 | } 1265 | else if (f > sphereVector.magnitude) 1266 | { 1267 | closestPointOnAxis = sphereB; 1268 | } 1269 | else closestPointOnAxis = sphereA + (f * sphereVector.normalized); 1270 | 1271 | float axisDistance = Vector3.Distance(closestPointOnAxis, nativeBakedVertices[index]); 1272 | if (axisDistance < radius) 1273 | { 1274 | deformed[0] = true; 1275 | closestPointOnAxis = sphereA + (f * sphereVector.normalized); 1276 | axisDistance = Vector3.Distance(closestPointOnAxis, nativeBakedVertices[index]); 1277 | float axisFactor = 1 - ((axisDistance / radius) * falloff); 1278 | 1279 | float centerDistance = Vector3.Distance(point1, nativeBakedVertices[index]); 1280 | float centerFactor = 1 - ((centerDistance / height) * falloff); 1281 | 1282 | float factor = Mathf.Lerp(axisFactor, centerFactor, axisWeight); 1283 | closestPointOnAxis = Vector3.Lerp(closestPointOnAxis, point1, axisWeight); 1284 | Vector3 newPoint = nativeBakedVertices[index] + (nativeBakedVertices[index] - (closestPointOnAxis + (point2 - point1))); 1285 | nativeBakedVertices[index] = Vector3.Lerp(nativeBakedVertices[index], newPoint, strength * factor); 1286 | nativeNewVertices[index] = BakedToNewVertex(nativeBakedVertices[index], RendererWorldToLocalMatrix, RendererLocalToWorldMatrix, RootBoneWorldToLocalMatrix, nativeboneMatrices, nativeBoneWeights, index, skinned); 1287 | } 1288 | } 1289 | } 1290 | } 1291 | } 1292 | 1293 | public override void Deform(NativeArray nativeNewVertices, NativeArray nativeBakedVertices, NativeArray nativeboneMatrices, NativeArray nativeBoneWeights, Matrix4x4 RendererLocalToWorldMatrix, Matrix4x4 RendererWorldToLocalMatrix, Matrix4x4 RootBoneWorldToLocalMatrix, bool skinned, NativeArray deformed, NativeArray nativeNormals) 1294 | { 1295 | SetDeformParams(); 1296 | SetPoints(RendererWorldToLocalMatrix, skinned); 1297 | 1298 | DeformJob deformJob = new DeformJob 1299 | { 1300 | nativeNewVertices = nativeNewVertices, 1301 | nativeBakedVertices = nativeBakedVertices, 1302 | radius = radius, 1303 | falloff = falloff, 1304 | strength = strength, 1305 | point1 = point1, 1306 | point2 = point2, 1307 | RendererLocalToWorldMatrix = RendererLocalToWorldMatrix, 1308 | RendererWorldToLocalMatrix = RendererWorldToLocalMatrix, 1309 | RootBoneWorldToLocalMatrix = RootBoneWorldToLocalMatrix, 1310 | nativeBoneWeights = nativeBoneWeights, 1311 | nativeboneMatrices = nativeboneMatrices, 1312 | skinned = skinned, 1313 | deformed = deformed, 1314 | selectorType = selectorType, 1315 | sphereA = sphereA, 1316 | sphereB = sphereB, 1317 | axisWeight = axisWeight, 1318 | height = height 1319 | }; 1320 | 1321 | JobHandle jobHandle = deformJob.Schedule(nativeNewVertices.Length, 32); 1322 | jobHandle.Complete(); 1323 | } 1324 | } 1325 | 1326 | public class Mover : Deformer 1327 | { 1328 | [BurstCompile] 1329 | public struct DeformJob : IJobParallelFor 1330 | { 1331 | public float radius; 1332 | public float falloff; 1333 | public float strength; 1334 | public NativeArray nativeNewVertices; 1335 | public NativeArray nativeBakedVertices; 1336 | public Vector3 point1; 1337 | public Vector3 point2; 1338 | public NativeArray nativeboneMatrices; 1339 | public NativeArray nativeBoneWeights; 1340 | public Matrix4x4 RendererWorldToLocalMatrix; 1341 | public Matrix4x4 RendererLocalToWorldMatrix; 1342 | public Matrix4x4 RootBoneWorldToLocalMatrix; 1343 | public Vector3 moveVector; 1344 | public bool skinned; 1345 | public NativeArray deformed; 1346 | public SelectorType selectorType; 1347 | public Vector3 sphereA; 1348 | public Vector3 sphereB; 1349 | public float height; 1350 | public float axisWeight; 1351 | 1352 | public void Execute(int index) 1353 | { 1354 | if (selectorType == SelectorType.Sphere) 1355 | { 1356 | float distance = Vector3.Distance(nativeBakedVertices[index], point1); 1357 | if (distance < radius) 1358 | { 1359 | deformed[0] = true; 1360 | Vector3 newPoint = nativeBakedVertices[index] + moveVector; 1361 | float factor = 1 - ((distance / radius) * falloff); 1362 | nativeBakedVertices[index] = Vector3.Lerp(nativeBakedVertices[index], newPoint, strength * factor); 1363 | nativeNewVertices[index] = BakedToNewVertex(nativeBakedVertices[index], RendererWorldToLocalMatrix, RendererLocalToWorldMatrix, RootBoneWorldToLocalMatrix, nativeboneMatrices, nativeBoneWeights, index, skinned); 1364 | } 1365 | } 1366 | if (selectorType == SelectorType.Capsule) 1367 | { 1368 | Vector3 sphereVector = sphereB - sphereA; 1369 | Vector3 capsuleEndA = sphereA - (radius * sphereVector.normalized); 1370 | Vector3 capsuleEndB = sphereB + (radius * sphereVector.normalized); 1371 | Vector3 capsuleVector = capsuleEndB - capsuleEndA; 1372 | Vector3 p = nativeBakedVertices[index] - capsuleEndA; 1373 | float dot = p.x * capsuleVector.x + p.y * capsuleVector.y + p.z * capsuleVector.z; 1374 | float lengthsq = capsuleVector.sqrMagnitude; 1375 | if ((dot > 0f) && (dot < lengthsq)) 1376 | { 1377 | Vector3 closestPointOnAxis; 1378 | float f = Vector3.Dot(nativeBakedVertices[index] - sphereA, sphereVector.normalized); 1379 | if (f < 0) 1380 | { 1381 | closestPointOnAxis = sphereA; 1382 | } 1383 | else if (f > sphereVector.magnitude) 1384 | { 1385 | closestPointOnAxis = sphereB; 1386 | } 1387 | else closestPointOnAxis = sphereA + (f * sphereVector.normalized); 1388 | 1389 | float axisDistance = Vector3.Distance(closestPointOnAxis, nativeBakedVertices[index]); 1390 | if (axisDistance < radius) 1391 | { 1392 | deformed[0] = true; 1393 | closestPointOnAxis = sphereA + (f * sphereVector.normalized); 1394 | axisDistance = Vector3.Distance(closestPointOnAxis, nativeBakedVertices[index]); 1395 | float axisFactor = 1 - ((axisDistance / radius) * falloff); 1396 | 1397 | float centerDistance = Vector3.Distance(point1, nativeBakedVertices[index]); 1398 | float centerFactor = 1 - ((centerDistance / height) * falloff); 1399 | 1400 | float factor = Mathf.Lerp(axisFactor, centerFactor, axisWeight); 1401 | Vector3 newPoint = nativeBakedVertices[index] + moveVector; 1402 | nativeBakedVertices[index] = Vector3.Lerp(nativeBakedVertices[index], newPoint, strength * factor); 1403 | nativeNewVertices[index] = BakedToNewVertex(nativeBakedVertices[index], RendererWorldToLocalMatrix, RendererLocalToWorldMatrix, RootBoneWorldToLocalMatrix, nativeboneMatrices, nativeBoneWeights, index, skinned); 1404 | } 1405 | } 1406 | } 1407 | } 1408 | } 1409 | 1410 | public override void Deform(NativeArray nativeNewVertices, NativeArray nativeBakedVertices, NativeArray nativeboneMatrices, NativeArray nativeBoneWeights, Matrix4x4 RendererLocalToWorldMatrix, Matrix4x4 RendererWorldToLocalMatrix, Matrix4x4 RootBoneWorldToLocalMatrix, bool skinned, NativeArray deformed, NativeArray nativeNormals) 1411 | { 1412 | SetDeformParams(); 1413 | SetPoints(RendererWorldToLocalMatrix, skinned); 1414 | 1415 | DeformJob deformJob = new DeformJob 1416 | { 1417 | nativeNewVertices = nativeNewVertices, 1418 | nativeBakedVertices = nativeBakedVertices, 1419 | radius = radius, 1420 | falloff = falloff, 1421 | strength = strength, 1422 | point1 = point1, 1423 | point2 = point2, 1424 | RendererLocalToWorldMatrix = RendererLocalToWorldMatrix, 1425 | RendererWorldToLocalMatrix = RendererWorldToLocalMatrix, 1426 | RootBoneWorldToLocalMatrix = RootBoneWorldToLocalMatrix, 1427 | nativeBoneWeights = nativeBoneWeights, 1428 | nativeboneMatrices = nativeboneMatrices, 1429 | moveVector = point2 - point1, 1430 | skinned = skinned, 1431 | deformed = deformed, 1432 | selectorType = selectorType, 1433 | sphereA = sphereA, 1434 | sphereB = sphereB, 1435 | axisWeight = axisWeight, 1436 | height = height 1437 | }; 1438 | 1439 | JobHandle jobHandle = deformJob.Schedule(nativeNewVertices.Length, 32); 1440 | jobHandle.Complete(); 1441 | } 1442 | } 1443 | 1444 | public class Rotator : Deformer 1445 | { 1446 | [BurstCompile] 1447 | public struct DeformJob : IJobParallelFor 1448 | { 1449 | public float radius; 1450 | public float falloff; 1451 | public float strength; 1452 | public NativeArray nativeNewVertices; 1453 | public NativeArray nativeBakedVertices; 1454 | public Vector3 point1; 1455 | public Vector3 point2; 1456 | public NativeArray nativeboneMatrices; 1457 | public NativeArray nativeBoneWeights; 1458 | public Matrix4x4 RendererWorldToLocalMatrix; 1459 | public Matrix4x4 RendererLocalToWorldMatrix; 1460 | public Matrix4x4 RootBoneWorldToLocalMatrix; 1461 | public Vector3 moveVector; 1462 | public bool skinned; 1463 | public Quaternion rotation; 1464 | public NativeArray deformed; 1465 | public SelectorType selectorType; 1466 | public Vector3 sphereA; 1467 | public Vector3 sphereB; 1468 | public float height; 1469 | public float axisWeight; 1470 | 1471 | public void Execute(int index) 1472 | { 1473 | 1474 | 1475 | if (selectorType == SelectorType.Sphere) 1476 | { 1477 | float distance = Vector3.Distance(nativeBakedVertices[index], point1); 1478 | if (distance < radius) 1479 | { 1480 | deformed[0] = true; 1481 | Vector3 newPoint = point2 + (rotation * (nativeBakedVertices[index] - point2)); 1482 | float factor = 1 - ((distance / radius) * falloff); 1483 | nativeBakedVertices[index] = Vector3.Lerp(nativeBakedVertices[index], newPoint, strength * factor); 1484 | nativeNewVertices[index] = BakedToNewVertex(nativeBakedVertices[index], RendererWorldToLocalMatrix, RendererLocalToWorldMatrix, RootBoneWorldToLocalMatrix, nativeboneMatrices, nativeBoneWeights, index, skinned); 1485 | } 1486 | } 1487 | if (selectorType == SelectorType.Capsule) 1488 | { 1489 | Vector3 sphereVector = sphereB - sphereA; 1490 | Vector3 capsuleEndA = sphereA - (radius * sphereVector.normalized); 1491 | Vector3 capsuleEndB = sphereB + (radius * sphereVector.normalized); 1492 | Vector3 capsuleVector = capsuleEndB - capsuleEndA; 1493 | Vector3 p = nativeBakedVertices[index] - capsuleEndA; 1494 | float dot = p.x * capsuleVector.x + p.y * capsuleVector.y + p.z * capsuleVector.z; 1495 | float lengthsq = capsuleVector.sqrMagnitude; 1496 | if ((dot > 0f) && (dot < lengthsq)) 1497 | { 1498 | Vector3 closestPointOnAxis; 1499 | float f = Vector3.Dot(nativeBakedVertices[index] - sphereA, sphereVector.normalized); 1500 | if (f < 0) 1501 | { 1502 | closestPointOnAxis = sphereA; 1503 | } 1504 | else if (f > sphereVector.magnitude) 1505 | { 1506 | closestPointOnAxis = sphereB; 1507 | } 1508 | else closestPointOnAxis = sphereA + (f * sphereVector.normalized); 1509 | 1510 | float axisDistance = Vector3.Distance(closestPointOnAxis, nativeBakedVertices[index]); 1511 | if (axisDistance < radius) 1512 | { 1513 | deformed[0] = true; 1514 | closestPointOnAxis = sphereA + (f * sphereVector.normalized); 1515 | axisDistance = Vector3.Distance(closestPointOnAxis, nativeBakedVertices[index]); 1516 | float axisFactor = 1 - ((axisDistance / radius) * falloff); 1517 | 1518 | float centerDistance = Vector3.Distance(point1, nativeBakedVertices[index]); 1519 | float centerFactor = 1 - ((centerDistance / height) * falloff); 1520 | 1521 | float factor = Mathf.Lerp(axisFactor, centerFactor, axisWeight); 1522 | closestPointOnAxis = Vector3.Lerp(closestPointOnAxis, point1, axisWeight); 1523 | Vector3 newPoint2 = closestPointOnAxis + (point2 - point1); 1524 | Vector3 newPoint = newPoint2 + (rotation * (nativeBakedVertices[index] - newPoint2)); 1525 | nativeBakedVertices[index] = Vector3.Lerp(nativeBakedVertices[index], newPoint, strength * factor); 1526 | nativeNewVertices[index] = BakedToNewVertex(nativeBakedVertices[index], RendererWorldToLocalMatrix, RendererLocalToWorldMatrix, RootBoneWorldToLocalMatrix, nativeboneMatrices, nativeBoneWeights, index, skinned); 1527 | } 1528 | } 1529 | } 1530 | } 1531 | } 1532 | 1533 | public override void Deform(NativeArray nativeNewVertices, NativeArray nativeBakedVertices, NativeArray nativeboneMatrices, NativeArray nativeBoneWeights, Matrix4x4 RendererLocalToWorldMatrix, Matrix4x4 RendererWorldToLocalMatrix, Matrix4x4 RootBoneWorldToLocalMatrix, bool skinned, NativeArray deformed, NativeArray nativeNormals) 1534 | { 1535 | SetDeformParams(); 1536 | SetPoints(RendererWorldToLocalMatrix, skinned); 1537 | 1538 | DeformJob deformJob = new DeformJob 1539 | { 1540 | nativeNewVertices = nativeNewVertices, 1541 | nativeBakedVertices = nativeBakedVertices, 1542 | radius = radius, 1543 | falloff = falloff, 1544 | strength = strength, 1545 | point1 = point1, 1546 | point2 = point2, 1547 | RendererLocalToWorldMatrix = RendererLocalToWorldMatrix, 1548 | RendererWorldToLocalMatrix = RendererWorldToLocalMatrix, 1549 | RootBoneWorldToLocalMatrix = RootBoneWorldToLocalMatrix, 1550 | nativeBoneWeights = nativeBoneWeights, 1551 | nativeboneMatrices = nativeboneMatrices, 1552 | moveVector = point2 - point1, 1553 | skinned = skinned, 1554 | rotation = N2.localRotation, 1555 | deformed = deformed, 1556 | selectorType = selectorType, 1557 | sphereA = sphereA, 1558 | sphereB = sphereB, 1559 | axisWeight = axisWeight, 1560 | height = height 1561 | }; 1562 | 1563 | JobHandle jobHandle = deformJob.Schedule(nativeNewVertices.Length, 32); 1564 | jobHandle.Complete(); 1565 | } 1566 | } 1567 | --------------------------------------------------------------------------------