备份CatanBuilding瘦身独立工程

This commit is contained in:
JSD\13999
2026-05-26 16:15:54 +08:00
commit 2d0e6a61b7
12001 changed files with 2431925 additions and 0 deletions

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 04cd50d4709d67d46ae02a5c0d18c3cc
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,76 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!114 &11400000
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 1a3c5d64ac83548c09dd1678b9f6f1cd, type: 3}
m_Name: Local
m_EditorClassIdentifier:
m_SchemaObjects:
- {fileID: 2134600949886003966}
- {fileID: 5450088179071591902}
m_Description:
m_Settings: {fileID: 11400000, guid: 2b420ef1fd7d56b4f86537c540c40803, type: 2}
--- !u!114 &2134600949886003966
MonoBehaviour:
m_ObjectHideFlags: 1
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: e5d17a21594effb4e9591490b009e7aa, type: 3}
m_Name: BundledAssetGroupSchema
m_EditorClassIdentifier:
m_Group: {fileID: 0}
m_InternalBundleIdMode: 1
m_Compression: 1
m_IncludeAddressInCatalog: 1
m_IncludeGUIDInCatalog: 1
m_IncludeLabelsInCatalog: 1
m_InternalIdNamingMode: 0
m_CacheClearBehavior: 0
m_IncludeInBuild: 1
m_BundledAssetProviderType:
m_AssemblyName: Unity.ResourceManager, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
m_ClassName: UnityEngine.ResourceManagement.ResourceProviders.BundledAssetProvider
m_ForceUniqueProvider: 0
m_UseAssetBundleCache: 1
m_UseAssetBundleCrc: 1
m_UseAssetBundleCrcForCachedBundles: 1
m_UseUWRForLocalBundles: 0
m_Timeout: 0
m_ChunkedTransfer: 0
m_RedirectLimit: -1
m_RetryCount: 3
m_BuildPath:
m_Id: 0327ded4381668844bc353d399df10b1
m_LoadPath:
m_Id: d3edbf09e52e321458f036629aea31aa
m_BundleMode: 1
m_AssetBundleProviderType:
m_AssemblyName: Unity.ResourceManager, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
m_ClassName: UnityEngine.ResourceManagement.ResourceProviders.AssetBundleProvider
m_BundleNaming: 0
m_AssetLoadMode: 0
--- !u!114 &5450088179071591902
MonoBehaviour:
m_ObjectHideFlags: 1
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 5834b5087d578d24c926ce20cd31e6d6, type: 3}
m_Name: ContentUpdateGroupSchema
m_EditorClassIdentifier:
m_Group: {fileID: 0}
m_StaticContent: 1

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 2c6c3b7b5de17d944b1acc2c37cb1ace
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 11400000
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,76 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!114 &11400000
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 1a3c5d64ac83548c09dd1678b9f6f1cd, type: 3}
m_Name: LocalOneBundle
m_EditorClassIdentifier:
m_SchemaObjects:
- {fileID: 2134600949886003966}
- {fileID: 5450088179071591902}
m_Description:
m_Settings: {fileID: 11400000, guid: 2b420ef1fd7d56b4f86537c540c40803, type: 2}
--- !u!114 &2134600949886003966
MonoBehaviour:
m_ObjectHideFlags: 1
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: e5d17a21594effb4e9591490b009e7aa, type: 3}
m_Name: BundledAssetGroupSchema
m_EditorClassIdentifier:
m_Group: {fileID: 0}
m_InternalBundleIdMode: 1
m_Compression: 1
m_IncludeAddressInCatalog: 1
m_IncludeGUIDInCatalog: 1
m_IncludeLabelsInCatalog: 1
m_InternalIdNamingMode: 0
m_CacheClearBehavior: 0
m_IncludeInBuild: 1
m_BundledAssetProviderType:
m_AssemblyName: Unity.ResourceManager, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
m_ClassName: UnityEngine.ResourceManagement.ResourceProviders.BundledAssetProvider
m_ForceUniqueProvider: 0
m_UseAssetBundleCache: 1
m_UseAssetBundleCrc: 1
m_UseAssetBundleCrcForCachedBundles: 1
m_UseUWRForLocalBundles: 0
m_Timeout: 0
m_ChunkedTransfer: 0
m_RedirectLimit: -1
m_RetryCount: 3
m_BuildPath:
m_Id: 0327ded4381668844bc353d399df10b1
m_LoadPath:
m_Id: d3edbf09e52e321458f036629aea31aa
m_BundleMode: 0
m_AssetBundleProviderType:
m_AssemblyName: Unity.ResourceManager, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
m_ClassName: UnityEngine.ResourceManagement.ResourceProviders.AssetBundleProvider
m_BundleNaming: 0
m_AssetLoadMode: 0
--- !u!114 &5450088179071591902
MonoBehaviour:
m_ObjectHideFlags: 1
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 5834b5087d578d24c926ce20cd31e6d6, type: 3}
m_Name: ContentUpdateGroupSchema
m_EditorClassIdentifier:
m_Group: {fileID: 0}
m_StaticContent: 1

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: f35d7d498ee47f84cba264039cf1cfbe
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 11400000
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,76 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!114 &-2495768021662990981
MonoBehaviour:
m_ObjectHideFlags: 1
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: e5d17a21594effb4e9591490b009e7aa, type: 3}
m_Name: BundledAssetGroupSchema
m_EditorClassIdentifier:
m_Group: {fileID: 0}
m_InternalBundleIdMode: 1
m_Compression: 1
m_IncludeAddressInCatalog: 1
m_IncludeGUIDInCatalog: 1
m_IncludeLabelsInCatalog: 1
m_InternalIdNamingMode: 0
m_CacheClearBehavior: 0
m_IncludeInBuild: 1
m_BundledAssetProviderType:
m_AssemblyName: Unity.ResourceManager, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
m_ClassName: UnityEngine.ResourceManagement.ResourceProviders.BundledAssetProvider
m_ForceUniqueProvider: 0
m_UseAssetBundleCache: 1
m_UseAssetBundleCrc: 1
m_UseAssetBundleCrcForCachedBundles: 1
m_UseUWRForLocalBundles: 0
m_Timeout: 0
m_ChunkedTransfer: 0
m_RedirectLimit: -1
m_RetryCount: 3
m_BuildPath:
m_Id: ce35249f4cedb0c4ea05a2b4547030d8
m_LoadPath:
m_Id: a0175be1cdc22bb48a6cec36df70320c
m_BundleMode: 1
m_AssetBundleProviderType:
m_AssemblyName: Unity.ResourceManager, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
m_ClassName: UnityEngine.ResourceManagement.ResourceProviders.AssetBundleProvider
m_BundleNaming: 0
m_AssetLoadMode: 0
--- !u!114 &11400000
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 1a3c5d64ac83548c09dd1678b9f6f1cd, type: 3}
m_Name: RemoteSeparately
m_EditorClassIdentifier:
m_SchemaObjects:
- {fileID: -2495768021662990981}
- {fileID: 1499562304012160075}
m_Description:
m_Settings: {fileID: 11400000, guid: 2b420ef1fd7d56b4f86537c540c40803, type: 2}
--- !u!114 &1499562304012160075
MonoBehaviour:
m_ObjectHideFlags: 1
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 5834b5087d578d24c926ce20cd31e6d6, type: 3}
m_Name: ContentUpdateGroupSchema
m_EditorClassIdentifier:
m_Group: {fileID: 0}
m_StaticContent: 0

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: d1116100ceb7a9246a9dfdbc4ab6c5ec
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 11400000
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,76 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!114 &-2495768021662990981
MonoBehaviour:
m_ObjectHideFlags: 1
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: e5d17a21594effb4e9591490b009e7aa, type: 3}
m_Name: BundledAssetGroupSchema
m_EditorClassIdentifier:
m_Group: {fileID: 0}
m_InternalBundleIdMode: 1
m_Compression: 1
m_IncludeAddressInCatalog: 1
m_IncludeGUIDInCatalog: 1
m_IncludeLabelsInCatalog: 1
m_InternalIdNamingMode: 0
m_CacheClearBehavior: 0
m_IncludeInBuild: 1
m_BundledAssetProviderType:
m_AssemblyName: Unity.ResourceManager, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
m_ClassName: UnityEngine.ResourceManagement.ResourceProviders.BundledAssetProvider
m_ForceUniqueProvider: 0
m_UseAssetBundleCache: 1
m_UseAssetBundleCrc: 1
m_UseAssetBundleCrcForCachedBundles: 1
m_UseUWRForLocalBundles: 0
m_Timeout: 0
m_ChunkedTransfer: 0
m_RedirectLimit: -1
m_RetryCount: 3
m_BuildPath:
m_Id: ce35249f4cedb0c4ea05a2b4547030d8
m_LoadPath:
m_Id: a0175be1cdc22bb48a6cec36df70320c
m_BundleMode: 0
m_AssetBundleProviderType:
m_AssemblyName: Unity.ResourceManager, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
m_ClassName: UnityEngine.ResourceManagement.ResourceProviders.AssetBundleProvider
m_BundleNaming: 0
m_AssetLoadMode: 0
--- !u!114 &11400000
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 1a3c5d64ac83548c09dd1678b9f6f1cd, type: 3}
m_Name: RemoteTogether
m_EditorClassIdentifier:
m_SchemaObjects:
- {fileID: -2495768021662990981}
- {fileID: 1499562304012160075}
m_Description:
m_Settings: {fileID: 11400000, guid: 2b420ef1fd7d56b4f86537c540c40803, type: 2}
--- !u!114 &1499562304012160075
MonoBehaviour:
m_ObjectHideFlags: 1
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 5834b5087d578d24c926ce20cd31e6d6, type: 3}
m_Name: ContentUpdateGroupSchema
m_EditorClassIdentifier:
m_Group: {fileID: 0}
m_StaticContent: 0

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 32e60196e37ee144896230d6223a6223
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 11400000
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,76 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!114 &-2495768021662990981
MonoBehaviour:
m_ObjectHideFlags: 1
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: e5d17a21594effb4e9591490b009e7aa, type: 3}
m_Name: BundledAssetGroupSchema
m_EditorClassIdentifier:
m_Group: {fileID: 0}
m_InternalBundleIdMode: 1
m_Compression: 1
m_IncludeAddressInCatalog: 1
m_IncludeGUIDInCatalog: 1
m_IncludeLabelsInCatalog: 1
m_InternalIdNamingMode: 0
m_CacheClearBehavior: 0
m_IncludeInBuild: 1
m_BundledAssetProviderType:
m_AssemblyName: Unity.ResourceManager, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
m_ClassName: UnityEngine.ResourceManagement.ResourceProviders.BundledAssetProvider
m_ForceUniqueProvider: 0
m_UseAssetBundleCache: 1
m_UseAssetBundleCrc: 1
m_UseAssetBundleCrcForCachedBundles: 1
m_UseUWRForLocalBundles: 0
m_Timeout: 0
m_ChunkedTransfer: 0
m_RedirectLimit: -1
m_RetryCount: 3
m_BuildPath:
m_Id: ce35249f4cedb0c4ea05a2b4547030d8
m_LoadPath:
m_Id: a0175be1cdc22bb48a6cec36df70320c
m_BundleMode: 2
m_AssetBundleProviderType:
m_AssemblyName: Unity.ResourceManager, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
m_ClassName: UnityEngine.ResourceManagement.ResourceProviders.AssetBundleProvider
m_BundleNaming: 0
m_AssetLoadMode: 0
--- !u!114 &11400000
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 1a3c5d64ac83548c09dd1678b9f6f1cd, type: 3}
m_Name: RemoteTogetherByLabel
m_EditorClassIdentifier:
m_SchemaObjects:
- {fileID: -2495768021662990981}
- {fileID: 1499562304012160075}
m_Description:
m_Settings: {fileID: 11400000, guid: 2b420ef1fd7d56b4f86537c540c40803, type: 2}
--- !u!114 &1499562304012160075
MonoBehaviour:
m_ObjectHideFlags: 1
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 5834b5087d578d24c926ce20cd31e6d6, type: 3}
m_Name: ContentUpdateGroupSchema
m_EditorClassIdentifier:
m_Group: {fileID: 0}
m_StaticContent: 0

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 4de1b4178aaf03b47bfed64c7b961b91
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 11400000
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 0f305f6f93f647249a13dd0f537996b7
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,729 @@
using System;
using System.IO;
using System.Linq;
using UnityEditor;
using UnityEditor.AddressableAssets;
using UnityEditor.AddressableAssets.Settings;
using UnityEngine;
using inspector.ext;
using UnityEditor.AddressableAssets.Settings.GroupSchemas;
using System.Collections.Generic;
using UnityEngine.AddressableAssets;
using System.Text.RegularExpressions;
namespace addressables.helper
{
[Serializable]
public class GroupDefine
{
public string name;
[inspector.ext.Folder]
public string folder;
public string folderPath => folder.ToFolderInfo().path;
public AddressableAssetGroupTemplate template;
public AssetLabelReference[] labels;
public void CopyToStreamingAssets()
{
var addrSettings = AddressableAssetSettingsDefaultObject.Settings;
var group = addrSettings.FindGroup(name);
var buildPath = group.Settings.RemoteCatalogBuildPath;
var schema = group.GetSchema<BundledAssetGroupSchema>();
if (schema != null)
{
if (schema.BundleMode == BundledAssetGroupSchema.BundlePackingMode.PackSeparately)
{
foreach (var entry in group.entries)
{
if (entry.labels.Any(x => x == "pack"))
{
if (Directory.Exists(buildPath.GetValue(addrSettings)) == false)
{
Debug.LogError($"{group.name} {entry.address} {buildPath.GetValue(addrSettings)}");
continue;
}
string bundleName = Path.GetFileName(entry.BundleFileId);
if (string.IsNullOrEmpty(bundleName))
{
Debug.LogError($"{group.name} {entry.address}");
continue;
}
var bunldes = Directory.GetFiles(buildPath.GetValue(addrSettings), bundleName);
if (bunldes.Length != 1)
{
Debug.LogError($"{group.name} {entry.address} {bunldes.Length} {bundleName}");
continue;
}
//copy bundle
var dest = Path.Combine(Application.streamingAssetsPath, Path.GetFileName(bunldes[0]));
File.Copy(bunldes[0], dest, true);
}
}
}
else if (schema.BundleMode == BundledAssetGroupSchema.BundlePackingMode.PackTogether)
{
foreach (var entry in group.entries)
{
if (entry.labels.Any(x => x == "pack"))
{
if (Directory.Exists(buildPath.GetValue(addrSettings)) == false)
{
Debug.LogError($"{group.name} {entry.address} {buildPath.GetValue(addrSettings)}");
continue;
}
string bundleName = Path.GetFileName(entry.BundleFileId);
if (string.IsNullOrEmpty(bundleName))
{
Debug.LogError($"{group.name} {entry.address}");
continue;
}
var bunldes = Directory.GetFiles(buildPath.GetValue(addrSettings), bundleName);
if (bunldes.Length != 1)
{
Debug.LogError($"{group.name} {entry.address} {bunldes.Length} {bundleName}");
continue;
}
//copy bundle
var dest = Path.Combine(Application.streamingAssetsPath, Path.GetFileName(bunldes[0]));
File.Copy(bunldes[0], dest, true);
return;
}
}
}
else if (schema.BundleMode == BundledAssetGroupSchema.BundlePackingMode.PackTogetherByLabel)
{
List<string> names = new List<string>();
foreach (var entry in group.entries)
{
if (entry.labels.Any(x => x == "pack"))
{
if (Directory.Exists(buildPath.GetValue(addrSettings)) == false)
{
Debug.LogError($"{group.name} {entry.address} {buildPath.GetValue(addrSettings)}");
continue;
}
string bundleName = Path.GetFileName(entry.BundleFileId);
if (string.IsNullOrEmpty(bundleName))
{
Debug.LogError($"{group.name} {entry.address}");
continue;
}
if (names.Contains(bundleName))
{
continue;
}
var bunldes = Directory.GetFiles(buildPath.GetValue(addrSettings), bundleName);
if (bunldes.Length != 1)
{
Debug.LogError($"{group.name} {entry.address} {bunldes.Length} {bundleName}");
continue;
}
names.Add(bundleName);
//copy bundle
var dest = Path.Combine(Application.streamingAssetsPath, Path.GetFileName(bunldes[0]));
File.Copy(bunldes[0], dest, true);
}
}
}
}
}
}
[Serializable]
public class GroupFolderDefine
{
public string name;
[inspector.ext.Folder]
public string folder;
public string folderPath => folder.ToFolderInfo().path;
public AddressableAssetGroupTemplate template;
public AssetLabelReference[] labels;
}
public class AddressableHelperSetting : ScriptableObject
{
public string[] MamualGroupNames;
public string[] MamualGroupNamePrefixs;
public GroupDefine[] GroupDefines;
public GroupFolderDefine[] GroupFolderDefines;
}
public class AddressableHelper
{
private const string helperSettingPath = "Assets/Settings/AddressableHelperSetting.asset";
public static bool IsSettingExists() => File.Exists(helperSettingPath);
[MenuItem("Window/Asset Management/Helper/Create Setting", true)]
static bool ValidateCreateSetting() => !IsSettingExists();
[MenuItem("Window/Asset Management/Helper/Create Setting")]
static void CreateSetting()
{
var instance = ScriptableObject.CreateInstance<AddressableHelperSetting>();
AssetDatabase.CreateAsset(instance, helperSettingPath);
}
//[MenuItem("Window/Asset Management/Helper/Sync Groups", true)]
//static bool ValidateSyncGroups() => IsSettingExists();
//[MenuItem("Window/Asset Management/Helper/Sync Groups &#F")]
public static void SyncGroups()
{
var helperSetting = AssetDatabase.LoadAssetAtPath<AddressableHelperSetting>(helperSettingPath);
var defines = helperSetting.GroupDefines;
var addrSettings = AddressableAssetSettingsDefaultObject.Settings;
var manualGroupNames = helperSetting.MamualGroupNames;
var MamualGroupNamePrefixs = helperSetting.MamualGroupNamePrefixs;
// Debug.Log($"[AddressableHelper] {addrSettings.groups.Select(x => x.Name)}");
var dbt = addrSettings.groups;
foreach (var x in dbt)
{
Debug.Log(x);
}
// Debug.Log($"[AddressableHelper] {addrSettings.groups.Select(x => x.Name).ToList()}");
var existsGroupNames = addrSettings.groups.Select(x => x.Name).ToList();
var newGroupNames = helperSetting.GroupDefines.Select(x => x.name)
.Concat(helperSetting.GroupFolderDefines.Select(x => x.name))
.ToList();
var allGroupNames = manualGroupNames.Concat(newGroupNames).ToList();
for(int i = 0; i < MamualGroupNamePrefixs.Length;i++)
{
var prefix = MamualGroupNamePrefixs[i];
if (string.IsNullOrEmpty(prefix))
continue;
var manualGroups = existsGroupNames.Where(x => x.StartsWith(prefix)).ToList();
if (manualGroups.Count > 0)
{
Debug.Log($"[AddressableHelper] add manual group {prefix}");
allGroupNames.AddRange(manualGroups);
}
}
// remove groups not defined in helper setting
for (int i = existsGroupNames.Count - 1; i >= 0; i--)
{
var group = existsGroupNames[i];
if (!allGroupNames.Contains(group))
{
Debug.Log($"[AddressableHelper] remove group {group}");
addrSettings.RemoveGroup(addrSettings.FindGroup(group));
existsGroupNames.RemoveAt(i);
}
}
foreach (var groupDefine in defines)
{
var groupName = groupDefine.name;
var group = addrSettings.FindGroup(groupName);
if (null == group)
{
Debug.Log($"[AddressableHelper] create group {groupDefine.name}");
group = CreateGroup(groupDefine, addrSettings);
groupDefine.template.ApplyToAddressableAssetGroup(group);
}
else
{
var entries = group.entries.ToList();
Debug.Log($"[AddressableHelper] clean group {groupDefine.name} {entries.Count}");
foreach (var entry in entries)
{
group.RemoveAssetEntry(entry);
}
}
Debug.Log($"[AddressableHelper] sync group {groupDefine.name}");
SyncEntries(groupDefine, group, addrSettings);
EditorUtility.SetDirty(group);
}
var folderDefines = helperSetting.GroupFolderDefines;
foreach (var folderDefine in folderDefines)
{
var groupName = folderDefine.name;
var group = addrSettings.FindGroup(groupName);
if (null == group)
{
Debug.Log($"[AddressableHelper] create group {folderDefine.name}");
group = CreateGroupByFolder(groupName, folderDefine, addrSettings);
folderDefine.template.ApplyToAddressableAssetGroup(group);
}
else
{
var entries = group.entries.ToList();
Debug.Log($"[AddressableHelper] clean group {folderDefine.name} {entries.Count}");
foreach (var entry in entries)
{
group.RemoveAssetEntry(entry);
}
}
Debug.Log($"[AddressableHelper] sync group {folderDefine.name}");
SyncEntriesByFolder(folderDefine, group, addrSettings);
EditorUtility.SetDirty(group);
}
EditorUtility.SetDirty(addrSettings);
AssetDatabase.SaveAssets();
}
private static AddressableAssetGroup CreateGroupByFolder(string groupName, GroupFolderDefine groupDefine, AddressableAssetSettings addrSettings)
{
var template = groupDefine.template;
var group = addrSettings.CreateGroup(groupName, false, false, true, null, template.GetTypes());
return group;
}
private static void SyncEntriesByFolder(GroupFolderDefine groupDefine, AddressableAssetGroup group, AddressableAssetSettings addrSettings)
{
var folder = new string[] { groupDefine.folderPath };
//获取文件夹下的所有文件夹
var assetsGUIDs = AssetDatabase.FindAssets("", folder);
var assetPaths = assetsGUIDs.Select(_ => AssetDatabase.GUIDToAssetPath(_)).ToArray();
var count = assetsGUIDs.Length;
Regex regexA = new Regex(groupDefine.folderPath + "/(.*?)/");
Regex regexB = new Regex(".*?/([^/]+)$");
for (int i = 0; i < count; i++)
{
var guid = assetsGUIDs[i];
var entry = group.GetAssetEntry(guid);
string address = Path.GetFileNameWithoutExtension(assetPaths[i]);
string folderName = Path.GetFileName(assetPaths[i]);
if (folderName.Contains("."))
{
if (entry == null || entry.address != address)
{
entry = addrSettings.CreateOrMoveEntry(guid, group);
entry.address = address;
//获取文件所在一级目录
string directoryPath = assetPaths[i];
//int startIndex = 1 + directoryPath.IndexOf(groupDefine.folderPath) + groupDefine.folderPath.Length;
//int endIndex = directoryPath.IndexOf("/", startIndex);
//directoryPath = directoryPath.Substring(startIndex, endIndex - startIndex);
//directoryPath = assetPaths[i];
Match match = regexA.Match(directoryPath);
if (match.Groups.Count > 1)
{
directoryPath = match.Groups[1].Value;
}
else
{
match = regexB.Match(groupDefine.folderPath);
directoryPath = match.Groups[1].Value;
}
entry.SetLabel(directoryPath, true, true);
for (int j = 0; j < groupDefine.labels.Length; j++)
{
if (!string.IsNullOrEmpty(groupDefine.labels[j].labelString))
{
entry.SetLabel(groupDefine.labels[j].labelString, true);
}
}
EditorUtility.SetDirty(group);
}
}
}
}
private static void SyncEntries(GroupDefine groupDefine, AddressableAssetGroup group, AddressableAssetSettings addrSettings)
{
var folder = new string[] { groupDefine.folderPath };
var assetsGUIDs = AssetDatabase.FindAssets("", folder);
var assetPaths = assetsGUIDs.Select(_ => AssetDatabase.GUIDToAssetPath(_)).ToArray();
var count = assetsGUIDs.Length;
for (int i = 0; i < count; i++)
{
if (Directory.Exists(assetPaths[i]))
continue;
var guid = assetsGUIDs[i];
var entry = group.GetAssetEntry(guid);
string address = Path.GetFileNameWithoutExtension(assetPaths[i]);
if (entry == null || entry.address != address)
{
entry = addrSettings.CreateOrMoveEntry(guid, group);
entry.address = address;
for (int j = 0; j < groupDefine.labels.Length; j++)
{
if (!string.IsNullOrEmpty(groupDefine.labels[j].labelString))
{
entry.SetLabel(groupDefine.labels[j].labelString, true);
}
}
EditorUtility.SetDirty(group);
}
}
}
private static AddressableAssetGroup CreateGroup(GroupDefine groupDefine, AddressableAssetSettings addrSettings)
{
var template = groupDefine.template;
var group = addrSettings.CreateGroup(groupDefine.name, false, false, true, null, template.GetTypes());
return group;
}
[MenuItem("Window/Asset Management/Helper/Clean StreamingAssets")]
public static void CleanStreamingAssets()
{
// delete all file with ext .bundle in StreamingAssets fold
string streamingAssetsPath = Application.streamingAssetsPath;
string[] bundleFiles = Directory.GetFiles(streamingAssetsPath, "*.bundle");
string[] bundleMetaFiles = Directory.GetFiles(streamingAssetsPath, "*.bundle.meta");
foreach (string bundleFile in bundleFiles)
{
File.Delete(bundleFile);
}
foreach (string metaFile in bundleMetaFiles)
{
File.Delete(metaFile);
}
AssetDatabase.Refresh();
}
[MenuItem("Window/Asset Management/Helper/Copy To StreamingAssets")]
public static void CopyToStreamingAssets()
{
//load helper setting
//var helperSetting = AssetDatabase.LoadAssetAtPath<AddressableHelperSetting>(helperSettingPath);
//foreach (var groupDefine in helperSetting.GroupDefines)
//{
// groupDefine.CopyToStreamingAssets();
//}
AddressableAssetSettings addrSettings = AddressableAssetSettingsDefaultObject.Settings;
var groups = addrSettings.groups;
foreach (var group in groups)
{
if (group.Settings.BuildRemoteCatalog)
{
CopyToStreamingAssets(group, addrSettings);
}
}
AssetDatabase.Refresh();
}
private static void CopyToStreamingAssets(AddressableAssetGroup group, AddressableAssetSettings addrSettings)
{
var buildPath = group.Settings.RemoteCatalogBuildPath;
var schema = group.GetSchema<BundledAssetGroupSchema>();
if (schema != null)
{
if (schema.BundleMode == BundledAssetGroupSchema.BundlePackingMode.PackSeparately)
{
foreach (var entry in group.entries)
{
if (entry.labels.Any(x => x == "pack"))
{
if (Directory.Exists(buildPath.GetValue(addrSettings)) == false)
{
Debug.LogError($"{group.name} {entry.address} {buildPath.GetValue(addrSettings)}");
continue;
}
string bundleName = Path.GetFileName(entry.BundleFileId);
if (string.IsNullOrEmpty(bundleName))
{
Debug.LogError($"{group.name} {entry.address}");
continue;
}
var bunldes = Directory.GetFiles(buildPath.GetValue(addrSettings), bundleName);
if (bunldes.Length != 1)
{
Debug.LogError($"{group.name} {entry.address} {bunldes.Length} {bundleName}");
continue;
}
//copy bundle
var dest = Path.Combine(Application.streamingAssetsPath, Path.GetFileName(bunldes[0]));
File.Copy(bunldes[0], dest, true);
}
}
}
else if (schema.BundleMode == BundledAssetGroupSchema.BundlePackingMode.PackTogether)
{
foreach (var entry in group.entries)
{
if (entry.labels.Any(x => x == "pack"))
{
if (Directory.Exists(buildPath.GetValue(addrSettings)) == false)
{
Debug.LogError($"{group.name} {entry.address} {buildPath.GetValue(addrSettings)}");
continue;
}
string bundleName = Path.GetFileName(entry.BundleFileId);
if (string.IsNullOrEmpty(bundleName))
{
Debug.LogError($"{group.name} {entry.address}");
continue;
}
var bunldes = Directory.GetFiles(buildPath.GetValue(addrSettings), bundleName);
if (bunldes.Length != 1)
{
Debug.LogError($"{group.name} {entry.address} {bunldes.Length} {bundleName}");
continue;
}
//copy bundle
var dest = Path.Combine(Application.streamingAssetsPath, Path.GetFileName(bunldes[0]));
File.Copy(bunldes[0], dest, true);
return;
}
}
}
else if (schema.BundleMode == BundledAssetGroupSchema.BundlePackingMode.PackTogetherByLabel)
{
List<string> names = new List<string>();
foreach (var entry in group.entries)
{
if (entry.labels.Any(x => x == "pack"))
{
if (Directory.Exists(buildPath.GetValue(addrSettings)) == false)
{
Debug.LogError($"{group.name} {entry.address} {buildPath.GetValue(addrSettings)}");
continue;
}
string bundleName = Path.GetFileName(entry.BundleFileId);
if (string.IsNullOrEmpty(bundleName))
{
Debug.LogError($"{group.name} {entry.address}");
continue;
}
if (names.Contains(bundleName))
{
continue;
}
var bunldes = Directory.GetFiles(buildPath.GetValue(addrSettings), bundleName);
if (bunldes.Length != 1)
{
Debug.LogError($"{group.name} {entry.address} {bunldes.Length} {bundleName}");
continue;
}
names.Add(bundleName);
//copy bundle
var dest = Path.Combine(Application.streamingAssetsPath, Path.GetFileName(bunldes[0]));
File.Copy(bunldes[0], dest, true);
}
}
}
}
}
public static HashSet<string> GetPackFileNames()
{
var names = new HashSet<string>();
AddressableAssetSettings addrSettings = AddressableAssetSettingsDefaultObject.Settings;
var groups = addrSettings.groups;
foreach (var group in groups)
{
if (group.Settings.BuildRemoteCatalog)
{
GetPackFileNames(group, addrSettings, names);
}
}
return names;
}
private static void GetPackFileNames(AddressableAssetGroup group, AddressableAssetSettings addrSettings, HashSet<string> names)
{
var buildPath = group.Settings.RemoteCatalogBuildPath;
var schema = group.GetSchema<BundledAssetGroupSchema>();
if (schema != null)
{
if (schema.BundleMode == BundledAssetGroupSchema.BundlePackingMode.PackSeparately)
{
foreach (var entry in group.entries)
{
if (entry.labels.Any(x => x == "pack"))
{
if (Directory.Exists(buildPath.GetValue(addrSettings)) == false)
{
Debug.LogError($"{group.name} {entry.address} {buildPath.GetValue(addrSettings)}");
continue;
}
string bundleName = Path.GetFileName(entry.BundleFileId);
names.Add(bundleName);
}
}
}
else if (schema.BundleMode == BundledAssetGroupSchema.BundlePackingMode.PackTogether)
{
foreach (var entry in group.entries)
{
if (entry.labels.Any(x => x == "pack"))
{
if (Directory.Exists(buildPath.GetValue(addrSettings)) == false)
{
Debug.LogError($"{group.name} {entry.address} {buildPath.GetValue(addrSettings)}");
continue;
}
string bundleName = Path.GetFileName(entry.BundleFileId);
names.Add(bundleName);
break;
}
}
}
else if (schema.BundleMode == BundledAssetGroupSchema.BundlePackingMode.PackTogetherByLabel)
{
foreach (var entry in group.entries)
{
if (entry.labels.Any(x => x == "pack"))
{
if (Directory.Exists(buildPath.GetValue(addrSettings)) == false)
{
Debug.LogError($"{group.name} {entry.address} {buildPath.GetValue(addrSettings)}");
continue;
}
string bundleName = Path.GetFileName(entry.BundleFileId);
if (names.Contains(bundleName))
{
continue;
}
names.Add(bundleName);
}
}
}
}
}
[MenuItem("Window/Asset Management/Helper/Copy All To StreamingAssets")]
public static void CopyALLToStreamingAssets()
{
var addrSettings = AddressableAssetSettingsDefaultObject.Settings;
var bundle_dir = addrSettings.RemoteCatalogBuildPath.GetValue(addrSettings);
var bunldes = Directory.GetFiles(bundle_dir, $"*.bundle");
foreach (var bunlde in bunldes)
{
File.Copy(bunlde, bunlde.Replace(bundle_dir, Application.streamingAssetsPath), true);
}
AssetDatabase.Refresh();
}
public static string ExportAssetsFile()
{
var addrSettings = AddressableAssetSettingsDefaultObject.Settings;
var bundle_dir = addrSettings.RemoteCatalogBuildPath.GetValue(addrSettings);
var allFileNames = new HashSet<string>(Directory.GetFiles(bundle_dir, $"*.bundle").Select(p => Path.GetFileName(p)));
var packFileNanes = GetPackFileNames();
var downloadFileNames = allFileNames.Except(packFileNanes);
var bundles = new Dictionary<string, List<string>>();
bundles["pack"] = packFileNanes.ToList();
bundles["download"] = downloadFileNames.ToList();
return Newtonsoft.Json.JsonConvert.SerializeObject(bundles, Newtonsoft.Json.Formatting.Indented);
}
//public static void SyncGroups()
//{
//var helperSetting = AssetDatabase.LoadAssetAtPath<AddressableHelperSetting>(helperSettingPath);
//var defines = helperSetting.GroupDefines;
//var addrSettings = AddressableAssetSettingsDefaultObject.Settings;
//foreach (var groupDefine in defines)
//{
//var groupName = groupDefine.name;
//var group = addrSettings.FindGroup(groupName);
//if (null == group)
//{
//group = CreateGroup(groupDefine, addrSettings);
//}
//groupDefine.template.ApplyToAddressableAssetGroup(group);
//SyncEntries(groupDefine, group, addrSettings);
//EditorUtility.SetDirty(addrSettings);
//AssetDatabase.SaveAssets();
//}
//var folderDefines = helperSetting.GroupFolderDefines;
//foreach (var folderDefine in folderDefines)
//{
//var groupName = folderDefine.name;
//var group = addrSettings.FindGroup(groupName);
//if (null == group)
//{
//group = CreateGroupByFolder(groupName, folderDefine, addrSettings);
//}
//folderDefine.template.ApplyToAddressableAssetGroup(group);
//SyncEntriesByFolder(folderDefine, group, addrSettings);
//EditorUtility.SetDirty(addrSettings);
//AssetDatabase.SaveAssets();
//}
//}
//[MenuItem("Window/Asset Management/Helper/Sync Groups PreloadOrPack", true)]
//static bool ValidateSyncGroupsPRLabel() => IsSettingExists();
//[MenuItem("Window/Asset Management/Helper/Sync Groups PreloadOrPack")]
//public static void SyncGroupsPRLabel()
//{
//var helperSetting = AssetDatabase.LoadAssetAtPath<AddressableHelperSetting>(helperSettingPath);
//var defines = helperSetting.GroupDefines;
//var addrSettings = AddressableAssetSettingsDefaultObject.Settings;
//foreach (var groupDefine in defines)
//{
//var groupName = groupDefine.name;
//var group = addrSettings.FindGroup(groupName);
//if (null != group)
//{
//foreach (var item in groupDefine.labels)
//{
//group.entries.ToList().ForEach(x => x.SetLabel(item.labelString, true, true));
//}
//}
//}
//EditorUtility.SetDirty(addrSettings);
//AssetDatabase.SaveAssets();
//}
//[MenuItem("Window/Asset Management/Helper/Sync Groups RewardLabel", true)]
//static bool ValidateSyncGroupsRewardLabel() => IsSettingExists();
//[MenuItem("Window/Asset Management/Helper/Sync Groups RewardLabel")]
//public static void SyncGroupsRewardLabel()
//{
//var helperSetting = AssetDatabase.LoadAssetAtPath<AddressableHelperSetting>(helperSettingPath);
//var defines = helperSetting.GroupDefines;
//var addrSettings = AddressableAssetSettingsDefaultObject.Settings;
//foreach (var groupDefine in defines)
//{
//var groupName = groupDefine.name;
//var group = addrSettings.FindGroup(groupName);
//if (null != group)
//{
//foreach (var item in groupDefine.rewardLabels)
//{
//group.entries.ToList().ForEach(x => x.SetLabel(item.labelString, false, true));
//}
//}
//}
//EditorUtility.SetDirty(addrSettings);
//AssetDatabase.SaveAssets();
//}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 218c59bf2d66c0c40b2118af7c5cdc61
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,20 @@
{
"name": "addressables.helper",
"rootNamespace": "addressables.helper",
"references": [
"Unity.Addressables.Editor",
"Unity.Addressables",
"inspector.extension"
],
"includePlatforms": [
"Editor"
],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": true,
"defineConstraints": [],
"versionDefines": [],
"noEngineReferences": false
}

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: ff1eccee924c22c468a32e5ed39e52ce
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,11 @@
{
"name": "com.addressable.helper",
"version": "0.0.1",
"displayName": "addressables helper",
"unity": "2020.3",
"unityRelease": "4f1",
"author": {
"name": "Skistua",
"email": "b166er.dada@gmail.com"
}
}

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: aef2de6b51b58124689c45f28f861db0
PackageManifestImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 39b6548830366c04697b5de123deec0a
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: fe88a087b0795174f9c8ec2369f4ccb2
folderAsset: yes
timeCreated: 1516620937
licenseType: Store
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,239 @@
using UnityEngine;
using System.Collections;
using UnityEditor;
using UnityEngine.Playables;
using System;
namespace RootMotion
{
public class BakerInspector : Editor
{
protected void DrawKeyframeSettings(Baker script)
{
if (script.isBaking) return;
EditorGUILayout.Space();
EditorGUILayout.PropertyField(serializedObject.FindProperty("frameRate"));
EditorGUILayout.PropertyField(serializedObject.FindProperty("keyReductionError"));
}
protected void DrawModeSettings(Baker script)
{
if (script.isBaking) return;
EditorGUILayout.Space();
switch(script.mode)
{
case Baker.Mode.AnimationClips:
EditorGUILayout.PropertyField(serializedObject.FindProperty("inheritClipSettings"));
if (!serializedObject.FindProperty("inheritClipSettings").boolValue) DrawClipSettings();
break;
default:
DrawClipSettings();
break;
}
EditorGUILayout.Space();
EditorGUILayout.PropertyField(serializedObject.FindProperty("mode"));
switch (script.mode)
{
case Baker.Mode.AnimationClips:
EditorGUILayout.PropertyField(serializedObject.FindProperty("animationClips"), true);
EditorGUILayout.PropertyField(serializedObject.FindProperty("appendName"));
break;
case Baker.Mode.AnimationStates:
EditorGUILayout.PropertyField(serializedObject.FindProperty("animationStates"), true);
EditorGUILayout.PropertyField(serializedObject.FindProperty("appendName"));
break;
case Baker.Mode.PlayableDirector:
EditorGUILayout.PropertyField(serializedObject.FindProperty("saveName"));
break;
default:
EditorGUILayout.PropertyField(serializedObject.FindProperty("saveName"));
break;
}
//EditorGUILayout.BeginHorizontal();
EditorGUILayout.Space();
EditorGUILayout.LabelField(new GUIContent("Save To Folder"));
if (EditorGUILayout.DropdownButton(new GUIContent(serializedObject.FindProperty("saveToFolder").stringValue, "The folder to save the baked AnimationClips to."), FocusType.Passive, GUILayout.MaxWidth(400)))
{
serializedObject.FindProperty("saveToFolder").stringValue = SaveClipFolderPanel.Apply(serializedObject.FindProperty("saveToFolder").stringValue);
}
//EditorGUILayout.EndHorizontal();
}
private void DrawClipSettings()
{
var p = serializedObject.FindProperty("clipSettings");
EditorGUILayout.PropertyField(p, false);
if (p.isExpanded)
{
EditorGUILayout.BeginVertical("Box");
EditorGUI.indentLevel++;
EditorGUILayout.PropertyField(p.FindPropertyRelative("loopTime"));
EditorGUI.indentLevel++;
EditorGUILayout.PropertyField(p.FindPropertyRelative("loopBlend"), new GUIContent("Loop Pose"));
EditorGUILayout.PropertyField(p.FindPropertyRelative("cycleOffset"));
EditorGUI.indentLevel--;
EditorGUILayout.Space();
EditorGUILayout.LabelField(new GUIContent("Root Transform Rotation"));
EditorGUI.indentLevel++;
EditorGUILayout.PropertyField(p.FindPropertyRelative("loopBlendOrientation"), new GUIContent("Bake Into Pose"));
EditorGUILayout.PropertyField(p.FindPropertyRelative("basedUponRotation"), new GUIContent("Based Upon"));
EditorGUILayout.PropertyField(p.FindPropertyRelative("orientationOffsetY"), new GUIContent("Offset"));
EditorGUI.indentLevel--;
EditorGUILayout.Space();
EditorGUILayout.LabelField(new GUIContent("Root Transform Position (Y)"));
EditorGUI.indentLevel++;
EditorGUILayout.PropertyField(p.FindPropertyRelative("loopBlendPositionY"), new GUIContent("Bake Into Pose"));
EditorGUILayout.PropertyField(p.FindPropertyRelative("basedUponY"), new GUIContent("Based Upon (at Start)"));
EditorGUILayout.PropertyField(p.FindPropertyRelative("level"), new GUIContent("Offset"));
EditorGUI.indentLevel--;
EditorGUILayout.Space();
EditorGUILayout.LabelField(new GUIContent("Root Transform Position (XZ)"));
EditorGUI.indentLevel++;
EditorGUILayout.PropertyField(p.FindPropertyRelative("loopBlendPositionXZ"), new GUIContent("Bake Into Pose"));
EditorGUILayout.PropertyField(p.FindPropertyRelative("basedUponXZ"), new GUIContent("Based Upon"));
EditorGUI.indentLevel--;
EditorGUILayout.Space();
EditorGUILayout.PropertyField(p.FindPropertyRelative("mirror"));
EditorGUI.indentLevel--;
EditorGUILayout.EndVertical();
}
}
private void TryBake(Baker script)
{
switch (script.mode)
{
case Baker.Mode.AnimationClips:
if (script.animator == null)
{
EditorGUILayout.LabelField("No Animator found on Baker GameObject", EditorStyles.helpBox);
return;
}
if (script.animator.isHuman && script.animator.runtimeAnimatorController == null)
{
EditorGUILayout.LabelField("Humanoid Animator needs to have a valid Controller assigned for clip baking (Unity crash bug)", EditorStyles.helpBox);
return;
}
if (script.animationClips.Length == 0)
{
EditorGUILayout.LabelField("Please add AnimationClips to bake", EditorStyles.helpBox);
return;
}
foreach (AnimationClip clip in script.animationClips)
{
if (clip == null)
{
EditorGUILayout.LabelField("One of the AnimationClips is null, can not bake.", EditorStyles.helpBox);
return;
}
}
if (GUILayout.Button("Bake Animation Clips")) script.BakeClip();
return;
case Baker.Mode.AnimationStates:
if (script.animator == null)
{
EditorGUILayout.LabelField("No Animator found on Baker GameObject", EditorStyles.helpBox);
return;
}
if (script.animationStates.Length == 0)
{
EditorGUILayout.LabelField("Please add Animation State names to bake. The Animator must contain AnimationStates with matching names. If AnimationState names match with clip names used in them, you can have the Baker fill the names in automatically by right-clicking on the component header and selecting 'Find Animation States'.", EditorStyles.helpBox);
return;
}
for (int i = 0; i < script.animationStates.Length; i++)
{
if (script.animationStates[i] == string.Empty || script.animationStates[i] == "")
{
EditorGUILayout.LabelField("One of the animation state names in 'Animation States' is empty, can not bake.", EditorStyles.helpBox);
return;
}
}
if (GUILayout.Button("Bake Animation States")) script.BakeClip();
return;
case Baker.Mode.PlayableDirector:
if (script.director == null)
{
EditorGUILayout.LabelField("No PlayableDirector found on Baker GameObject", EditorStyles.helpBox);
return;
}
if (GUILayout.Button("Bake Timeline")) script.BakeClip();
break;
case Baker.Mode.Realtime:
if (GUILayout.Button("Start Baking")) script.StartBaking();
return;
}
}
protected void DrawButtons(Baker script)
{
if (!script.enabled) return;
if (script.animator == null)
{
serializedObject.FindProperty("animator").objectReferenceValue = script.GetComponent<Animator>();
}
if (script.director == null)
{
serializedObject.FindProperty("director").objectReferenceValue = script.GetComponent<PlayableDirector>();
}
if (!Application.isPlaying)
{
EditorGUILayout.LabelField("Enter Play Mode to bake.", EditorStyles.helpBox);
return;
}
if (!script.isBaking)
{
TryBake(script);
}
else
{
GUI.color = Color.red;
switch (script.mode)
{
case Baker.Mode.Realtime:
if (GUILayout.Button("Stop Baking")) script.StopBaking();
break;
default:
GUILayout.Label("Baking Progress: " + System.Math.Round(script.bakingProgress, 2));
break;
}
GUI.color = Color.white;
EditorUtility.SetDirty(script);
}
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: dcf5801ad3ff7fa43b06824f09d82160
timeCreated: 1516619065
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,52 @@
using UnityEngine;
using System.Collections;
using UnityEditor;
namespace RootMotion
{
[CustomEditor(typeof(GenericBaker))]
public class GenericBakerInspector : BakerInspector
{
private GenericBaker script { get { return target as GenericBaker; } }
private MonoScript monoScript;
void OnEnable()
{
// Changing the script execution order
if (!Application.isPlaying)
{
monoScript = MonoScript.FromMonoBehaviour(script);
int currentExecutionOrder = MonoImporter.GetExecutionOrder(monoScript);
if (currentExecutionOrder != 15001) MonoImporter.SetExecutionOrder(monoScript, 15001);
}
}
public override void OnInspectorGUI()
{
serializedObject.Update();
DrawKeyframeSettings(script as Baker);
DrawGenericKeyframeSettings(script);
DrawModeSettings(script as Baker);
DrawButtons(script as Baker);
if (serializedObject.ApplyModifiedProperties())
{
EditorUtility.SetDirty(script);
}
}
private void DrawGenericKeyframeSettings(GenericBaker script)
{
if (script.isBaking) return;
EditorGUILayout.PropertyField(serializedObject.FindProperty("markAsLegacy"));
EditorGUILayout.PropertyField(serializedObject.FindProperty("root"));
EditorGUILayout.PropertyField(serializedObject.FindProperty("rootNode"));
EditorGUILayout.PropertyField(serializedObject.FindProperty("ignoreList"), true);
EditorGUILayout.PropertyField(serializedObject.FindProperty("bakePositionList"), true);
}
}
}

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 8f544a5bc87054e74ac2e415889ba75a
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:

View File

@@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: 73b96cf8495867d429c9c5b31ff6d6da
folderAsset: yes
timeCreated: 1516621014
licenseType: Store
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,38 @@
using UnityEngine;
using System.Collections;
using UnityEditor;
namespace RootMotion
{
public static class AnimationUtilityExtended
{
/// <summary>
/// Copies the curves with the specified property names from clipFrom to clipTo.
/// </summary>
/// <param name="fromClip">copy from clip.</param>
/// <param name="toClip">paste to clip</param>
/// <param name="propertyNames">Property names ("Root.T", "Root.Q", "LeftFoot.T"...).</param>
public static void CopyCurves(AnimationClip fromClip, AnimationClip toClip, string[] propertyNames)
{
EditorCurveBinding[] bindings = AnimationUtility.GetCurveBindings(fromClip);
for (int i = 0; i < bindings.Length; i++)
{
for (int n = 0; n < propertyNames.Length; n++)
{
if (bindings[i].propertyName == propertyNames[n])
{
CopyCurve(fromClip, toClip, bindings[i]);
}
}
}
}
public static void CopyCurve(AnimationClip fromClip, AnimationClip toClip, EditorCurveBinding binding)
{
AnimationCurve curve = AnimationUtility.GetEditorCurve(fromClip, binding);
toClip.SetCurve(string.Empty, typeof(Animator), binding.propertyName, curve);
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 054c55a0c5c10dc4fafcfd81aeaaec56
timeCreated: 1516620625
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,22 @@
using UnityEngine;
using UnityEditor;
using System.IO;
using System;
namespace RootMotion
{
public class SaveClipFolderPanel : EditorWindow
{
public static string Apply(string currentPath)
{
string path = EditorUtility.SaveFolderPanel("Save clip(s) to folder", currentPath, "");
if (path.Length != 0)
{
return path.Substring(path.IndexOf("Assets/"));
}
return currentPath;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 7edb6cbf0a3b9924d8f631c4c00fd38a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,52 @@
using UnityEngine;
using System.Collections;
using UnityEditor;
namespace RootMotion
{
[CustomEditor(typeof(HumanoidBaker))]
public class HumanoidBakerInspector : BakerInspector
{
private HumanoidBaker script { get { return target as HumanoidBaker; } }
private MonoScript monoScript;
void OnEnable()
{
// Changing the script execution order
if (!Application.isPlaying)
{
monoScript = MonoScript.FromMonoBehaviour(script);
int currentExecutionOrder = MonoImporter.GetExecutionOrder(monoScript);
if (currentExecutionOrder != 15000) MonoImporter.SetExecutionOrder(monoScript, 15000);
}
}
// TODO Move this to BakerInspector.cs
public override void OnInspectorGUI()
{
serializedObject.Update();
DrawKeyframeSettings(script as Baker);
DrawHumanoidKeyframeSettings(script);
DrawModeSettings(script as Baker);
DrawButtons(script as Baker);
if (serializedObject.ApplyModifiedProperties())
{
EditorUtility.SetDirty(script);
}
}
protected void DrawHumanoidKeyframeSettings(HumanoidBaker script)
{
if (script.isBaking) return;
EditorGUILayout.PropertyField(serializedObject.FindProperty("IKKeyReductionError"));
EditorGUILayout.PropertyField(serializedObject.FindProperty("muscleFrameRateDiv"));
EditorGUILayout.PropertyField(serializedObject.FindProperty("bakeHandIK"));
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: f8139af98945e154885b65eedbb102cc
timeCreated: 1516265598
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: 403e73ed4eb874619a26a7b37fbb9c35
folderAsset: yes
timeCreated: 1436186156
licenseType: Store
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,38 @@
using UnityEditor;
using UnityEngine;
using System.Collections;
namespace RootMotion.FinalIK {
/*
* Custom inspector for AimIK.
* */
[CustomEditor(typeof(AimIK))]
public class AimIKInspector : IKInspector {
private AimIK script { get { return target as AimIK; }}
protected override MonoBehaviour GetMonoBehaviour(out int executionOrder) {
executionOrder = 9997;
return script;
}
protected override void OnApplyModifiedProperties() {
if (!Application.isPlaying) script.solver.Initiate(script.transform);
}
protected override void AddInspector() {
// Draw the inspector for IKSolverAim
IKSolverAimInspector.AddInspector(solver, !Application.isPlaying);
// Warning box
string message = string.Empty;
if (!script.solver.IsValid(ref message)) AddWarningBox(message);
}
void OnSceneGUI() {
// Draw the scene veiw helpers
IKSolverAimInspector.AddScene(script.solver, new Color(1f, 0f, 0.5f, 1f), true);
}
}
}

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 4a8f3f357746148a98faf7ccd416a2a6
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,189 @@
using UnityEngine;
using UnityEditor;
using System.Collections;
using RootMotion;
namespace RootMotion.FinalIK {
/// <summary>
/// Custom inspector for the Aim Poser for visualizing pose range
/// </summary>
[CustomEditor(typeof(AimPoser))]
public class AimPoserInspector : Editor {
[System.Serializable]
public struct ColorDirection {
public Vector3 direction;
public Vector3 color;
public float dot;
public ColorDirection(Vector3 direction, Vector3 color) {
this.direction = direction.normalized;
this.color = color;
this.dot = 0;
}
}
private AimPoser script { get { return target as AimPoser; }}
private ColorDirection[] colorDirections;
private static Vector3[] poly = new Vector3[36];
void OnSceneGUI() {
for (int i = 0; i < script.poses.Length; i++) {
script.poses[i].yaw = Mathf.Clamp(script.poses[i].yaw, 0, 180);
script.poses[i].pitch = Mathf.Clamp(script.poses[i].pitch, 0, 180);
}
if (colorDirections == null) {
colorDirections = new ColorDirection[6] {
new ColorDirection(Vector3.right, Vector3.right),
new ColorDirection(Vector3.up, Vector3.up),
new ColorDirection(Vector3.forward, Vector3.forward),
new ColorDirection(Vector3.left, new Vector3(0f, 1f, 1f)),
new ColorDirection(Vector3.down, new Vector3(1f, 0f, 1f)),
new ColorDirection(Vector3.back, new Vector3(1f, 1f, 0f))
};
}
for (int i = 0; i < script.poses.Length; i++) {
if (script.poses[i].visualize) {
DrawPose(script.poses[i], script.transform.position, script.transform.rotation, GetDirectionColor(script.poses[i].direction));
}
}
}
private Color GetDirectionColor(Vector3 localDirection) {
localDirection = localDirection.normalized;
// Calculating dot products for all AxisDirections
for (int i = 0; i < colorDirections.Length; i++) {
colorDirections[i].dot = Mathf.Clamp(Vector3.Dot(colorDirections[i].direction, localDirection), 0f, 1f);
}
// Summing up the arm bend axis
Vector3 sum = Vector3.zero;
for (int i = 0; i < colorDirections.Length; i++) {
sum = Vector3.Lerp(sum, colorDirections[i].color, colorDirections[i].dot * colorDirections[i].dot);
}
return new Color(sum.x, sum.y, sum.z);
}
private static void DrawPose(AimPoser.Pose pose, Vector3 position, Quaternion rotation, Color color) {
if (pose.pitch <= 0f || pose.yaw <= 0f) return;
if (pose.direction == Vector3.zero) return;
Handles.color = color;
GUI.color = color;
Vector3 up = rotation * Vector3.up;
Vector3 normalizedPoseDirection = pose.direction.normalized;
Vector3 direction = rotation * normalizedPoseDirection;
// Direction and label
Handles.DrawLine(position, position + direction);
Inspector.ConeCap(0, position + direction, Quaternion.LookRotation(direction), 0.05f);
Handles.Label(position + direction.normalized * 1.1f, pose.name);
if (pose.yaw >= 180f && pose.pitch >= 180f) {
Handles.color = Color.white;
GUI.color = Color.white;
return;
}
Quaternion halfYaw = Quaternion.AngleAxis(pose.yaw, up);
float directionPitch = Vector3.Angle(up, direction);
Vector3 crossRight = halfYaw * Vector3.Cross(up, direction);
Vector3 crossLeft = Quaternion.Inverse(halfYaw) * Vector3.Cross(up, direction);
bool isVertical = normalizedPoseDirection == Vector3.up || normalizedPoseDirection == Vector3.down;
if (isVertical) {
crossRight = halfYaw * Vector3.right;
crossLeft = Quaternion.Inverse(halfYaw) * Vector3.right;
}
float minPitch = Mathf.Clamp(directionPitch - pose.pitch, 0f, 180f);
float maxPitch = Mathf.Clamp(directionPitch + pose.pitch, 0f, 180f);
Quaternion upToCornerUpperRight = Quaternion.AngleAxis(minPitch, crossRight);
Quaternion upToCornerLowerRight = Quaternion.AngleAxis(maxPitch, crossRight);
Quaternion upToCornerUpperLeft = Quaternion.AngleAxis(minPitch, crossLeft);
Quaternion upToCornerLowerLeft = Quaternion.AngleAxis(maxPitch, crossLeft);
Vector3 toCornerUpperRight = upToCornerUpperRight * up;
Vector3 toCornerLowerRight = upToCornerLowerRight * up;
Vector3 toCornerUpperLeft = upToCornerUpperLeft * up;
Vector3 toCornerLowerLeft = upToCornerLowerLeft * up;
if (pose.yaw < 180f) {
Handles.DrawLine(position, position + toCornerUpperRight);
Handles.DrawLine(position, position + toCornerUpperLeft);
Handles.DrawLine(position, position + toCornerLowerRight);
Handles.DrawLine(position, position + toCornerLowerLeft);
}
Vector3 d = direction;
if (isVertical) d = Vector3.forward;
if (pose.pitch < 180f) {
DrawPolyLineOnSphere(position, toCornerUpperLeft, toCornerUpperRight, d, Vector3.up, color);
DrawPolyLineOnSphere(position, toCornerLowerLeft, toCornerLowerRight, d, Vector3.up, color);
}
if (pose.yaw < 180f) {
DrawPolyLineOnSphere(position, toCornerUpperLeft, toCornerLowerLeft, Quaternion.Inverse(halfYaw) * d, crossLeft, color);
DrawPolyLineOnSphere(position, toCornerUpperRight, toCornerLowerRight, halfYaw * d, crossRight, color);
}
Handles.color = Color.white;
GUI.color = Color.white;
}
private static void DrawPolyLineOnSphere(Vector3 center, Vector3 d1, Vector3 d2, Vector3 direction, Vector3 axis, Color color) {
Handles.color = color;
Vector3 normal = axis;
Vector3 d1Ortho = d1;
Vector3.OrthoNormalize(ref normal, ref d1Ortho);
normal = axis;
Vector3 d2Ortho = d2;
Vector3.OrthoNormalize(ref normal, ref d2Ortho);
normal = axis;
Vector3 directionOrtho = direction;
Vector3.OrthoNormalize(ref normal, ref directionOrtho);
float angle = Vector3.Angle(d1Ortho, d2Ortho);
float dot = Vector3.Dot(directionOrtho, d1Ortho);
if (dot < 0) {
angle = 180 + (180 - angle);
}
int segments = Mathf.Clamp(Mathf.RoundToInt(angle / 36f) * 5, 3, 36);
float segmentF = angle / (float)(segments - 1);
for (int i = 0; i < segments; i++) {
poly[i] = center + Quaternion.AngleAxis(i * segmentF, axis) * d1;
}
Handles.color = new Color(color.r, color.g, color.b, color.a * 0.1f);
for (int i = 0; i < segments; i++) {
Handles.DrawLine(center, poly[i]);
}
Handles.color = color;
for (int i = 0; i < segments - 1; i++) {
Handles.DrawLine(poly[i], poly[i + 1]);
}
}
}
}

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 079587d3635eb48c3a5c0d57f8c3cc6f
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,38 @@
using UnityEditor;
using UnityEngine;
using System.Collections;
namespace RootMotion.FinalIK {
/*
* Custom inspector for ArmIK.
* */
[CustomEditor(typeof(ArmIK))]
public class ArmIKInspector : IKInspector {
private ArmIK script { get { return target as ArmIK; }}
protected override MonoBehaviour GetMonoBehaviour(out int executionOrder) {
executionOrder = 9997;
return script;
}
protected override void OnApplyModifiedProperties() {
if (!Application.isPlaying) script.solver.Initiate(script.transform);
}
protected override void AddInspector() {
// Draw the inspector for IKSolverTrigonometric
IKSolverArmInspector.AddInspector(solver, !Application.isPlaying, true);
// Warning box
string message = string.Empty;
if (!script.solver.IsValid(ref message)) AddWarningBox(message);
}
void OnSceneGUI() {
// Draw the scene veiw helpers
IKSolverArmInspector.AddScene(script.solver, new Color(0f, 1f, 1f, 1f), true);
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 07bc62a41db738b488fc9430a0a20772
timeCreated: 1528379362
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,115 @@
using UnityEditor;
using UnityEngine;
using System.Collections;
using System;
namespace RootMotion.FinalIK {
/*
* Custom inspector for Biped IK.
* */
[CustomEditor(typeof(BipedIK))]
public class BipedIKInspector : Editor {
private BipedIK script { get { return target as BipedIK; }}
private int selectedSolver = -1;
private SerializedProperty references, solvers;
private SerializedProperty[] solversProps;
private SerializedContent fixTransforms;
public void OnEnable() {
if (serializedObject == null) return;
// Store the MonoScript for changing script execution order
if (!Application.isPlaying) {
MonoScript monoScript = MonoScript.FromMonoBehaviour(script);
// Changing the script execution order to make sure BipedIK always executes after any other script except FullBodyBipedIK
int executionOrder = MonoImporter.GetExecutionOrder(monoScript);
if (executionOrder != 9998) MonoImporter.SetExecutionOrder(monoScript, 9998);
}
references = serializedObject.FindProperty("references");
solvers = serializedObject.FindProperty("solvers");
solversProps = BipedIKSolversInspector.FindProperties(solvers);
fixTransforms = new SerializedContent(serializedObject.FindProperty("fixTransforms"), new GUIContent("Fix Transforms", "If true, will fix all the Transforms used by the solver to their initial state in each Update. This prevents potential problems with unanimated bones and animator culling with a small cost of performance."));
// Automatically detecting references
if (!Application.isPlaying) {
if (script.references.isEmpty) {
BipedReferences.AutoDetectReferences(ref script.references, script.transform, new BipedReferences.AutoDetectParams(false, true));
references.isExpanded = true;
solvers.isExpanded = false;
for (int i = 0; i < solversProps.Length; i++) solversProps[i].isExpanded = false;
// Setting default values and initiating
script.InitiateBipedIK();
script.SetToDefaults();
EditorUtility.SetDirty(script);
} else script.InitiateBipedIK();
Warning.logged = false;
string message = string.Empty;
if (Application.isPlaying) {
if (BipedReferences.SetupError(script.references, ref message) || BipedReferences.SetupWarning(script.references, ref message)) {
Warning.Log(message, script.references.root, false);
}
}
}
}
// Override the default warning box
private void AddWarningBox(string message) {
EditorGUILayout.Space();
EditorGUILayout.LabelField("Invalid/incomplete setup, can't initiate solver. " + message, EditorStyles.helpBox);
EditorGUILayout.Space();
}
public override void OnInspectorGUI() {
serializedObject.Update();
EditorGUILayout.Space();
Inspector.AddContent(fixTransforms);
string message = string.Empty;
// Editing References
if (BipedReferencesInspector.AddModifiedInspector(references)) {
if (!Application.isPlaying) {
Warning.logged = false;
if (!BipedReferences.SetupError(script.references, ref message)) {
script.InitiateBipedIK();
}
}
}
if (BipedReferences.SetupError(script.references, ref message)) {
// Warning box
AddWarningBox(message);
Warning.Log(message, script.transform, false);
} else {
// Editing Solvers
BipedIKSolversInspector.AddInspector(solvers, solversProps);
}
EditorGUILayout.Space();
serializedObject.ApplyModifiedProperties();
}
void OnSceneGUI() {
if (!script.enabled) return;
// Draw the scene view helpers for the solvers
BipedIKSolversInspector.AddScene(script.solvers, ref selectedSolver);
}
}
}

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: f5864bb0a05eb491697063685c4d6cb3
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,120 @@
using UnityEngine;
using UnityEditor;
using System.Collections;
namespace RootMotion.FinalIK {
/*
* Custom inspector and scene view tools for Biped IK Solvers.
* */
public class BipedIKSolversInspector: IKSolverInspector {
/*
* Returns all solvers SeiralizedProperties
* */
public static SerializedProperty[] FindProperties(SerializedProperty prop) {
SerializedProperty[] props = new SerializedProperty[8] {
prop.FindPropertyRelative("leftFoot"),
prop.FindPropertyRelative("rightFoot"),
prop.FindPropertyRelative("leftHand"),
prop.FindPropertyRelative("rightHand"),
prop.FindPropertyRelative("spine"),
prop.FindPropertyRelative("aim"),
prop.FindPropertyRelative("lookAt"),
prop.FindPropertyRelative("pelvis"),
};
return props;
}
/*
* Draws the custom inspector for BipedIK.Solvers
* */
public static void AddInspector(SerializedProperty prop, SerializedProperty[] props) {
EditorGUILayout.PropertyField(prop, false);
if (prop.isExpanded) {
for (int i = 0; i < props.Length; i++) {
BeginProperty(props[i]);
if (props[i].isExpanded) {
if (i <= 3) IKSolverLimbInspector.AddInspector(props[i], false, false);
else if (i == 4) IKSolverHeuristicInspector.AddInspector(props[i], false, false);
else if (i == 5) IKSolverAimInspector.AddInspector(props[i], false);
else if (i == 6) IKSolverLookAtInspector.AddInspector(props[i], false, false);
else if (i == 7) ConstraintsInspector.AddInspector(props[i]);
}
EndProperty(props[i]);
}
}
}
/*
* Draws the scene view helpers for BipedIK.Solvers
* */
public static void AddScene(BipedIKSolvers solvers, ref int selected) {
// Draw limbs
for (int i = 0; i < solvers.limbs.Length; i++) {
IKSolverLimbInspector.AddScene(solvers.limbs[i] as IKSolverLimb, GetSolverColor(i), selected == i);
}
// Draw spine
IKSolverHeuristicInspector.AddScene(solvers.spine, GetSolverColor(4), selected == 4);
// Draw look at
IKSolverLookAtInspector.AddScene(solvers.lookAt, GetSolverColor(5), selected == 5);
// Draw aim
IKSolverAimInspector.AddScene(solvers.aim, GetSolverColor(6), selected == 6);
// Draw constraints
ConstraintsInspector.AddScene(solvers.pelvis, GetSolverColor(7), selected == 7);
// Selecting solvers
if (Application.isPlaying) {
for (int i = 0; i < solvers.ikSolvers.Length; i++) {
Handles.color = GetSolverColor(i);
if (solvers.ikSolvers[i].GetIKPositionWeight() > 0 && selected != i && solvers.ikSolvers[i].initiated) {
if (Inspector.DotButton(solvers.ikSolvers[i].GetIKPosition(), Quaternion.identity, GetHandleSize(solvers.ikSolvers[i].GetIKPosition()), GetHandleSize(solvers.ikSolvers[i].GetIKPosition()))) selected = i;
}
}
if ((solvers.pelvis.positionWeight > 0 || solvers.pelvis.rotationWeight > 0) && selected != solvers.ikSolvers.Length) {
Handles.color = GetSolverColor(7);
if (Inspector.DotButton(solvers.pelvis.position, Quaternion.identity, GetHandleSize(solvers.pelvis.position), GetHandleSize(solvers.pelvis.position))) selected = solvers.ikSolvers.Length;
}
}
}
/*
* Gets the color of the solver at index.
* */
private static Color GetSolverColor(int index) {
if (index == 0 || index == 2) return new Color(0f, 0.8f, 1f, 1f); // Left limb
if (index == 1 || index == 3) return new Color(0.3f, 1f, 0.3f, 1f); // Right limb
if (index == 4) return new Color(1f, 0.5f, 0.5f, 1f); // Spine
if (index == 5) return new Color(0.2f, 0.5f, 1f, 1f); // Look At
if (index == 6) return new Color(1f, 0f, 0.5f, 1f); // Aim
if (index == 7) return new Color(0.9f, 0.9f, 0.9f, 1f); // Pelvis
return Color.white;
}
/*
* Begin property box
* */
private static void BeginProperty(SerializedProperty prop) {
EditorGUI.indentLevel = 1;
EditorGUILayout.BeginVertical("Box");
EditorGUILayout.PropertyField(prop, false);
}
/*
* End Property box
* */
private static void EndProperty(SerializedProperty prop) {
EditorGUILayout.EndVertical();
if (prop.isExpanded) EditorGUILayout.Space();
EditorGUI.indentLevel = 1;
}
}
}

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 0569aef68e5c24672b37607a948d3c92
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,38 @@
using UnityEditor;
using UnityEngine;
using System.Collections;
namespace RootMotion.FinalIK {
/*
* Custom inspector for CCDIK.
* */
[CustomEditor(typeof(CCDIK))]
public class CCDIKInspector : IKInspector {
private CCDIK script { get { return target as CCDIK; }}
protected override MonoBehaviour GetMonoBehaviour(out int executionOrder) {
executionOrder = 9997;
return script;
}
protected override void OnApplyModifiedProperties() {
if (!Application.isPlaying) script.solver.Initiate(script.transform);
}
protected override void AddInspector() {
// Draw the inspector for IKSolverCCD
IKSolverHeuristicInspector.AddInspector(solver, !Application.isPlaying, true);
// Warning box
string message = string.Empty;
if (!script.solver.IsValid(ref message)) AddWarningBox(message);
}
void OnSceneGUI() {
// Draw the scene veiw helpers
IKSolverHeuristicInspector.AddScene(script.solver, Color.cyan, true);
}
}
}

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 90fdc724098474c78a5ae764777a5008
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,67 @@
using UnityEngine;
using UnityEditor;
using System.Collections;
namespace RootMotion.FinalIK {
/*
* Custom inspector and scene view tools for Constraints
* */
public class ConstraintsInspector: IKSolverInspector {
#region Public methods
/*
* Draws the custom inspector for Constraints
* */
public static void AddInspector(SerializedProperty prop) {
if (!prop.isExpanded) return;
// Main properties
EditorGUILayout.PropertyField(prop.FindPropertyRelative("target"), new GUIContent("Target", "Target transform for the pelvis (optional). If assigned, will overwrite pelvis.position in each update."));
EditorGUILayout.PropertyField(prop.FindPropertyRelative("positionOffset"), new GUIContent("Pos Offset", "Pelvis offset from animation. If there is no animation playing and Fix Transforms is unchecked, it will make the character fly away."));
EditorGUILayout.PropertyField(prop.FindPropertyRelative("positionWeight"), new GUIContent("Pos Weight", "The weight of lerping the pelvis to bipedIK.solvers.pelvis.position."));
EditorGUILayout.PropertyField(prop.FindPropertyRelative("rotationOffset"), new GUIContent("Rot Offset", "Pelvis rotation offset from animation. If there is no animation playing and Fix Transforms is unchecked, it will make the character spin."));
EditorGUILayout.PropertyField(prop.FindPropertyRelative("rotationWeight"), new GUIContent("Rot Weight", "The weiight of slerping the pelvis to bipedIK.solver.pelvis.rotation."));
EditorGUILayout.Space();
}
/*
* Draws the scene view helpers for Constraints
* */
public static void AddScene(Constraints constraints, Color color, bool modifiable) {
if (!constraints.IsValid()) return;
Handles.color = color;
GUI.color = color;
// Transform
Inspector.SphereCap(0, constraints.transform.position, Quaternion.identity, GetHandleSize(constraints.transform.position));
// Target
Handles.color = new Color(color.r, color.g, color.b, color.a * constraints.positionWeight);
Handles.DrawLine(constraints.transform.position, constraints.position);
Handles.color = color;
if (Application.isPlaying && modifiable && (constraints.positionWeight > 0 || constraints.rotationWeight > 0)) {
Inspector.CubeCap(0, constraints.position, Quaternion.Euler(constraints.rotation), GetHandleSize(constraints.transform.position));
// Manipulating position and rotation
switch(Tools.current) {
case Tool.Move:
constraints.position = Handles.PositionHandle(constraints.position, Quaternion.Euler(constraints.rotation));
break;
case Tool.Rotate:
constraints.rotation = Handles.RotationHandle(Quaternion.Euler(constraints.rotation), constraints.position).eulerAngles;
break;
}
}
Handles.color = Color.white;
GUI.color = Color.white;
}
#endregion Public methods
}
}

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: b9903cbc6483347caadff80dc461c23f
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,87 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using UnityEditor.SceneManagement;
namespace RootMotion.FinalIK
{
[CustomEditor(typeof(EditorIK))]
public class EditorIKInspector : Editor
{
private EditorIK script { get { return target as EditorIK; } }
public override void OnInspectorGUI()
{
base.OnInspectorGUI();
if (Application.isPlaying) return;
if (!script.enabled) return;
EditorGUILayout.Space();
if (script.defaultPose != null && script.ik != null && !script.ik.GetIKSolver().executedInEditor)
{
if (GUILayout.Button("Store Default Pose"))
{
script.StoreDefaultPose();
serializedObject.ApplyModifiedProperties();
EditorUtility.SetDirty(script.defaultPose);
AssetDatabase.SaveAssets();
AssetDatabase.Refresh();
}
if (script.defaultPose.poseStored && script.defaultPose.localPositions.Length == script.bones.Length)
{
if (GUILayout.Button("Reset To Default Pose"))
{
script.defaultPose.Restore(script.bones);
EditorSceneManager.MarkSceneDirty(EditorSceneManager.GetActiveScene());
}
}
}
EditorGUILayout.Space();
if (script.defaultPose != null && script.defaultPose.poseStored && script.ik != null)
{
if (!script.ik.GetIKSolver().executedInEditor)
{
bool isValid = script.ik.GetIKSolver().IsValid();
EditorGUI.BeginDisabledGroup(!isValid);
if (GUILayout.Button(isValid? "Start Solver": "'Start Solver' disabled for invalid solver setup"))
{
bool initiated = script.Initiate();
serializedObject.ApplyModifiedProperties();
EditorUtility.SetDirty(script.defaultPose);
AssetDatabase.SaveAssets();
AssetDatabase.Refresh();
var ikS = new SerializedObject(script.ik);
ikS.FindProperty("solver").FindPropertyRelative("executedInEditor").boolValue = initiated;
ikS.ApplyModifiedProperties();
script.Update();
EditorSceneManager.MarkSceneDirty(EditorSceneManager.GetActiveScene());
}
EditorGUI.EndDisabledGroup();
}
if (script.ik.GetIKSolver().executedInEditor)
{
if (GUILayout.Button("Stop"))
{
var ikS = new SerializedObject(script.ik);
ikS.FindProperty("solver").FindPropertyRelative("executedInEditor").boolValue = false;
ikS.ApplyModifiedProperties();
}
}
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 4bdb775e141709e40972e0ed29aecc04
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,38 @@
using UnityEditor;
using UnityEngine;
using System.Collections;
namespace RootMotion.FinalIK {
/*
* Custom inspector for FABRIK.
* */
[CustomEditor(typeof(FABRIK))]
public class FABRIKInspector : IKInspector {
private FABRIK script { get { return target as FABRIK; }}
protected override MonoBehaviour GetMonoBehaviour(out int executionOrder) {
executionOrder = 9997;
return script;
}
protected override void OnApplyModifiedProperties() {
if (!Application.isPlaying) script.solver.Initiate(script.transform);
}
protected override void AddInspector() {
// Draw the inspector for IKSolverFABRIK
IKSolverHeuristicInspector.AddInspector(solver, !Application.isPlaying, false);
// Warning box
string message = string.Empty;
if (!script.solver.IsValid(ref message)) AddWarningBox(message);
}
void OnSceneGUI() {
// Draw the scene veiw helpers
IKSolverHeuristicInspector.AddScene(script.solver, Color.cyan, true);
}
}
}

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 35028d751824a4378ab31047db78a4ac
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,35 @@
using UnityEditor;
using UnityEngine;
using System.Collections;
namespace RootMotion.FinalIK {
/*
* Custom inspector for FABRIKRoot.
* */
[CustomEditor(typeof(FABRIKRoot))]
public class FABRIKRootInspector : IKInspector {
private FABRIKRoot script { get { return target as FABRIKRoot; }}
private FABRIKChain selectedChain;
protected override MonoBehaviour GetMonoBehaviour(out int executionOrder) {
executionOrder = 9997;
return script;
}
protected override void AddInspector() {
// Draw the inspector for IKSolverFABRIKRoot
IKSolverFABRIKRootInspector.AddInspector(solver, !Application.isPlaying);
// Warning box
string message = string.Empty;
if (!script.solver.IsValid(ref message)) AddWarningBox(message);
}
void OnSceneGUI() {
// Draw the scene veiw helpers
IKSolverFABRIKRootInspector.AddScene(script.solver, Color.cyan, true, ref selectedChain);
}
}
}

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 97f4f303b23be42ddabd838850dd9c03
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,99 @@
using UnityEngine;
using System.Collections;
using UnityEditor;
namespace RootMotion.FinalIK {
// Custom Scene View handles for the FingerRig.
[CustomEditor(typeof(FingerRig))]
public class FingerRigInspector : Editor {
private FingerRig script { get { return target as FingerRig; }}
private int selected = -1;
private MonoScript monoScript;
void OnEnable() {
if (serializedObject == null) return;
// Changing the script execution order
if (!Application.isPlaying) {
monoScript = MonoScript.FromMonoBehaviour(script);
int currentExecutionOrder = MonoImporter.GetExecutionOrder(monoScript);
if (currentExecutionOrder != 10000) MonoImporter.SetExecutionOrder(monoScript, 10000);
}
}
void OnSceneGUI() {
if (!script.enabled) return;
string message = string.Empty;
if (!script.IsValid(ref message)) return;
if (Application.isPlaying && !script.initiated) return;
Color color = Color.cyan;
color.a = script.weight;
Handles.color = color;
GUI.color = color;
// Display the bones
if (!Application.isPlaying) {
for (int i = 0; i < script.fingers.Length; i++) {
Handles.DrawLine(script.fingers[i].bone1.position, script.fingers[i].bone2.position);
Inspector.SphereCap(0, script.fingers[i].bone1.position, Quaternion.identity, IKSolverInspector.GetHandleSize(script.fingers[i].bone1.position) * 0.5f);
Inspector.SphereCap(0, script.fingers[i].bone2.position, Quaternion.identity, IKSolverInspector.GetHandleSize(script.fingers[i].bone2.position) * 0.5f);
if (script.fingers[i].bone3 != null) {
Handles.DrawLine(script.fingers[i].bone2.position, script.fingers[i].bone3.position);
Handles.DrawLine(script.fingers[i].bone3.position, script.fingers[i].tip.position);
Inspector.SphereCap(0, script.fingers[i].bone3.position, Quaternion.identity, IKSolverInspector.GetHandleSize(script.fingers[i].bone3.position) * 0.5f);
} else {
Handles.DrawLine(script.fingers[i].bone2.position, script.fingers[i].tip.position);
}
Inspector.SphereCap(0, script.fingers[i].tip.position, Quaternion.identity, IKSolverInspector.GetHandleSize(script.fingers[i].tip.position) * 0.5f);
}
}
// Selecting solvers
if (Application.isPlaying) {
if (selected >= 0 && selected < script.fingers.Length) {
if (script.fingers[selected].weight > 0f) {
color.a = script.weight * script.fingers[selected].weight;
Handles.color = color;
float size = IKSolverInspector.GetHandleSize(script.fingers[selected].IKPosition);
Inspector.CubeCap(0, script.fingers[selected].IKPosition, script.fingers[selected].IKRotation, size);
if (script.fingers[selected].target == null) {
switch(Tools.current) {
case Tool.Move:
script.fingers[selected].IKPosition = Handles.PositionHandle(script.fingers[selected].IKPosition, Tools.pivotRotation == PivotRotation.Local? script.fingers[selected].IKRotation: Quaternion.identity);
break;
case Tool.Rotate:
script.fingers[selected].IKRotation = Handles.RotationHandle(script.fingers[selected].IKRotation, script.fingers[selected].IKPosition);
break;
}
}
}
}
for (int i = 0; i < script.fingers.Length; i++) {
color.a = script.weight * script.fingers[i].weight;
Handles.color = color;
Handles.DrawLine(script.fingers[i].tip.position, script.fingers[i].IKPosition);
if (script.fingers[i].weight > 0 && selected != i && script.fingers[i].initiated) {
float size = IKSolverInspector.GetHandleSize(script.fingers[i].IKPosition) * 0.5f;
if (Inspector.DotButton(script.fingers[i].IKPosition, Quaternion.identity, size, size)) selected = i;
}
}
}
Handles.color = Color.white;
GUI.color = Color.white;
}
}
}

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: aa6fa0b5b780d4401b031336dd86cfa4
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,107 @@
using UnityEditor;
using UnityEngine;
using System.Collections;
namespace RootMotion.FinalIK {
/*
* Custom inspector for FullBodyBipedIK.
* */
[CustomEditor(typeof(FullBodyBipedIK))]
public class FullBodyBipedIKInspector : IKInspector {
private FullBodyBipedIK script { get { return target as FullBodyBipedIK; }}
private int selectedEffector;
private SerializedProperty references;
private bool autodetected;
private static Color color {
get {
return new Color(0f, 0.75f, 1f);
}
}
protected override MonoBehaviour GetMonoBehaviour(out int executionOrder) {
executionOrder = 9999;
return script;
}
protected override void OnEnableVirtual() {
references = serializedObject.FindProperty("references");
// Autodetecting References
if (script.references.IsEmpty(false) && script.enabled) {
BipedReferences.AutoDetectReferences(ref script.references, script.transform, new BipedReferences.AutoDetectParams(true, false));
script.solver.rootNode = IKSolverFullBodyBiped.DetectRootNodeBone(script.references);
Initiate();
if (Application.isPlaying) Warning.Log("Biped references were auto-detected on a FullBodyBipedIK component that was added in runtime. Note that this only happens in the Editor and if the GameObject is selected (for quick and convenient debugging). If you want to add FullBodyBipedIK dynamically in runtime via script, you will have to use BipedReferences.AutodetectReferences() for automatic biped detection.", script.transform);
references.isExpanded = !script.references.isFilled;
}
}
protected override void AddInspector() {
// While in editor
if (!Application.isPlaying) {
// Editing References, if they have changed, reinitiate.
if (BipedReferencesInspector.AddModifiedInspector(references)) {
Initiate();
return; // Don't draw immediatelly to avoid errors
}
// Root Node
IKSolverFullBodyBipedInspector.AddReferences(true, solver);
// Reinitiate if rootNode has changed
if (serializedObject.ApplyModifiedProperties()) {
Initiate();
return; // Don't draw immediatelly to avoid errors
}
} else {
// While in play mode
// Draw the references and the root node for UMA
BipedReferencesInspector.AddModifiedInspector(references);
IKSolverFullBodyBipedInspector.AddReferences(true, solver);
}
string errorMessage = string.Empty;
if (script.ReferencesError(ref errorMessage) || !script.solver.IsValid(ref errorMessage)) {
AddWarningBox(errorMessage);
Warning.Log(errorMessage, script.transform, false);
} else {
// Draw the inspector for IKSolverFullBody
IKSolverFullBodyBipedInspector.AddInspector(solver, false);
}
EditorGUILayout.Space();
}
private void Initiate() {
Warning.logged = false;
// Check for possible errors, if found, do not initiate
string message = "";
if (script.ReferencesError(ref message)) {
Warning.Log(message, script.transform, false);
return;
}
// Notify of possible problems, but still initiate
if (script.ReferencesWarning(ref message)) Warning.Log(message, script.transform, false);
// Initiate
script.solver.SetToReferences(script.references, script.solver.rootNode);
}
// Draw the scene view handles
void OnSceneGUI() {
// Draw the scene veiw helpers
if (!script.references.isFilled) return;
IKSolverFullBodyBipedInspector.AddScene(target, script.solver, color, ref selectedEffector, script.transform);
}
}
}

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: a1af94c10682a46c0849b487ad86dd40
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,13 @@
using UnityEngine;
using UnityEditor;
using System.Collections;
namespace RootMotion.FinalIK {
public class GroundingInspector : Editor {
public static void Visualize(Grounding grounding, Transform root, Transform foot) {
Inspector.SphereCap (0, foot.position + root.forward * grounding.footCenterOffset, root.rotation, grounding.footRadius * 2f);
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 43cffbb650ededd4bbfb46bf19a74782
timeCreated: 1487065127
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,106 @@
using UnityEngine;
using UnityEditor;
using System.Collections;
namespace RootMotion.FinalIK {
/*
* Custom inspector and scene view tools for IKEffector
* */
public class IKEffectorInspector: IKSolverInspector {
#region Public methods
public static void DrawArrayElementEffector(SerializedProperty effector, bool editHierarchy) {
if (!editHierarchy) return;
if (effector.FindPropertyRelative("bones").arraySize > 1) {
GUILayout.BeginHorizontal();
GUILayout.Space(indent);
AddClampedFloat(effector.FindPropertyRelative("falloff"), new GUIContent("Distance Falloff", string.Empty), 0f, Mathf.Infinity);
GUILayout.EndHorizontal();
}
AddArray(effector.FindPropertyRelative("bones"), new GUIContent("Bones", string.Empty), editHierarchy, false, null, OnAddToArrayBone, DrawArrayElementLabelBone, false);
if (effector.isExpanded) EditorGUILayout.Space();
}
public static void OnAddToArrayEffector(SerializedProperty effector) {
effector.FindPropertyRelative("positionWeight").floatValue = 0f;
effector.FindPropertyRelative("rotationWeight").floatValue = 0f;
effector.FindPropertyRelative("falloff").floatValue = 0.5f;
effector.FindPropertyRelative("position").vector3Value = Vector3.zero;
effector.FindPropertyRelative("positionOffset").vector3Value = Vector3.zero;
}
public static void DrawArrayElementLabelEffector(SerializedProperty effector, bool editHierarchy) {
GUILayout.Space(Inspector.indent);
if (editHierarchy) {
EditorGUILayout.PropertyField(effector, new GUIContent(GetArrayName(effector.FindPropertyRelative("bones"), "Effector"), string.Empty), false, GUILayout.Width(100));
} else {
EditorGUILayout.LabelField(new GUIContent(GetArrayName(effector.FindPropertyRelative("bones"), "Effector"), string.Empty), GUILayout.Width(100));
}
GUILayout.Space(10);
GUILayout.Label("Position", GUILayout.Width(50));
effector.FindPropertyRelative("positionWeight").floatValue = GUILayout.HorizontalSlider(effector.FindPropertyRelative("positionWeight").floatValue, 0f, 1f, GUILayout.Width(50));
GUILayout.Space(5);
GUILayout.Label("Rotation", GUILayout.Width(50));
effector.FindPropertyRelative("rotationWeight").floatValue = GUILayout.HorizontalSlider(effector.FindPropertyRelative("rotationWeight").floatValue, 0f, 1f, GUILayout.Width(50));
if (!editHierarchy && effector.FindPropertyRelative("bones").arraySize > 1) {
EditorGUILayout.LabelField(new GUIContent("Falloff", string.Empty), GUILayout.Width(50));
EditorGUILayout.PropertyField(effector.FindPropertyRelative("falloff"), GUIContent.none);
effector.FindPropertyRelative("falloff").floatValue = Mathf.Clamp(effector.FindPropertyRelative("falloff").floatValue, 0f, Mathf.Infinity);
}
}
public static void AddScene(IKEffector e, Color color, bool modifiable, float size) {
if (!modifiable) return;
// Draw effectors
bool rotate = e.isEndEffector;
float weight = rotate? Mathf.Max(e.positionWeight, e.rotationWeight): e.positionWeight;
if (e.bone != null && weight > 0) {
//if (Application.isPlaying) {
Handles.color = new Color(color.r, color.g, color.b, weight);
Handles.DrawLine(e.position, e.bone.position);
Inspector.SphereCap(0, e.bone.position, Quaternion.identity, size * 0.5f);
// Manipulating position and rotation
if (e.target == null) {
switch(Tools.current) {
case Tool.Move:
e.position = Handles.PositionHandle(e.position, Quaternion.identity);
break;
case Tool.Rotate:
if (rotate) e.rotation = Handles.RotationHandle(e.rotation, e.position);
break;
}
}
if (rotate) Inspector.CubeCap(0, e.position, e.rotation, size);
else Inspector.SphereCap(0, e.position, Quaternion.identity, size);
//}
}
}
#endregion Public methods
private static void DrawArrayElementLabelBone(SerializedProperty bone, bool editHierarchy) {
AddObjectReference(bone, GUIContent.none, editHierarchy, 0, 300);
}
private static void OnAddToArrayBone(SerializedProperty bone) {
bone.objectReferenceValue = null;
}
}
}

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: f11a75612fdb244758156ae2d26a95ec
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,27 @@
using UnityEngine;
using UnityEditor;
using System.Collections;
namespace RootMotion.FinalIK {
// Custom inspector for IKExecutionOrder
[CustomEditor(typeof(IKExecutionOrder))]
public class IKExecutionOrderInspector : Editor {
private IKExecutionOrder script { get { return target as IKExecutionOrder; }}
private MonoScript monoScript;
void OnEnable() {
if (serializedObject == null) return;
// Changing the script execution order
if (!Application.isPlaying) {
int executionOrder = 9996;
monoScript = MonoScript.FromMonoBehaviour(script);
int currentExecutionOrder = MonoImporter.GetExecutionOrder(monoScript);
if (currentExecutionOrder != executionOrder) MonoImporter.SetExecutionOrder(monoScript, executionOrder);
}
}
}
}

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: e2d73247f9c4b4190a30f8e4cc054bc5
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,67 @@
using UnityEditor;
using UnityEngine;
using System.Collections;
namespace RootMotion.FinalIK {
/*
* Base abstract class for IK component inspectors.
* */
public abstract class IKInspector : Editor {
protected abstract void AddInspector();
protected abstract MonoBehaviour GetMonoBehaviour(out int executionOrder);
protected SerializedProperty solver;
protected SerializedContent fixTransforms;
protected SerializedContent[] content;
protected virtual void OnApplyModifiedProperties() {}
protected virtual void OnEnableVirtual() {}
private MonoScript monoScript;
void OnEnable() {
if (serializedObject == null) return;
// Changing the script execution order
if (!Application.isPlaying) {
int executionOrder = 0;
monoScript = MonoScript.FromMonoBehaviour(GetMonoBehaviour(out executionOrder));
int currentExecutionOrder = MonoImporter.GetExecutionOrder(monoScript);
if (currentExecutionOrder != executionOrder) MonoImporter.SetExecutionOrder(monoScript, executionOrder);
}
solver = serializedObject.FindProperty("solver");
fixTransforms = new SerializedContent(serializedObject.FindProperty("fixTransforms"), new GUIContent("Fix Transforms", "If true, will fix all the Transforms used by the solver to their initial state in each Update. This prevents potential problems with unanimated bones and animator culling with a small cost of performance. Not recommended for CCD and FABRIK solvers."));
OnEnableVirtual();
}
// Override the default warning box
protected virtual void AddWarningBox(string message) {
EditorGUILayout.Space();
EditorGUILayout.LabelField("Invalid/incomplete setup, can not initiate the solver. " + message, EditorStyles.helpBox);
EditorGUILayout.Space();
}
#region Inspector
public override void OnInspectorGUI() {
if (serializedObject == null) return;
serializedObject.Update();
Inspector.AddContent(fixTransforms);
AddInspector();
if (serializedObject.ApplyModifiedProperties()) {
OnApplyModifiedProperties();
}
}
#endregion Inspector
}
}

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 00e26cb6b10c641c49833ea4316e25cf
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,103 @@
using UnityEngine;
using UnityEditor;
using System.Collections;
using System;
namespace RootMotion.FinalIK {
/*
* Custom inspector and scene view tools for IKSolverAim
* */
public class IKSolverAimInspector: IKSolverInspector {
#region Public methods
/// <summary>
/// Draws the custom inspector for IKSolverAim
/// </summary>
public static void AddInspector(SerializedProperty prop, bool editHierarchy) {
IKSolverHeuristicInspector.AddTarget(prop);
if (!prop.FindPropertyRelative("XY").boolValue) EditorGUILayout.PropertyField(prop.FindPropertyRelative("poleTarget"), new GUIContent("Pole Target", "If assigned, will automatically set polePosition to the position of this Transform."));
EditorGUILayout.PropertyField(prop.FindPropertyRelative("transform"), new GUIContent("Aim Transform", "The transform that you want to be aimed at the target. Needs to be a lineal descendant of the bone hierarchy. For example, if you wish to aim a gun, it should be the gun, one of its children or the hand bone."));
EditorGUILayout.PropertyField(prop.FindPropertyRelative("axis"), new GUIContent("Axis", "The local axis of the Transform that you want to be aimed at IKPosition."));
if (!prop.FindPropertyRelative("XY").boolValue) EditorGUILayout.PropertyField(prop.FindPropertyRelative("poleAxis"), new GUIContent("Pole Axis", "Keeps that axis of the Aim Transform directed at the polePosition."));
EditorGUILayout.Space();
IKSolverHeuristicInspector.AddIKPositionWeight(prop);
if (!prop.FindPropertyRelative("XY").boolValue) EditorGUILayout.PropertyField(prop.FindPropertyRelative("poleWeight"), new GUIContent("Pole Weight", "The weight of the Pole."));
IKSolverHeuristicInspector.AddProps(prop);
EditorGUILayout.PropertyField(prop.FindPropertyRelative("clampWeight"), new GUIContent("Clamp Weight", "Clamping rotation of the solver. 0 is free rotation, 1 is completely clamped to transform axis."));
EditorGUILayout.PropertyField(prop.FindPropertyRelative("clampSmoothing"), new GUIContent("Clamp Smoothing", "Number of sine smoothing iterations applied on clamping to make the clamping point smoother."));
IKSolverHeuristicInspector.AddBones(prop, editHierarchy, true);
}
/// <summary>
/// Draws the scene view helpers for IKSolverAim
/// </summary>
public static void AddScene(IKSolverAim solver, Color color, bool modifiable) {
// Protect from null reference errors
if (solver.transform == null) return;
if (Application.isPlaying && !solver.initiated) return;
if (!Application.isPlaying) {
string message = string.Empty;
if (!solver.IsValid(ref message)) return;
}
Handles.color = color;
GUI.color = color;
// Display the bones
for (int i = 0; i < solver.bones.Length; i++) {
IKSolver.Bone bone = solver.bones[i];
if (i < solver.bones.Length - 1) Handles.DrawLine(bone.transform.position, solver.bones[i + 1].transform.position);
Inspector.SphereCap(0, solver.bones[i].transform.position, Quaternion.identity, GetHandleSize(solver.bones[i].transform.position));
}
if (solver.axis != Vector3.zero) Inspector.ConeCap(0, solver.transform.position, Quaternion.LookRotation(solver.transform.rotation * solver.axis), GetHandleSize(solver.transform.position) * 2f);
// Selecting joint and manipulating IKPosition
if (Application.isPlaying && solver.IKPositionWeight > 0) {
if (modifiable) {
Inspector.SphereCap(0, solver.IKPosition, Quaternion.identity, GetHandleSize(solver.IKPosition));
// Manipulating position
solver.IKPosition = Handles.PositionHandle(solver.IKPosition, Quaternion.identity);
}
// Draw a transparent line from transform to IKPosition
Handles.color = new Color(color.r, color.g, color.b, color.a * solver.IKPositionWeight);
Handles.DrawLine(solver.bones[solver.bones.Length - 1].transform.position, solver.transform.position);
Handles.DrawLine(solver.transform.position, solver.IKPosition);
}
Handles.color = color;
// Pole
if (Application.isPlaying && solver.poleWeight > 0f) {
if (modifiable) {
Inspector.SphereCap(0, solver.polePosition, Quaternion.identity, GetHandleSize(solver.IKPosition) * 0.5f);
// Manipulating position
solver.polePosition = Handles.PositionHandle(solver.polePosition, Quaternion.identity);
}
// Draw a transparent line from transform to polePosition
Handles.color = new Color(color.r, color.g, color.b, color.a * solver.poleWeight);
Handles.DrawLine(solver.transform.position, solver.polePosition);
}
Handles.color = Color.white;
GUI.color = Color.white;
}
#endregion Public methods
}
}

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 13082609a38964d0486119efce14e42c
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,110 @@
using UnityEngine;
using UnityEditor;
using System.Collections;
namespace RootMotion.FinalIK {
/*
* Custom inspector and scene view tools for IKSolverArm
* */
public class IKSolverArmInspector: IKSolverInspector {
#region Public methods
/*
* Draws the custom inspector for IKSolverTrigonometric
* */
public static void AddInspector(SerializedProperty prop, bool editHierarchy, bool showReferences) {
EditorGUI.indentLevel = 0;
// Bone references
if (showReferences) {
EditorGUILayout.Space();
AddObjectReference(prop.FindPropertyRelative("chest.transform"), new GUIContent("Chest", "The last spine bone."), editHierarchy, 100);
AddObjectReference(prop.FindPropertyRelative("shoulder.transform"), new GUIContent("Shoulder", "The shoulder (clavicle) bone."), editHierarchy, 100);
AddObjectReference(prop.FindPropertyRelative("upperArm.transform"), new GUIContent("Upper Arm", "The upper arm bone."), editHierarchy, 100);
AddObjectReference(prop.FindPropertyRelative("forearm.transform"), new GUIContent("Forearm", "The forearm bone."), editHierarchy, 100);
AddObjectReference(prop.FindPropertyRelative("hand.transform"), new GUIContent("Hand", "The hand bone."), editHierarchy, 100);
EditorGUILayout.Space();
}
// Hand
EditorGUILayout.PropertyField(prop.FindPropertyRelative("isLeft"), new GUIContent("Is Left", "Check this if this is the left arm, uncheck if right."));
EditorGUILayout.PropertyField(prop.FindPropertyRelative("arm.target"), new GUIContent("Target", "The target Transform. Solver IKPosition will be automatically set to the position of the target."));
EditorGUILayout.PropertyField(prop.FindPropertyRelative("IKPositionWeight"), new GUIContent("Position Weight", "Solver weight for smooth blending."));
EditorGUILayout.PropertyField(prop.FindPropertyRelative("IKRotationWeight"), new GUIContent("Rotation Weight", "Weight of last bone's rotation to IKRotation."));
// Shoulder
EditorGUILayout.PropertyField(prop.FindPropertyRelative("arm.shoulderRotationMode"), new GUIContent("Shoulder Rotation Mode", " Different techniques for shoulder bone rotation."));
EditorGUILayout.PropertyField(prop.FindPropertyRelative("arm.shoulderRotationWeight"), new GUIContent("Shoulder Rotation Weight", " The weight of shoulder rotation."));
EditorGUILayout.PropertyField(prop.FindPropertyRelative("arm.shoulderTwistWeight"), new GUIContent("Shoulder Twist Weight", " The weight of twisting the shoulders backwards when arms are lifted up."));
EditorGUILayout.PropertyField(prop.FindPropertyRelative("arm.shoulderYawOffset"), new GUIContent("Shoulder Yaw Offset", " Tweak this value to adjust shoulder rotation around the yaw (up) axis."));
EditorGUILayout.PropertyField(prop.FindPropertyRelative("arm.shoulderPitchOffset"), new GUIContent("Shoulder Pitch Offset", " Tweak this value to adjust shoulder rotation around the pitch (forward) axis."));
// Bending
EditorGUILayout.PropertyField(prop.FindPropertyRelative("arm.bendGoal"), new GUIContent("Bend Goal", "If assigned, the knee will be bent in the direction towards this transform."));
EditorGUILayout.PropertyField(prop.FindPropertyRelative("arm.bendGoalWeight"), new GUIContent("Bend Goal Weight", "Weight of the bend goal."));
EditorGUILayout.PropertyField(prop.FindPropertyRelative("arm.swivelOffset"), new GUIContent("Swivel Offset", "Angular offset of the arm's bending direction."));
EditorGUILayout.PropertyField(prop.FindPropertyRelative("arm.wristToPalmAxis"), new GUIContent("Wrist To Palm Axis", "Local axis of the hand bone that points from the wrist towards the palm. Used for defining hand bone orientation."));
EditorGUILayout.PropertyField(prop.FindPropertyRelative("arm.palmToThumbAxis"), new GUIContent("Palm To Thumb Axis", "Local axis of the hand bone that points from the palm towards the thumb. Used for defining hand bone orientation."));
// Stretching
EditorGUILayout.PropertyField(prop.FindPropertyRelative("arm.armLengthMlp"), new GUIContent("Arm Length Mlp", "Use this to make the arm shorter/longer."));
EditorGUILayout.PropertyField(prop.FindPropertyRelative("arm.stretchCurve"), new GUIContent("Stretch Curve", "Evaluates stretching of the arm by target distance relative to arm length. Value at time 1 represents stretching amount at the point where distance to the target is equal to arm length. Value at time 2 represents stretching amount at the point where distance to the target is double the arm length. Value represents the amount of stretching. Linear stretching would be achieved with a linear curve going up by 45 degrees. Increase the range of stretching by moving the last key up and right at the same amount. Smoothing in the curve can help reduce elbow snapping (start stretching the arm slightly before target distance reaches arm length)."));
}
/*
* Draws the scene view helpers for IKSolverTrigonometric
* */
public static void AddScene(IKSolverArm solver, Color color, bool modifiable) {
if (Application.isPlaying && !solver.initiated) return;
if (!Application.isPlaying && !solver.IsValid()) return;
//float length = Vector3.Distance(solver.bone1.transform.position, solver.bone2.transform.position) + Vector3.Distance(solver.bone2.transform.position, solver.bone3.transform.position);
//float size = length * 0.05f;
Handles.color = color;
GUI.color = color;
// Chain lines
Handles.DrawLine(solver.chest.transform.position, solver.shoulder.transform.position);
Handles.DrawLine(solver.shoulder.transform.position, solver.upperArm.transform.position);
Handles.DrawLine(solver.upperArm.transform.position, solver.forearm.transform.position);
Handles.DrawLine(solver.forearm.transform.position, solver.hand.transform.position);
// Joints
Inspector.SphereCap(0, solver.chest.transform.position, Quaternion.identity, GetHandleSize(solver.chest.transform.position));
Inspector.SphereCap(0, solver.shoulder.transform.position, Quaternion.identity, GetHandleSize(solver.shoulder.transform.position));
Inspector.SphereCap(0, solver.upperArm.transform.position, Quaternion.identity, GetHandleSize(solver.upperArm.transform.position));
Inspector.SphereCap(0, solver.forearm.transform.position, Quaternion.identity, GetHandleSize(solver.forearm.transform.position));
Inspector.SphereCap(0, solver.hand.transform.position, Quaternion.identity, GetHandleSize(solver.hand.transform.position));
if (Application.isPlaying && (solver.IKPositionWeight > 0 || solver.IKRotationWeight > 0)) {
if (modifiable) {
Inspector.CubeCap(0, solver.IKPosition, solver.IKRotation, GetHandleSize(solver.IKPosition));
// Manipulating position and rotation
switch(Tools.current) {
case Tool.Move:
if (solver.arm.target == null) solver.IKPosition = Handles.PositionHandle(solver.IKPosition, Quaternion.identity);
break;
case Tool.Rotate:
if (solver.arm.target == null) solver.IKRotation = Handles.RotationHandle(solver.IKRotation, solver.IKPosition);
break;
}
}
// Target
Handles.color = new Color(color.r, color.g, color.b, color.a * Mathf.Max(solver.IKPositionWeight, solver.IKRotationWeight));
Handles.DrawLine(solver.hand.transform.position, solver.IKPosition);
}
Handles.color = Color.white;
GUI.color = Color.white;
}
#endregion Public methods
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 2096c71e8e55def4bafe5d7f1604ea55
timeCreated: 1528379406
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,94 @@
using UnityEngine;
using UnityEditor;
using System.Collections;
namespace RootMotion.FinalIK {
/*
* Custom inspector and scene view tools for IKSolverFABRIKRoot
* */
public class IKSolverFABRIKRootInspector : IKSolverInspector {
#region Public methods
/*
* Draws the custom inspector for IKSolverFABRIKRoot
* */
public static void AddInspector(SerializedProperty prop, bool editHierarchy) {
AddClampedInt(prop.FindPropertyRelative("iterations"), new GUIContent("Iterations", "Solver iterations."), 0, int.MaxValue);
EditorGUILayout.PropertyField(prop.FindPropertyRelative("IKPositionWeight"), new GUIContent("Weight", "Solver weight."));
EditorGUILayout.PropertyField(prop.FindPropertyRelative("rootPin"), new GUIContent("Root Pin", "Weight of keeping all FABRIK Trees pinned to the root position."));
EditorGUILayout.Space();
EditorGUI.indentLevel = 0;
EditorGUILayout.PropertyField(prop.FindPropertyRelative("chains"), new GUIContent("Chains", "FABRIK chains."), true);
EditorGUILayout.Space();
}
/*
* Draws the scene view helpers for IKSolverFABRIKRoot
* */
public static void AddScene(IKSolverFABRIKRoot solver, Color color, bool modifiable, ref FABRIKChain selected) {
// Protect from null reference errors
if (Application.isPlaying && !solver.initiated) return;
if (!Application.isPlaying) {
string message = string.Empty;
if (!solver.IsValid(ref message)) return;
}
Handles.color = color;
// Selecting solvers
if (Application.isPlaying) {
SelectChain(solver.chains, ref selected, color);
}
AddSceneChain(solver.chains, color, selected);
// Root pin
Handles.color = new Color(Mathf.Lerp(1f, color.r, solver.rootPin), Mathf.Lerp(1f, color.g, solver.rootPin), Mathf.Lerp(1f, color.b, solver.rootPin), Mathf.Lerp(0.5f, 1f, solver.rootPin));
if (solver.GetRoot() != null) {
Handles.DrawLine(solver.chains[0].ik.solver.bones[0].transform.position, solver.GetRoot().position);
Inspector.CubeCap(0, solver.GetRoot().position, Quaternion.identity, GetHandleSize(solver.GetRoot().position));
}
}
#endregion Public methods
private static Color col, midColor, endColor;
private static void SelectChain(FABRIKChain[] chain, ref FABRIKChain selected, Color color) {
foreach (FABRIKChain c in chain) {
if (c.ik.solver.IKPositionWeight > 0 && selected != c) {
Handles.color = GetChainColor(c, color);
if (Inspector.DotButton(c.ik.solver.GetIKPosition(), Quaternion.identity, GetHandleSize(c.ik.solver.GetIKPosition()), GetHandleSize(c.ik.solver.GetIKPosition()))) {
selected = c;
return;
}
}
}
}
private static Color GetChainColor(FABRIKChain chain, Color color) {
float midWeight = chain.pin;
midColor = new Color(Mathf.Lerp(1f, color.r, midWeight), Mathf.Lerp(1f, color.g, midWeight), Mathf.Lerp(1f, color.b, midWeight), Mathf.Lerp(0.5f, 1f, midWeight));
float endWeight = chain.pull;
endColor = new Color(Mathf.Lerp(1f, color.r, endWeight), Mathf.Lerp(0f, color.g, endWeight), Mathf.Lerp(0f, color.b, endWeight), Mathf.Lerp(0.5f, 1f, endWeight));
return chain.children.Length == 0? endColor: midColor;
}
private static void AddSceneChain(FABRIKChain[] chain, Color color, FABRIKChain selected) {
foreach (FABRIKChain c in chain) {
col = GetChainColor(c, color);
IKSolverHeuristicInspector.AddScene(c.ik.solver as IKSolverHeuristic, col, selected == c);
}
}
}
}

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 47b6cc68611af428d82361a2eb3d8505
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,339 @@
using UnityEngine;
using UnityEditor;
using System.Collections;
using System;
namespace RootMotion.FinalIK {
// Custom inspector and scene view tools for IKSolverFullBodyBiped
public class IKSolverFullBodyBipedInspector : IKSolverInspector {
#region Public methods
public static void AddReferences(bool editHierarchy, SerializedProperty prop) {
// RootNode
if (editHierarchy) {
EditorGUILayout.PropertyField(prop.FindPropertyRelative("rootNode"), new GUIContent("Root Node", "Select one of the bones in the (lower) spine."));
}
}
// Draws the custom inspector for IKSolverFullBodybiped
public static void AddInspector(SerializedProperty prop, bool editWeights) {
IKSolverFullBodyInspector.AddInspector(prop, editWeights);
EditorGUILayout.Space();
EditorGUI.indentLevel = 0;
AddSolver(prop);
}
// Draws the scene view helpers for IKSolverFullBodyBiped
public static void AddScene(UnityEngine.Object target, IKSolverFullBodyBiped solver, Color color, ref int selectedEffector, Transform root) {
if (Application.isPlaying && !solver.initiated) return;
if (!Application.isPlaying && !solver.IsValid()) return;
bool modifiable = solver.initiated;
float heightF = Vector3.Distance(solver.chain[1].nodes[0].transform.position, solver.chain[1].nodes[1].transform.position) +
Vector3.Distance(solver.chain[3].nodes[0].transform.position, solver.chain[3].nodes[1].transform.position);
float size = Mathf.Clamp(heightF * 0.075f, 0.001f, Mathf.Infinity);
// Bend goals
for (int i = 0; i < solver.chain.Length; i++) {
if (solver.chain[i].nodes.Length == 3 && solver.chain[i].bendConstraint.bendGoal != null && solver.chain[i].bendConstraint.weight > 0f) {
Color c = color;
c.a = solver.chain[i].bendConstraint.weight;
Handles.color = c;
Handles.DrawLine(solver.chain[i].nodes[1].transform.position, solver.chain[i].bendConstraint.bendGoal.position);
Inspector.SphereCap(0, solver.chain[i].nodes[1].transform.position, Quaternion.identity, size * 0.5f);
Inspector.SphereCap(0, solver.chain[i].bendConstraint.bendGoal.position, Quaternion.identity, size * 0.5f);
Handles.color = Color.white;
}
}
// Chain
if (!modifiable) {
for (int i = 0; i < solver.chain.Length; i++) {
IKSolverFullBodyInspector.AddChain(solver.chain, i, color, size);
}
Handles.DrawLine(solver.chain[1].nodes[0].transform.position, solver.chain[2].nodes[0].transform.position);
Handles.DrawLine(solver.chain[3].nodes[0].transform.position, solver.chain[4].nodes[0].transform.position);
AddLimbHelper(solver.chain[1], size);
AddLimbHelper(solver.chain[2], size);
AddLimbHelper(solver.chain[3], size, root);
AddLimbHelper(solver.chain[4], size, root);
}
// Effectors
IKSolverFullBodyInspector.AddScene(target, solver, color, modifiable, ref selectedEffector, size);
}
// Scene view handles to help with limb setup
private static void AddLimbHelper(FBIKChain chain, float size, Transform root = null) {
Vector3 cross = Vector3.Cross((chain.nodes[1].transform.position - chain.nodes[0].transform.position).normalized, (chain.nodes[2].transform.position - chain.nodes[0].transform.position).normalized);
Vector3 bendDirection = -Vector3.Cross(cross.normalized, (chain.nodes[2].transform.position - chain.nodes[0].transform.position).normalized);
if (bendDirection != Vector3.zero) {
Color c = Handles.color;
bool inverted = root != null && Vector3.Dot(root.forward, bendDirection.normalized) < 0f;
// Inverted bend direction
if (inverted) {
GUI.color = new Color(1f, 0.75f, 0.75f);
Handles.color = Color.yellow;
if (Inspector.DotButton(chain.nodes[1].transform.position, Quaternion.identity, size * 0.5f, size)) {
Warning.logged = false;
Warning.Log("The bend direction of this limb appears to be inverted. Please rotate this bone so that the limb is bent in its natural bending direction. If this limb is supposed to be bent in the direction pointed by the arrow, ignore this warning.", root, true);
}
}
Inspector.ArrowCap(0, chain.nodes[1].transform.position, Quaternion.LookRotation(bendDirection), size * 2f);
GUI.color = Color.white;
Handles.color = c;
} else {
// The limb is completely stretched out
Color c = Handles.color;
Handles.color = Color.red;
GUI.color = new Color(1f, 0.75f, 0.75f);
if (Inspector.DotButton(chain.nodes[1].transform.position, Quaternion.identity, size * 0.5f, size)) {
Warning.logged = false;
Warning.Log("The limb is completely stretched out. Full Body Biped IK does not know which way the limb should be bent. Please rotate this bone slightly in its bending direction.", root, true);
}
GUI.color = Color.white;
Handles.color = c;
}
}
#endregion Public methods
private const string style = "Box";
private static void AddProperty(SerializedProperty prop, GUIContent guiContent) {
GUILayout.BeginHorizontal();
GUILayout.Space(50);
EditorGUILayout.PropertyField(prop, guiContent);
GUILayout.Space(20);
GUILayout.EndHorizontal();
}
private static void AddSolver(SerializedProperty prop) {
var chains = prop.FindPropertyRelative("chain");
AddBody(prop, chains.GetArrayElementAtIndex(0), new GUIContent("Body", string.Empty));
AddLimb(prop, chains.GetArrayElementAtIndex(1), FullBodyBipedChain.LeftArm, new GUIContent("Left Arm", string.Empty));
AddLimb(prop, chains.GetArrayElementAtIndex(2), FullBodyBipedChain.RightArm, new GUIContent("Right Arm", string.Empty));
AddLimb(prop, chains.GetArrayElementAtIndex(3), FullBodyBipedChain.LeftLeg, new GUIContent("Left Leg", string.Empty));
AddLimb(prop, chains.GetArrayElementAtIndex(4), FullBodyBipedChain.RightLeg, new GUIContent("Right Leg", string.Empty));
}
private static void AddBody(SerializedProperty prop, SerializedProperty chain, GUIContent guiContent) {
EditorGUILayout.PropertyField(chain, guiContent, false);
GUILayout.BeginHorizontal();
GUILayout.Space(10);
GUILayout.BeginVertical();
if (chain.isExpanded) {
var effectors = prop.FindPropertyRelative("effectors");
var effector = effectors.GetArrayElementAtIndex(0);
var spineMapping = prop.FindPropertyRelative("spineMapping");
var headMapping = prop.FindPropertyRelative("boneMappings").GetArrayElementAtIndex(0);
GUILayout.BeginVertical(style);
DrawLabel("Body Effector", startEffectorIcon);
AddProperty(effector.FindPropertyRelative("target"), new GUIContent("Target", "Target Transform (optional, you can also use bodyEffector.position and bodyEffector.rotation directly)."));
AddProperty(effector.FindPropertyRelative("positionWeight"), new GUIContent("Position Weight", "The weight of pinning the effector bone to the effector position."));
AddProperty(effector.FindPropertyRelative("effectChildNodes"), new GUIContent("Use Thighs", "If true, the effect of the body effector will be applied to also the thigh effectors (IKEffector.effectChildNodes)."));
DrawLabel("Chain", null);
// Spine stiffness
AddProperty(prop.FindPropertyRelative("spineStiffness"), new GUIContent("Spine Stiffness", "The bend resistance of the spine."));
// Pull Body
AddProperty(prop.FindPropertyRelative("pullBodyVertical"), new GUIContent("Pull Body Vertical", "Weight of hand effectors pulling the body vertically."));
AddProperty(prop.FindPropertyRelative("pullBodyHorizontal"), new GUIContent("Pull Body Horizontal", "Weight of hand effectors pulling the body horizontally."));
DrawLabel("Mapping", null);
AddProperty(spineMapping.FindPropertyRelative("iterations"), new GUIContent("Spine Iterations", "The number of FABRIK iterations for mapping the spine bones to the solver armature."));
AddProperty(spineMapping.FindPropertyRelative("twistWeight"), new GUIContent("Spine Twist Weight", "The weight of spine twist."));
AddProperty(headMapping.FindPropertyRelative("maintainRotationWeight"), new GUIContent("Maintain Head Rot", "The weight of maintaining the bone's animated rotation in world space."));
GUILayout.Space(5);
GUILayout.EndVertical();
}
GUILayout.EndVertical();
GUILayout.EndHorizontal();
}
private static void AddLimb(SerializedProperty prop, SerializedProperty chain, FullBodyBipedChain chainType, GUIContent guiContent) {
EditorGUILayout.PropertyField(chain, guiContent, false);
GUILayout.BeginHorizontal();
GUILayout.Space(10);
GUILayout.BeginVertical();
if (chain.isExpanded) {
var effectors = prop.FindPropertyRelative("effectors");
var endEffector = effectors.GetArrayElementAtIndex(GetEndEffectorIndex(chainType));
var startEffector = effectors.GetArrayElementAtIndex(GetStartEffectorIndex(chainType));
var mapping = prop.FindPropertyRelative("limbMappings").GetArrayElementAtIndex(GetLimbMappingIndex(chainType));
GUILayout.BeginVertical(style);
DrawLabel(GetEndEffectorName(chainType), endEffectorIcon);
AddProperty(endEffector.FindPropertyRelative("target"), new GUIContent("Target", "Target Transform (optional, you can also use IKEffector.position and IKEffector.rotation directly)."));
AddProperty(endEffector.FindPropertyRelative("positionWeight"), new GUIContent("Position Weight", "The weight of pinning the effector bone to the effector position."));
AddProperty(endEffector.FindPropertyRelative("rotationWeight"), new GUIContent("Rotation Weight", "The weight of pinning the effector bone to the effector rotation."));
AddProperty(endEffector.FindPropertyRelative("maintainRelativePositionWeight"), new GUIContent("Maintain Relative Pos", "Maintains the position of the hand/foot fixed relative to the chest/hips while effector positionWeight is not weighed in."));
DrawLabel(GetStartEffectorName(chainType), startEffectorIcon);
AddProperty(startEffector.FindPropertyRelative("target"), new GUIContent("Target", "Target Transform (optional, you can also use IKEffector.position and IKEffector.rotation directly)."));
AddProperty(startEffector.FindPropertyRelative("positionWeight"), new GUIContent("Position Weight", "The weight of pinning the effector bone to the effector position."));
DrawLabel("Chain", null);
AddProperty(chain.FindPropertyRelative("pull"), new GUIContent("Pull", "The weight of pulling other chains."));
AddProperty(chain.FindPropertyRelative("reach"), new GUIContent("Reach", "Pulls the first node closer to the last node of the chain."));
AddProperty(chain.FindPropertyRelative("push"), new GUIContent("Push", "The weight of the end-effector pushing the first node."));
AddProperty(chain.FindPropertyRelative("pushParent"), new GUIContent("Push Parent", "The amount of push force transferred to the parent (from hand or foot to the body)."));
AddProperty(chain.FindPropertyRelative("reachSmoothing"), new GUIContent("Reach Smoothing", "Smoothing the effect of the Reach with the expense of some accuracy."));
AddProperty(chain.FindPropertyRelative("pushSmoothing"), new GUIContent("Push Smoothing", "Smoothing the effect of the Push."));
AddProperty(chain.FindPropertyRelative("bendConstraint").FindPropertyRelative("bendGoal"), new GUIContent("Bend Goal", "The Transform to bend towards (optional, you can also use ik.leftArmChain.bendConstraint.direction)."));
AddProperty(chain.FindPropertyRelative("bendConstraint").FindPropertyRelative("weight"), new GUIContent("Bend Goal Weight", "The weight of to bending towards the Bend Goal (optional, you can also use ik.leftArmChain.bendConstraint.weight)."));
DrawLabel("Mapping", null);
AddProperty(mapping.FindPropertyRelative("weight"), new GUIContent("Mapping Weight", "The weight of mapping the limb to its IK pose. This can be useful if you want to disable the effect of IK for the limb."));
AddProperty(mapping.FindPropertyRelative("maintainRotationWeight"), new GUIContent(GetEndBoneMappingName(chainType), "The weight of maintaining the bone's animated rotation in world space."));
GUILayout.Space(5);
GUILayout.EndVertical();
}
GUILayout.EndVertical();
GUILayout.EndHorizontal();
}
private static void DrawLabel(string label, Texture2D texture) {
GUILayout.Space(3);
GUILayout.BeginHorizontal();
if (texture != null) {
Rect rect = EditorGUILayout.GetControlRect(GUILayout.Width(16), GUILayout.Height(16));
GUI.DrawTexture(rect, texture);
} else GUILayout.Space(21);
EditorGUILayout.LabelField(new GUIContent(label, string.Empty));
GUILayout.EndHorizontal();
GUILayout.Space(3);
}
private static string GetEndEffectorName(FullBodyBipedChain chain) {
switch(chain) {
case FullBodyBipedChain.LeftArm: return "Left Hand Effector";
case FullBodyBipedChain.RightArm: return "Right Hand Effector";
case FullBodyBipedChain.LeftLeg: return "Left Foot Effector";
case FullBodyBipedChain.RightLeg: return "Right Foot Effector";
default: return string.Empty;
}
}
private static string GetStartEffectorName(FullBodyBipedChain chain) {
switch(chain) {
case FullBodyBipedChain.LeftArm: return "Left Shoulder Effector";
case FullBodyBipedChain.RightArm: return "Right Shoulder Effector";
case FullBodyBipedChain.LeftLeg: return "Left Thigh Effector";
case FullBodyBipedChain.RightLeg: return "Right Thigh Effector";
default: return string.Empty;
}
}
private static string GetEndBoneMappingName(FullBodyBipedChain chain) {
switch(chain) {
case FullBodyBipedChain.LeftArm: return "Maintain Hand Rot";
case FullBodyBipedChain.RightArm: return "Maintain Hand Rot";
case FullBodyBipedChain.LeftLeg: return "Maintain Foot Rot";
case FullBodyBipedChain.RightLeg: return "Maintain Foot Rot";
default: return string.Empty;
}
}
private static int GetEndEffectorIndex(FullBodyBipedChain chainType) {
switch(chainType) {
case FullBodyBipedChain.LeftArm: return 5;
case FullBodyBipedChain.RightArm: return 6;
case FullBodyBipedChain.LeftLeg: return 7;
case FullBodyBipedChain.RightLeg: return 8;
}
return 0;
}
private static int GetStartEffectorIndex(FullBodyBipedChain chainType) {
switch(chainType) {
case FullBodyBipedChain.LeftArm: return 1;
case FullBodyBipedChain.RightArm: return 2;
case FullBodyBipedChain.LeftLeg: return 3;
case FullBodyBipedChain.RightLeg: return 4;
}
return 0;
}
private static int GetLimbMappingIndex(FullBodyBipedChain chainType) {
switch(chainType) {
case FullBodyBipedChain.LeftArm: return 0;
case FullBodyBipedChain.RightArm: return 1;
case FullBodyBipedChain.LeftLeg: return 2;
case FullBodyBipedChain.RightLeg: return 3;
}
return 0;
}
private static Texture2D endEffectorIcon {
get {
if (_endEffectorIcon == null) _endEffectorIcon = (Texture2D)AssetDatabase.LoadAssetAtPath("Assets/RootMotion/FinalIK/Gizmos/EndEffector Icon.png", typeof(Texture2D));
return _endEffectorIcon;
}
}
private static Texture2D _endEffectorIcon;
private static Texture2D startEffectorIcon {
get {
if (_startEffectorIcon == null) _startEffectorIcon = (Texture2D)AssetDatabase.LoadAssetAtPath("Assets/RootMotion/FinalIK/Gizmos/MidEffector Icon.png", typeof(Texture2D));
return _startEffectorIcon;
}
}
private static Texture2D _startEffectorIcon;
private static Texture2D chainIcon {
get {
if (_chainIcon == null) _chainIcon = (Texture2D)AssetDatabase.LoadAssetAtPath("Assets/RootMotion/FinalIK/Gizmos/Chain Icon.png", typeof(Texture2D));
return _chainIcon;
}
}
private static Texture2D _chainIcon;
private static Texture2D mappingIcon {
get {
if (_mappingIcon == null) _mappingIcon = (Texture2D)AssetDatabase.LoadAssetAtPath("Assets/RootMotion/FinalIK/Gizmos/Mapping Icon.png", typeof(Texture2D));
return _mappingIcon;
}
}
private static Texture2D _mappingIcon;
}
}

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 533c5d8f60bd14648a10c7c1ad3f9ee5
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,80 @@
using UnityEngine;
using UnityEditor;
using System.Collections;
using System;
namespace RootMotion.FinalIK {
/*
* Custom inspector and scene view tools for IKSolverFullBody
* */
public class IKSolverFullBodyInspector : IKSolverInspector {
#region Public methods
/*
* Draws the custom inspector for IKSolverFullBody
* */
public static void AddInspector(SerializedProperty prop, bool editWeights) {
EditorGUILayout.PropertyField(prop.FindPropertyRelative("IKPositionWeight"), new GUIContent("Weight", "Solver weight for smooth blending (ik.solver.IKPositionWeight)."));
EditorGUILayout.PropertyField(prop.FindPropertyRelative("iterations"), new GUIContent("Iterations", "Solver iterations per frame."));
}
/*
* Draws the scene view helpers for IKSolverFullBody
* */
public static void AddScene(UnityEngine.Object target, IKSolverFullBody solver, Color color, bool modifiable, ref int selectedEffector, float size) {
if (!modifiable) return;
if (!solver.initiated) return;
if (!Application.isPlaying && !solver.IsValid()) return;
// Effectors
for (int i = 0; i < solver.effectors.Length; i++) {
bool rotate = solver.effectors[i].isEndEffector;
float weight = rotate? Mathf.Max(solver.effectors[i].positionWeight, solver.effectors[i].rotationWeight): solver.effectors[i].positionWeight;
if (weight > 0 && selectedEffector != i) {
Handles.color = color;
if (rotate) {
if (Inspector.DotButton(solver.effectors[i].position, solver.effectors[i].rotation, size * 0.5f, size * 0.5f)) {
selectedEffector = i;
return;
}
} else {
if (Inspector.SphereButton(solver.effectors[i].position, solver.effectors[i].rotation, size, size)) {
selectedEffector = i;
return;
}
}
}
}
for (int i = 0; i < solver.effectors.Length; i++) IKEffectorInspector.AddScene(solver.effectors[i], color, modifiable && i == selectedEffector, size);
if (GUI.changed) EditorUtility.SetDirty(target);
}
#endregion Public methods
public static void AddChain(FBIKChain[] chain, int index, Color color, float size) {
Handles.color = color;
for (int i = 0; i < chain[index].nodes.Length - 1; i++) {
Handles.DrawLine(GetNodePosition(chain[index].nodes[i]), GetNodePosition(chain[index].nodes[i + 1]));
Inspector.SphereCap(0, GetNodePosition(chain[index].nodes[i]), Quaternion.identity, size);
}
Inspector.SphereCap(0, GetNodePosition(chain[index].nodes[chain[index].nodes.Length - 1]), Quaternion.identity, size);
for (int i = 0; i < chain[index].children.Length; i++) {
Handles.DrawLine(GetNodePosition(chain[index].nodes[chain[index].nodes.Length - 1]), GetNodePosition(chain[chain[index].children[i]].nodes[0]));
}
}
private static Vector3 GetNodePosition(IKSolver.Node node) {
if (Application.isPlaying) return node.solverPosition;
return node.transform.position;
}
}
}

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 9a32242b195b44820b383881d973c731
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,104 @@
using UnityEngine;
using UnityEditor;
using System.Collections;
namespace RootMotion.FinalIK {
/*
* Custom inspector and scene view tools for IK solvers extending IKSolverHeuristic
* */
public class IKSolverHeuristicInspector: IKSolverInspector {
#region Public methods
/*
* Draws the custom inspector for IKSolverHeuristic
* */
public static void AddInspector(SerializedProperty prop, bool editHierarchy, bool editWeights) {
AddTarget(prop);
AddIKPositionWeight(prop);
AddProps(prop);
AddBones(prop, editHierarchy, editWeights);
}
public static void AddTarget(SerializedProperty prop) {
EditorGUILayout.PropertyField(prop.FindPropertyRelative("target"), new GUIContent("Target", "The target Transform. Solver IKPosition will be automatically set to the position of the target."));
}
public static void AddIKPositionWeight(SerializedProperty prop) {
EditorGUILayout.PropertyField(prop.FindPropertyRelative("IKPositionWeight"), new GUIContent("Weight", "Solver weight for smooth blending."));
}
public static void AddProps(SerializedProperty prop) {
AddClampedFloat(prop.FindPropertyRelative("tolerance"), new GUIContent("Tolerance", "Minimum offset from last reached position. Will stop solving if offset is less than tolerance. If tolerance is zero, will iterate until maxIterations."));
AddClampedInt(prop.FindPropertyRelative("maxIterations"), new GUIContent("Max Iterations", "Max solver iterations per frame."), 0, int.MaxValue);
}
public static void AddBones(SerializedProperty prop, bool editHierarchy, bool editWeights) {
EditorGUILayout.PropertyField(prop.FindPropertyRelative("useRotationLimits"), new GUIContent("Use Rotation Limits", "If true, rotation limits (if existing) will be applied on each iteration."));
EditorGUILayout.PropertyField(prop.FindPropertyRelative("XY"), new GUIContent("2D", "If true, will solve only in the XY plane."));
EditorGUILayout.Space();
weights = editWeights;
if (editHierarchy || editWeights) {
AddArray(prop.FindPropertyRelative("bones"), new GUIContent("Bones", string.Empty), editHierarchy, false, null, OnAddToArrayBone, DrawArrayElementLabelBone);
}
EditorGUILayout.Space();
}
/*
* Draws the scene view helpers for IKSolverHeuristic
* */
public static void AddScene(IKSolverHeuristic solver, Color color, bool modifiable) {
// Protect from null reference errors
if (Application.isPlaying && !solver.initiated) return;
if (!Application.isPlaying && !solver.IsValid()) return;
Handles.color = color;
GUI.color = color;
// Display the bones
for (int i = 0; i < solver.bones.Length; i++) {
IKSolver.Bone bone = solver.bones[i];
if (i < solver.bones.Length - 1) Handles.DrawLine(bone.transform.position, solver.bones[i + 1].transform.position);
Inspector.SphereCap(0, solver.bones[i].transform.position, Quaternion.identity, GetHandleSize(solver.bones[i].transform.position));
}
// Selecting joint and manipulating IKPosition
if (Application.isPlaying && solver.IKPositionWeight > 0) {
if (modifiable) {
Inspector.CubeCap(0, solver.IKPosition, solver.GetRoot().rotation, GetHandleSize(solver.IKPosition));
// Manipulating position
if (solver.target == null) solver.IKPosition = Handles.PositionHandle(solver.IKPosition, Quaternion.identity);
}
// Draw a transparent line from last bone to IKPosition
Handles.color = new Color(color.r, color.g, color.b, color.a * solver.IKPositionWeight);
Handles.DrawLine(solver.bones[solver.bones.Length - 1].transform.position, solver.IKPosition);
}
Handles.color = Color.white;
GUI.color = Color.white;
}
#endregion Public methods
private static bool weights;
private static void DrawArrayElementLabelBone(SerializedProperty bone, bool editHierarchy) {
AddObjectReference(bone.FindPropertyRelative("transform"), GUIContent.none, editHierarchy, 0, weights? 100: 200);
if (weights) AddWeightSlider(bone.FindPropertyRelative("weight"));
}
private static void OnAddToArrayBone(SerializedProperty bone) {
bone.FindPropertyRelative("weight").floatValue = 1f;
}
private static void AddWeightSlider(SerializedProperty prop) {
GUILayout.Label("Weight", GUILayout.Width(45));
EditorGUILayout.PropertyField(prop, GUIContent.none);
}
}
}

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: d5806071df7484ff0bfa7330e9adb04e
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,19 @@
using UnityEngine;
using UnityEditor;
using System.Collections;
using System;
namespace RootMotion.FinalIK {
/*
* Contains helper methods for managing IKSolver's fields.
* */
public class IKSolverInspector: Inspector {
public static float GetHandleSize(Vector3 position) {
float s = HandleUtility.GetHandleSize(position) * 0.1f;
return Mathf.Lerp(s, 0.025f, 0.2f);
}
}
}

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: f8fadad0d2804439bad44738bf137eb3
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,102 @@
using UnityEngine;
using UnityEditor;
using System.Collections;
namespace RootMotion.FinalIK {
/*
* Custom inspector and scene view tools for IKSolverLeg
* */
public class IKSolverLegInspector: IKSolverInspector {
#region Public methods
/*
* Draws the custom inspector for IKSolverTrigonometric
* */
public static void AddInspector(SerializedProperty prop, bool editHierarchy, bool showReferences) {
EditorGUI.indentLevel = 0;
// Bone references
if (showReferences) {
EditorGUILayout.Space();
AddObjectReference(prop.FindPropertyRelative("pelvis.transform"), new GUIContent("Pelvis", "The pelvis (hips)."), editHierarchy, 100);
AddObjectReference(prop.FindPropertyRelative("thigh.transform"), new GUIContent("Thigh", "The upper leg."), editHierarchy, 100);
AddObjectReference(prop.FindPropertyRelative("calf.transform"), new GUIContent("Calf", "The lower leg."), editHierarchy, 100);
AddObjectReference(prop.FindPropertyRelative("foot.transform"), new GUIContent("Foot", "The ankle."), editHierarchy, 100);
AddObjectReference(prop.FindPropertyRelative("toe.transform"), new GUIContent("Toe", "The first toe bone."), editHierarchy, 100);
EditorGUILayout.Space();
}
// Foot/Toe
EditorGUILayout.PropertyField(prop.FindPropertyRelative("leg.target"), new GUIContent("Target", "The target Transform. Solver IKPosition will be automatically set to the position of the target."));
EditorGUILayout.PropertyField(prop.FindPropertyRelative("IKPositionWeight"), new GUIContent("Position Weight", "Solver weight for smooth blending."));
EditorGUILayout.PropertyField(prop.FindPropertyRelative("IKRotationWeight"), new GUIContent("Rotation Weight", "Weight of last bone's rotation to IKRotation."));
EditorGUILayout.PropertyField(prop.FindPropertyRelative("heelOffset"), new GUIContent("Heel Offset", "Offset of the heel in world space."));
// Bending
EditorGUILayout.PropertyField(prop.FindPropertyRelative("leg.bendGoal"), new GUIContent("Bend Goal", "If assigned, the knee will be bent in the direction towards this transform."));
EditorGUILayout.PropertyField(prop.FindPropertyRelative("leg.bendGoalWeight"), new GUIContent("Bend Goal Weight", "Weight of the bend goal."));
EditorGUILayout.PropertyField(prop.FindPropertyRelative("leg.swivelOffset"), new GUIContent("Swivel Offset", "Angular offset of the leg's bending direction."));
EditorGUILayout.PropertyField(prop.FindPropertyRelative("leg.bendToTargetWeight"), new GUIContent("Bend To Target Weight", "If 0, the bend plane will be locked to the rotation of the pelvis and rotating the foot will have no effect on the knee direction. If 1, to the target rotation of the leg so that the knee will bend towards the forward axis of the foot. Values in between will be slerped between the two."));
// Stretching
EditorGUILayout.PropertyField(prop.FindPropertyRelative("leg.legLengthMlp"), new GUIContent("Leg Length Mlp", "Use this to make the leg shorter/longer."));
EditorGUILayout.PropertyField(prop.FindPropertyRelative("leg.stretchCurve"), new GUIContent("Stretch Curve", "Evaluates stretching of the leg by target distance relative to leg length. Value at time 1 represents stretching amount at the point where distance to the target is equal to leg length. Value at time 1 represents stretching amount at the point where distance to the target is double the leg length. Value represents the amount of stretching. Linear stretching would be achieved with a linear curve going up by 45 degrees. Increase the range of stretching by moving the last key up and right at the same amount. Smoothing in the curve can help reduce knee snapping (start stretching the arm slightly before target distance reaches leg length)."));
}
/*
* Draws the scene view helpers for IKSolverTrigonometric
* */
public static void AddScene(IKSolverLeg solver, Color color, bool modifiable) {
if (Application.isPlaying && !solver.initiated) return;
if (!Application.isPlaying && !solver.IsValid()) return;
//float length = Vector3.Distance(solver.bone1.transform.position, solver.bone2.transform.position) + Vector3.Distance(solver.bone2.transform.position, solver.bone3.transform.position);
//float size = length * 0.05f;
Handles.color = color;
GUI.color = color;
// Chain lines
Handles.DrawLine(solver.pelvis.transform.position, solver.thigh.transform.position);
Handles.DrawLine(solver.thigh.transform.position, solver.calf.transform.position);
Handles.DrawLine(solver.calf.transform.position, solver.foot.transform.position);
Handles.DrawLine(solver.foot.transform.position, solver.toe.transform.position);
// Joints
Inspector.SphereCap(0, solver.pelvis.transform.position, Quaternion.identity, GetHandleSize(solver.pelvis.transform.position));
Inspector.SphereCap(0, solver.thigh.transform.position, Quaternion.identity, GetHandleSize(solver.thigh.transform.position));
Inspector.SphereCap(0, solver.calf.transform.position, Quaternion.identity, GetHandleSize(solver.calf.transform.position));
Inspector.SphereCap(0, solver.foot.transform.position, Quaternion.identity, GetHandleSize(solver.foot.transform.position));
Inspector.SphereCap(0, solver.toe.transform.position, Quaternion.identity, GetHandleSize(solver.toe.transform.position));
if (Application.isPlaying && (solver.IKPositionWeight > 0 || solver.IKRotationWeight > 0)) {
if (modifiable) {
Inspector.CubeCap(0, solver.IKPosition, solver.IKRotation, GetHandleSize(solver.IKPosition));
// Manipulating position and rotation
switch(Tools.current) {
case Tool.Move:
if (solver.leg.target == null) solver.IKPosition = Handles.PositionHandle(solver.IKPosition, Quaternion.identity);
break;
case Tool.Rotate:
if (solver.leg.target == null) solver.IKRotation = Handles.RotationHandle(solver.IKRotation, solver.IKPosition);
break;
}
}
// Target
Handles.color = new Color(color.r, color.g, color.b, color.a * Mathf.Max(solver.IKPositionWeight, solver.IKRotationWeight));
Handles.DrawLine(solver.toe.transform.position, solver.IKPosition);
}
Handles.color = Color.white;
GUI.color = Color.white;
}
#endregion Public methods
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: b8601eb42d45b294dba88abac3e27d24
timeCreated: 1487059931
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,63 @@
using UnityEngine;
using UnityEditor;
using System.Collections;
using System;
namespace RootMotion.FinalIK {
/*
* Custom inspector and scene view tools for IKSolverLimb
* */
public class IKSolverLimbInspector: IKSolverInspector {
#region Public methods
/*
* Draws the custom inspector for IKSolverLimb
* */
public static void AddInspector(SerializedProperty prop, bool editHierarchy, bool showReferences) {
// Draw the trigonometric IK inspector
IKSolverTrigonometricInspector.AddInspector(prop, editHierarchy, showReferences);
EditorGUILayout.Space();
if (showReferences && editHierarchy) {
EditorGUILayout.PropertyField(prop.FindPropertyRelative("goal"), new GUIContent("Avatar IK Goal", "Avatar IK Goal here is only used by the 'Arm' bend modifier."));
}
EditorGUILayout.PropertyField(prop.FindPropertyRelative("maintainRotationWeight"), new GUIContent("Maintain Rotation", "Weight of rotating the last bone back to the rotation it had before solving IK."));
// Bend normal modifier.
EditorGUILayout.PropertyField(prop.FindPropertyRelative("bendModifier"), new GUIContent("Bend Modifier", "Bend normal modifier."));
EditorGUILayout.PropertyField(prop.FindPropertyRelative("bendModifierWeight"), new GUIContent("Bend Modifier Weight", "Weight of the bend modifier."));
if (prop.FindPropertyRelative("bendModifier").enumValueIndex == 4) EditorGUILayout.PropertyField(prop.FindPropertyRelative("bendGoal"), new GUIContent("Bend Goal", "The bend goal Transform (optional, you can also use IKSolverTrigonometric.SetBendGoalPosition(Vector position, float weight)."));
EditorGUILayout.Space();
}
/*
* Draws the scene view helpers for IKSolverLimb
* */
public static void AddScene(IKSolverLimb solver, Color color, bool modifiable) {
if (Application.isPlaying && !solver.initiated) return;
if (!Application.isPlaying && !solver.IsValid()) return;
if (solver.bendGoal != null && solver.bendModifierWeight > 0f) {
Color c = color;
c.a = solver.bendModifierWeight;
Handles.color = c;
Handles.DrawLine(solver.bone2.transform.position, solver.bendGoal.position);
Inspector.SphereCap(0, solver.bendGoal.position, Quaternion.identity, GetHandleSize(solver.bendGoal.position) * 0.5f);
Handles.color = Color.white;
}
IKSolverTrigonometricInspector.AddScene(solver as IKSolverTrigonometric, color, modifiable);
}
#endregion Public methods
}
}

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 57956e150e00f474b9c03c7155dc43e3
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,122 @@
using UnityEngine;
using UnityEditor;
using System.Collections;
using System;
namespace RootMotion.FinalIK {
/*
* Custom inspector and scene view tools for IKSolverLookAt
* */
public class IKSolverLookAtInspector: IKSolverInspector {
#region Public methods
/*
* Draws the custom inspector for IKSolverLookAt
* */
public static void AddInspector(SerializedProperty prop, bool editHierarchy, bool showReferences) {
EditorGUILayout.PropertyField(prop.FindPropertyRelative("target"), new GUIContent("Target", "The target Transform. Solver IKPosition will be automatically set to the position of the target."));
EditorGUILayout.PropertyField(prop.FindPropertyRelative("IKPositionWeight"), new GUIContent("Weight", "Solver weight for smooth blending."));
EditorGUILayout.PropertyField(prop.FindPropertyRelative("bodyWeight"), new GUIContent("Body Weight", "Weight of rotating spine to target."));
EditorGUILayout.PropertyField(prop.FindPropertyRelative("headWeight"), new GUIContent("Head Weight", "Weight of rotating head to target."));
EditorGUILayout.PropertyField(prop.FindPropertyRelative("eyesWeight"), new GUIContent("Eyes Weight", "Weight of rotating eyes to target."));
EditorGUILayout.PropertyField(prop.FindPropertyRelative("clampWeight"), new GUIContent("Clamp Weight", "Clamping rotation of spine and head. 0 is free rotation, 1 is completely clamped to forward."));
EditorGUILayout.PropertyField(prop.FindPropertyRelative("clampWeightHead"), new GUIContent("Clamp Weight Head", "Clamping rotation of the head. 0 is free rotation, 1 is completely clamped to forward."));
EditorGUILayout.PropertyField(prop.FindPropertyRelative("clampWeightEyes"), new GUIContent("Clamp Weight Eyes", "Clamping rotation of the eyes. 0 is free rotation, 1 is completely clamped to forward."));
EditorGUILayout.PropertyField(prop.FindPropertyRelative("clampSmoothing"), new GUIContent("Clamp Smoothing", "Number of sine smoothing iterations applied on clamping to make the clamping point smoother."));
EditorGUILayout.PropertyField(prop.FindPropertyRelative("spineWeightCurve"), new GUIContent("Spine Weight Curve", "Weight distribution between spine bones (first bone is evaluated at time 0.0, last bone at 1.0)."));
// References
if (showReferences) {
EditorGUILayout.Space();
EditorGUILayout.PropertyField(prop.FindPropertyRelative("head.transform"), new GUIContent("Head", "The head bone."));
EditorGUILayout.Space();
AddArray(prop.FindPropertyRelative("spine"), new GUIContent("Spine", string.Empty), editHierarchy, false, null, null, DrawArrayElementLabelBone);
EditorGUILayout.Space();
AddArray(prop.FindPropertyRelative("eyes"), new GUIContent("Eyes", string.Empty), editHierarchy, false, null, null, DrawArrayElementLabelBone);
}
EditorGUILayout.Space();
}
/*
* Draws the scene view helpers for IKSolverLookAt
* */
public static void AddScene(IKSolverLookAt solver, Color color, bool modifiable) {
// Protect from null reference errors
if (Application.isPlaying && !solver.initiated) return;
if (!Application.isPlaying && !solver.IsValid()) return;
// Display the Spine
if (solver.spine.Length > 0) {
Handles.color = color;
GUI.color = color;
for (int i = 0; i < solver.spine.Length; i++) {
IKSolverLookAt.LookAtBone bone = solver.spine[i];
if (i < solver.spine.Length - 1) Handles.DrawLine(bone.transform.position, solver.spine[i + 1].transform.position);
Inspector.SphereCap(0, bone.transform.position, Quaternion.identity, GetHandleSize(bone.transform.position));
}
// Draw a transparent line from last bone to IKPosition
if (Application.isPlaying) {
Handles.color = new Color(color.r, color.g, color.b, color.a * solver.IKPositionWeight * solver.bodyWeight);
Handles.DrawLine(solver.spine[solver.spine.Length - 1].transform.position, solver.IKPosition);
}
}
// Display the eyes
if (solver.eyes.Length > 0) {
for (int i = 0; i < solver.eyes.Length; i++) {
DrawLookAtBoneInScene(solver.eyes[i], solver.IKPosition, color, solver.IKPositionWeight * solver.eyesWeight);
}
}
// Display the head
if (solver.head.transform != null) {
DrawLookAtBoneInScene(solver.head, solver.IKPosition, color, solver.IKPositionWeight * solver.headWeight);
}
Handles.color = color;
GUI.color = color;
// Selecting joint and manipulating IKPosition
if (Application.isPlaying && solver.IKPositionWeight > 0) {
if (modifiable) {
Inspector.SphereCap(0, solver.IKPosition, Quaternion.identity, GetHandleSize(solver.IKPosition));
// Manipulating position
if (solver.target == null) solver.IKPosition = Handles.PositionHandle(solver.IKPosition, Quaternion.identity);
}
}
Handles.color = Color.white;
GUI.color = Color.white;
}
#endregion Public methods
private static void DrawArrayElementLabelBone(SerializedProperty bone, bool editHierarchy) {
AddObjectReference(bone.FindPropertyRelative("transform"), GUIContent.none, editHierarchy, 0, 300);
}
private static void DrawLookAtBoneInScene(IKSolverLookAt.LookAtBone bone, Vector3 IKPosition, Color color, float lineWeight) {
Handles.color = color;
GUI.color = color;
Inspector.SphereCap(0, bone.transform.position, Quaternion.identity, GetHandleSize(bone.transform.position));
// Draw a transparent line from last bone to IKPosition
if (Application.isPlaying && lineWeight > 0) {
Handles.color = new Color(color.r, color.g, color.b, color.a * lineWeight);
Handles.DrawLine(bone.transform.position, IKPosition);
}
}
}
}

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 5cf17f5d7f4954636ad6575fd9f9832c
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,97 @@
using UnityEngine;
using UnityEditor;
using System.Collections;
namespace RootMotion.FinalIK {
/*
* Custom inspector and scene view tools for IKSolverTrigonometric
* */
public class IKSolverTrigonometricInspector: IKSolverInspector {
#region Public methods
/*
* Draws the custom inspector for IKSolverTrigonometric
* */
public static void AddInspector(SerializedProperty prop, bool editHierarchy, bool showReferences) {
EditorGUI.indentLevel = 0;
// Bone references
if (showReferences) {
EditorGUILayout.Space();
AddObjectReference(prop.FindPropertyRelative("bone1.transform"), new GUIContent("Bone 1", "The first bone in the hierarchy (thigh or upper arm)."), editHierarchy, 100);
AddObjectReference(prop.FindPropertyRelative("bone2.transform"), new GUIContent("Bone 2", "The second bone in the hierarchy (calf or forearm)."), editHierarchy, 100);
AddObjectReference(prop.FindPropertyRelative("bone3.transform"), new GUIContent("Bone 3", "The last bone in the hierarchy (foot or hand)."), editHierarchy, 100);
EditorGUILayout.Space();
}
EditorGUILayout.PropertyField(prop.FindPropertyRelative("target"), new GUIContent("Target", "The target Transform. Solver IKPosition will be automatically set to the position of the target."));
EditorGUILayout.PropertyField(prop.FindPropertyRelative("IKPositionWeight"), new GUIContent("Position Weight", "Solver weight for smooth blending."));
EditorGUILayout.PropertyField(prop.FindPropertyRelative("IKRotationWeight"), new GUIContent("Rotation Weight", "Weight of last bone's rotation to IKRotation."));
if (showReferences) {
EditorGUILayout.PropertyField(prop.FindPropertyRelative("bendNormal"), new GUIContent("Bend Normal", "Bend plane normal."));
}
}
public static void AddTestInspector(SerializedObject obj) {
SerializedProperty solver = obj.FindProperty("solver");
EditorGUILayout.PropertyField(solver.FindPropertyRelative("bendNormal"));
}
/*
* Draws the scene view helpers for IKSolverTrigonometric
* */
public static void AddScene(IKSolverTrigonometric solver, Color color, bool modifiable) {
if (Application.isPlaying && !solver.initiated) return;
if (!Application.isPlaying && !solver.IsValid()) return;
//float length = Vector3.Distance(solver.bone1.transform.position, solver.bone2.transform.position) + Vector3.Distance(solver.bone2.transform.position, solver.bone3.transform.position);
//float size = length * 0.05f;
Handles.color = color;
GUI.color = color;
Vector3 bendPosition = solver.bone2.transform.position;
Vector3 endPosition = solver.bone3.transform.position;
// Chain lines
Handles.DrawLine(solver.bone1.transform.position, bendPosition);
Handles.DrawLine(bendPosition, endPosition);
// Joints
Inspector.SphereCap(0, solver.bone1.transform.position, Quaternion.identity, GetHandleSize(solver.bone1.transform.position));
Inspector.SphereCap(0, bendPosition, Quaternion.identity, GetHandleSize(bendPosition));
Inspector.SphereCap(0, endPosition, Quaternion.identity, GetHandleSize(endPosition));
if (Application.isPlaying && (solver.IKPositionWeight > 0 || solver.IKRotationWeight > 0)) {
if (modifiable) {
Inspector.CubeCap(0, solver.IKPosition, solver.IKRotation, GetHandleSize(solver.IKPosition));
// Manipulating position and rotation
switch(Tools.current) {
case Tool.Move:
if (solver.target == null) solver.IKPosition = Handles.PositionHandle(solver.IKPosition, Quaternion.identity);
break;
case Tool.Rotate:
if (solver.target == null) solver.IKRotation = Handles.RotationHandle(solver.IKRotation, solver.IKPosition);
break;
}
}
// Target
Handles.color = new Color(color.r, color.g, color.b, color.a * Mathf.Max(solver.IKPositionWeight, solver.IKRotationWeight));
Handles.DrawLine(endPosition, solver.IKPosition);
}
Handles.color = Color.white;
GUI.color = Color.white;
}
#endregion Public methods
}
}

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 3474539eeb23c491fbd6a10e0951ce9d
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,90 @@
using UnityEngine;
using UnityEditor;
using System.Collections;
using RootMotion.FinalIK;
namespace RootMotion.Demos {
/*
* Custom inspector and scene view helpers for the InteractionTarget.
* */
[CustomEditor(typeof(InteractionTarget))]
public class InteractionTargetInspector : Editor {
private InteractionTarget script { get { return target as InteractionTarget; }}
private const string twistAxisLabel = " Twist Axis";
private const float size = 0.005f;
private static Color targetColor = new Color(0.2f, 1f, 0.5f);
private static Color pivotColor = new Color(0.2f, 0.5f, 1f);
void OnSceneGUI() {
Handles.color = targetColor;
Inspector.SphereCap(0, script.transform.position, Quaternion.identity, size);
DrawChildrenRecursive(script.transform);
if (script.pivot != null) {
Handles.color = pivotColor;
GUI.color = pivotColor;
Inspector.SphereCap(0, script.pivot.position, Quaternion.identity, size);
if (script.rotationMode == InteractionTarget.RotationMode.TwoDOF)
{
Vector3 twistAxisWorld = script.pivot.rotation * script.twistAxis.normalized * size * 40;
Handles.DrawLine(script.pivot.position, script.pivot.position + twistAxisWorld);
Inspector.SphereCap(0, script.pivot.position + twistAxisWorld, Quaternion.identity, size);
Inspector.CircleCap(0, script.pivot.position, Quaternion.LookRotation(twistAxisWorld), size * 20);
Handles.Label(script.pivot.position + twistAxisWorld, twistAxisLabel);
}
}
Handles.color = Color.white;
GUI.color = Color.white;
}
public override void OnInspectorGUI()
{
serializedObject.Update();
EditorGUILayout.PropertyField(serializedObject.FindProperty("effectorType"));
EditorGUILayout.PropertyField(serializedObject.FindProperty("multipliers"), true);
EditorGUILayout.PropertyField(serializedObject.FindProperty("interactionSpeedMlp"));
EditorGUILayout.PropertyField(serializedObject.FindProperty("pivot"));
EditorGUILayout.Space();
EditorGUILayout.PropertyField(serializedObject.FindProperty("rotationMode"));
int rotationMode = serializedObject.FindProperty("rotationMode").enumValueIndex;
if (rotationMode == 0)
{
EditorGUILayout.PropertyField(serializedObject.FindProperty("twistAxis"));
EditorGUILayout.PropertyField(serializedObject.FindProperty("twistWeight"));
EditorGUILayout.PropertyField(serializedObject.FindProperty("swingWeight"));
} else if (rotationMode == 1)
{
EditorGUILayout.PropertyField(serializedObject.FindProperty("threeDOFWeight"));
}
EditorGUILayout.PropertyField(serializedObject.FindProperty("rotateOnce"));
EditorGUILayout.PropertyField(serializedObject.FindProperty("usePoser"));
if (serializedObject.ApplyModifiedProperties())
{
EditorUtility.SetDirty(script);
}
}
private void DrawChildrenRecursive(Transform t) {
for (int i = 0; i < t.childCount; i++) {
Handles.DrawLine(t.position, t.GetChild(i).position);
Inspector.SphereCap(0, t.GetChild(i).position, Quaternion.identity, size);
DrawChildrenRecursive(t.GetChild(i));
}
}
}
}

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 244e0878f45b6442cac28a34942f9ac3
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,206 @@
using UnityEngine;
using UnityEditor;
using System.Collections;
namespace RootMotion.FinalIK {
// Custom scene view helpers for the InteractionTrigger
[CustomEditor(typeof(InteractionTrigger))]
public class InteractionTriggerInspector : Editor {
private InteractionTrigger script { get { return target as InteractionTrigger; }}
void OnSceneGUI() {
if (!script.enabled) return;
var collider = script.GetComponent<Collider>();
if (collider != null)
collider.isTrigger = true;
else {
Warning.Log ("InteractionTrigger requires a Collider component.", script.transform, true);
return;
}
if (script.ranges.Length == 0) return;
for (int i = 0; i < script.ranges.Length; i++) {
DrawRange (script.ranges[i], i);
}
Handles.BeginGUI();
int h = script.ranges.Length * 18;
GUILayout.BeginArea(new Rect(10, 10, 200, h + 25), "InteractionTrigger Visualization", "Window");
// Rotating display
for (int i = 0; i < script.ranges.Length; i++) {
script.ranges[i].show = GUILayout.Toggle(script.ranges[i].show, new GUIContent(" Show Range " + i.ToString() + ": " + script.ranges[i].name, string.Empty));
}
GUILayout.EndArea();
Handles.EndGUI();
}
private void DrawRange(InteractionTrigger.Range range, int index) {
range.name = string.Empty;
for (int i = 0; i < range.interactions.Length; i++) {
if (range.name.Length > 50) {
range.name += "...";
break;
}
if (i > 0) range.name += "; ";
for (int e = 0; e < range.interactions[i].effectors.Length; e++) {
if (e > 0) range.name += ", ";
range.name += range.interactions[i].effectors[e].ToString();
}
if (range.interactions[i].interactionObject != null) {
range.name += ": " + range.interactions[i].interactionObject.name;
}
}
if (!range.show) return;
Color color = GetColor(index);
Handles.color = color;
GUI.color = color;
// Character Position
DrawCharacterPosition(range, index);
// Camera Position
DrawCameraPosition(range, index);
Handles.color = Color.white;
GUI.color = Color.white;
}
private void DrawCharacterPosition(InteractionTrigger.Range range, int index) {
Vector3 labelPosition = script.transform.position - Vector3.up * index * 0.05f;
if (!range.characterPosition.use) {
Handles.Label(labelPosition, "Character Position is not used for Range " + index.ToString() + ": " + range.name);
return;
}
range.characterPosition.radius = Mathf.Max(range.characterPosition.radius, 0f);
if (range.characterPosition.radius <= 0f) {
Handles.Label(labelPosition, "Character Position radius is zero for Range " + index.ToString() + ": " + range.name);
return;
}
if (range.characterPosition.maxAngle <= 0f) {
Handles.Label(labelPosition, "Character Position max angle is zero for Range " + index.ToString() + ": " + range.name);
return;
}
Vector3 f = script.transform.forward;
if (range.characterPosition.fixYAxis) f.y = 0f;
if (f == Vector3.zero) {
Handles.Label(script.transform.position - Vector3.up * index * 0.05f, "Invalid rotation of InteractionTrigger for Range " + index.ToString() + ": " + range.name);
return; // Singularity
}
Quaternion triggerRotation = Quaternion.LookRotation(f, (range.characterPosition.fixYAxis? Vector3.up: script.transform.up));
Vector3 position = script.transform.position + triggerRotation * range.characterPosition.offset3D;
Vector3 direction = triggerRotation * range.characterPosition.direction3D;
Quaternion rotation = direction == Vector3.zero? triggerRotation: Quaternion.LookRotation(direction, (range.characterPosition.fixYAxis? Vector3.up: script.transform.up));
Vector3 up = rotation * Vector3.up;
Vector3 forward = rotation * Vector3.forward;
Handles.DrawWireDisc(position, up, range.characterPosition.radius);
if (range.characterPosition.orbit) {
float mag = range.characterPosition.offset.magnitude;
if (mag - range.characterPosition.radius > 0f) {
Handles.DrawWireDisc(script.transform.position, up, mag - range.characterPosition.radius);
}
Handles.DrawWireDisc(script.transform.position, up, mag + range.characterPosition.radius);
}
Vector3 x = forward * range.characterPosition.radius;
Quaternion q = Quaternion.AngleAxis(-range.characterPosition.maxAngle, up);
Vector3 dir = q * x;
if (direction != Vector3.zero && range.characterPosition.maxAngle < 180f) {
Handles.DrawLine(position, position + x);
Inspector.DotCap(0, position + x, Quaternion.identity, range.characterPosition.radius * 0.01f);
}
Handles.Label(position - Vector3.up * index * 0.05f, "Character Position for Range " + index.ToString() + ": " + range.name);
Color color = Handles.color;
Color transparent = new Color(color.r, color.g, color.b, 0.3f);
Handles.color = transparent;
Handles.DrawSolidArc(position, up, dir, range.characterPosition.maxAngle * 2f, range.characterPosition.radius);
Handles.color = color;
}
private void DrawCameraPosition(InteractionTrigger.Range range, int index) {
if (range.cameraPosition.lookAtTarget == null) return;
Vector3 labelPosition = range.cameraPosition.lookAtTarget.transform.position - Vector3.up * index * 0.05f;
if (range.cameraPosition.direction == Vector3.zero) {
Handles.Label(labelPosition, "Camera Position direction is Vector3.zero for Range" + index.ToString() + ": " + range.name);
return;
}
if (range.cameraPosition.maxAngle <= 0f) {
Handles.Label(labelPosition, "Camera Position max angle is zero for Range" + index.ToString() + ": " + range.name);
return;
}
range.cameraPosition.maxDistance = Mathf.Max(range.cameraPosition.maxDistance, 0f);
if (range.cameraPosition.maxDistance <= 0f) {
Handles.Label(labelPosition, "Camera Position Max Distance is zero for Range" + index.ToString() + ": " + range.name);
return;
}
Quaternion targetRotation = range.cameraPosition.GetRotation();
Vector3 position = range.cameraPosition.lookAtTarget.transform.position;
Vector3 direction = targetRotation * range.cameraPosition.direction;
direction = direction.normalized * range.cameraPosition.maxDistance;
Handles.DrawLine(position, position + direction);
Inspector.DotCap(0, position + direction, Quaternion.identity, 0.005f);
Handles.Label(position + direction * 1.1f, "Camera Position for Range " + index.ToString() + ": " + range.name);
if (range.cameraPosition.maxAngle >= 180f) return;
float r = Mathf.Sin(range.cameraPosition.maxAngle * Mathf.Deg2Rad) * range.cameraPosition.maxDistance;
float d = Mathf.Cos(range.cameraPosition.maxAngle * Mathf.Deg2Rad) * range.cameraPosition.maxDistance;
Quaternion rotation = targetRotation * Quaternion.LookRotation(range.cameraPosition.direction);
Inspector.CircleCap(0, position + direction.normalized * d, rotation, r);
if (SceneView.lastActiveSceneView != null && SceneView.lastActiveSceneView.camera != null) {
//Vector3 c = Vector3.Cross(direction, SceneView.lastActiveSceneView.camera.transform.forward);
Vector3 c = Vector3.Cross(direction, (range.cameraPosition.lookAtTarget.transform.position - SceneView.lastActiveSceneView.camera.transform.position).normalized);
c = Vector3.Cross(direction, c);
Quaternion dirRotation = Quaternion.AngleAxis(range.cameraPosition.maxAngle, c);
Vector3 dir3 = dirRotation * direction;
Handles.DrawLine(position, position + dir3);
Vector3 dir4 = Quaternion.Inverse(dirRotation) * direction;
Handles.DrawLine(position, position + dir4);
Handles.DrawWireArc(position, -c, dir3, range.cameraPosition.maxAngle * 2, range.cameraPosition.maxDistance);
}
}
private static Color GetColor(int index) {
float i = (float)index + 1f;
return new Color(1f / i, i * 0.1f, (i * i) + 0.1f);
}
}
}

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 873f095e66d4c4a1cad1da5353934f00
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,38 @@
using UnityEditor;
using UnityEngine;
using System.Collections;
namespace RootMotion.FinalIK {
/*
* Custom inspector for LegIK.
* */
[CustomEditor(typeof(LegIK))]
public class LegIKInspector : IKInspector {
private LegIK script { get { return target as LegIK; }}
protected override MonoBehaviour GetMonoBehaviour(out int executionOrder) {
executionOrder = 9997;
return script;
}
protected override void OnApplyModifiedProperties() {
if (!Application.isPlaying) script.solver.Initiate(script.transform);
}
protected override void AddInspector() {
// Draw the inspector for IKSolverTrigonometric
IKSolverLegInspector.AddInspector(solver, !Application.isPlaying, true);
// Warning box
string message = string.Empty;
if (!script.solver.IsValid(ref message)) AddWarningBox(message);
}
void OnSceneGUI() {
// Draw the scene veiw helpers
IKSolverLegInspector.AddScene(script.solver, new Color(0f, 1f, 1f, 1f), true);
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: a1d4a2dfd093628479ab4e1611fab8cf
timeCreated: 1487059923
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,38 @@
using UnityEditor;
using UnityEngine;
using System.Collections;
namespace RootMotion.FinalIK {
/*
* Custom inspector for LimbIK.
* */
[CustomEditor(typeof(LimbIK))]
public class LimbIKInspector : IKInspector {
private LimbIK script { get { return target as LimbIK; }}
protected override MonoBehaviour GetMonoBehaviour(out int executionOrder) {
executionOrder = 9997;
return script;
}
protected override void OnApplyModifiedProperties() {
if (!Application.isPlaying) script.solver.Initiate(script.transform);
}
protected override void AddInspector() {
// Draw the inspector for IKSolverLimb
IKSolverLimbInspector.AddInspector(solver, !Application.isPlaying, true);
// Warning box
string message = string.Empty;
if (!script.solver.IsValid(ref message)) AddWarningBox(message);
}
void OnSceneGUI() {
// Draw the scene veiw helpers
IKSolverLimbInspector.AddScene(script.solver, new Color(0f, 1f, 1f, 1f), true);
}
}
}

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: f0d1da4d6345d4ebbb58a7fbdb461e88
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,39 @@
using UnityEditor;
using UnityEngine;
using System.Collections;
namespace RootMotion.FinalIK {
/*
* Custom inspector for LookAtIK.
* */
[CustomEditor(typeof(LookAtIK))]
public class LookAtIKInspector : IKInspector {
private LookAtIK script { get { return target as LookAtIK; }}
protected override MonoBehaviour GetMonoBehaviour(out int executionOrder) {
executionOrder = 9997;
return script;
}
protected override void OnApplyModifiedProperties() {
if (!Application.isPlaying) script.solver.Initiate(script.transform);
}
protected override void AddInspector() {
// Draw the inspector for IKSolverTrigonometric
IKSolverLookAtInspector.AddInspector(solver, !Application.isPlaying, true);
// Warning box
string message = string.Empty;
if (!script.solver.IsValid(ref message)) AddWarningBox(message);
}
void OnSceneGUI() {
// Draw the scene veiw helpers
IKSolverLookAtInspector.AddScene(script.solver, new Color(0f, 1f, 1f, 1f), true);
}
}
}

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 76c03a228cc7d4cfab5b65bf55ca89a0
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,93 @@
using UnityEditor;
using UnityEngine;
using System.Collections;
namespace RootMotion.FinalIK
{
/*
* Custom inspector for RotationLimitAngle.
* */
[CustomEditor(typeof(RotationLimitAngle))]
[CanEditMultipleObjects]
public class RotationLimitAngleInspector : RotationLimitInspector
{
private RotationLimitAngle script { get { return target as RotationLimitAngle; } }
#region Inspector
public override void OnInspectorGUI()
{
GUI.changed = false;
// Draw the default inspector
DrawDefaultInspector();
script.limit = Mathf.Clamp(script.limit, 0, 180);
if (GUI.changed) EditorUtility.SetDirty(script);
}
#endregion Inspector
#region Scene
void OnSceneGUI()
{
// Set defaultLocalRotation so that the initial local rotation will be the zero point for the rotation limit
if (!Application.isPlaying && !script.defaultLocalRotationOverride) script.defaultLocalRotation = script.transform.localRotation;
if (script.axis == Vector3.zero) return;
DrawRotationSphere(script.transform.position);
// Display the main axis
DrawArrow(script.transform.position, Direction(script.axis), colorDefault, "Axis", 0.02f);
Vector3 swing = script.axis.normalized;
// Display limits
lastPoint = script.transform.position;
for (int i = 0; i < 360; i += 2)
{
Quaternion offset = Quaternion.AngleAxis(i, swing);
Quaternion limitedRotation = Quaternion.AngleAxis(script.limit, offset * script.crossAxis);
Vector3 limitedDirection = Direction(limitedRotation * swing);
Handles.color = colorDefaultTransparent;
Vector3 limitPoint = script.transform.position + limitedDirection;
if (i == 0) zeroPoint = limitPoint;
Handles.DrawLine(script.transform.position, limitPoint);
if (i > 0)
{
Handles.color = colorDefault;
Handles.DrawLine(limitPoint, lastPoint);
if (i == 358) Handles.DrawLine(limitPoint, zeroPoint);
}
lastPoint = limitPoint;
}
Handles.color = Color.white;
}
private Vector3 lastPoint, zeroPoint;
/*
* Converting directions from local space to world space
* */
private Vector3 Direction(Vector3 v)
{
if (script.transform.parent == null) return script.defaultLocalRotation * v;
return script.transform.parent.rotation * (script.defaultLocalRotation * v);
}
#endregion Scene
}
}

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: c1549de5f5a6641758443bebbd5eb733
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,119 @@
using UnityEditor;
using UnityEngine;
using System.Collections;
namespace RootMotion.FinalIK
{
/*
* Custom inspector for RotationLimitHinge
* */
[CustomEditor(typeof(RotationLimitHinge))]
[CanEditMultipleObjects]
public class RotationLimitHingeInspector : RotationLimitInspector
{
private RotationLimitHinge script { get { return target as RotationLimitHinge; } }
#region Inspector
public override void OnInspectorGUI()
{
GUI.changed = false;
// Draw the default inspector
DrawDefaultInspector();
if (GUI.changed) EditorUtility.SetDirty(script);
}
#endregion Inspector
#region Scene
void OnSceneGUI()
{
// Set defaultLocalRotation so that the initial local rotation will be the zero point for the rotation limit
if (!Application.isPlaying && !script.defaultLocalRotationOverride) script.defaultLocalRotation = script.transform.localRotation;
if (script.axis == Vector3.zero) return;
// Quick Editing Tools
Handles.BeginGUI();
GUILayout.BeginArea(new Rect(10, 10, 200, 50), "Rotation Limit Hinge", "Window");
// Rotating display
if (GUILayout.Button("Rotate display 90 degrees"))
{
if (!Application.isPlaying) Undo.RecordObject(script, "Rotate Display");
script.zeroAxisDisplayOffset += 90;
if (script.zeroAxisDisplayOffset >= 360) script.zeroAxisDisplayOffset = 0;
}
GUILayout.EndArea();
Handles.EndGUI();
// Normalize the main axes
Vector3 axis = Direction(script.axis.normalized);
Vector3 cross = Direction(Quaternion.AngleAxis(script.zeroAxisDisplayOffset, script.axis) * script.crossAxis.normalized);
// Axis vector
DrawArrow(script.transform.position, axis, colorDefault, "Axis", 0.02f);
if (script.useLimits)
{
// Zero rotation vector
DrawArrow(script.transform.position, cross * 0.5f, colorDefault, " 0", 0.02f);
// Arcs for the rotation limit
Handles.color = colorDefaultTransparent;
Handles.DrawSolidArc(script.transform.position, axis, cross, script.min, 0.5f);
Handles.DrawSolidArc(script.transform.position, axis, cross, script.max, 0.5f);
}
Handles.color = colorDefault;
GUI.color = colorDefault;
Inspector.CircleCap(0, script.transform.position, Quaternion.LookRotation(axis, cross), 0.5f);
if (!script.useLimits) return;
// Handles for adjusting rotation limits in the scene
Quaternion minRotation = Quaternion.AngleAxis(script.min, axis);
Handles.DrawLine(script.transform.position, script.transform.position + minRotation * cross);
Quaternion maxRotation = Quaternion.AngleAxis(script.max, axis);
Handles.DrawLine(script.transform.position, script.transform.position + maxRotation * cross);
// Undoable scene handles
float min = script.min;
min = DrawLimitHandle(min, script.transform.position + minRotation * cross, Quaternion.identity, 0.5f, "Min", -10);
if (min != script.min)
{
if (!Application.isPlaying) Undo.RecordObject(script, "Min Limit");
script.min = min;
}
float max = script.max;
max = DrawLimitHandle(max, script.transform.position + maxRotation * cross, Quaternion.identity, 0.5f, "Max", 10);
if (max != script.max)
{
if (!Application.isPlaying) Undo.RecordObject(script, "Max Limit");
script.max = max;
}
Handles.color = Color.white;
GUI.color = Color.white;
}
/*
* Converting directions from local space to world space
* */
private Vector3 Direction(Vector3 v)
{
if (script.transform.parent == null) return script.defaultLocalRotation * v;
return script.transform.parent.rotation * (script.defaultLocalRotation * v);
}
#endregion Scene
}
}

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 9c6dcd6b6b7a74dd6b1ef5428b42217b
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

Some files were not shown because too many files have changed in this diff Show More