#if (UNITY_EDITOR) using UnityEngine; using UnityEditor; using System.IO; namespace ECE { [System.Serializable] public class EasyColliderPreferences : ScriptableObject { #if (!UNITY_EDITOR_LINUX) /// /// Currently set vhacd parameters. /// [SerializeField] private VHACDParameters _VHACDParameters; public VHACDParameters VHACDParameters { get { if (_VHACDParameters == null) { _VHACDParameters = new VHACDParameters(); } return _VHACDParameters; } set { _VHACDParameters = value; } } /// /// Float to convert to vhacd parameters resolution using 2^Value for UI Slider when advanced parameters is expanded /// [SerializeField] public float VHACDResFloat = 12.97f; /// /// Resets vhacd parameters to default. /// public void VHACDSetDefaultParameters() { VHACDParameters = new VHACDParameters(); } #endif /// /// When enabled, selecting objects in the background of the scene view can be done with a single click even when an object is currently selected for collider creation. /// [SerializeField] public bool AllowBackgroundSelection; /// /// when enabled, allows convex hulls used in mesh colliders to be saved in Packages folder. /// THESE FILES ARE NOT SHARED WITH JUST THE PROJECT. MUST BE HANDLED BY YOUR TEAM. MUST ALSO SHARE SOURCE PACKAGES FOLDERS /// [SerializeField] public bool AllowSavingConvexHullsInPackages; /// /// When entering prefab mode, should we automatically select the root object? /// [SerializeField] public bool AutoSelectOnPrefabOpen; /// /// Auto include child skinned meshes /// [SerializeField] public bool AutoIncludeChildSkinnedMeshes; /// /// Should we try to reduce the number of vertices in auto-skinned calculations for convex mesh colliders if the result ends up trying to create a collider that has >=256 triangles. /// [SerializeField] public bool AutoSkinnedForce256Triangles; /// /// The minimum weight for a vertex to be included in a bone's calculations. /// [SerializeField] public float AutoSkinnedMinBoneWeight; /// /// The angle of mis-alignedment above which we should create a better aligned child transform to hold colliders for skinned meshes. /// [SerializeField] public float AutoSkinnedMinRealignAngle; /// /// Should we allow transforms to be created that would better align the collider with the mesh than a mis-aligned bone? /// [SerializeField] public bool AutoSkinnedAllowRealign; /// /// Type of collider to use when auto generating skinned mesh colliders along a bone chain. /// [SerializeField] public SKINNED_MESH_COLLIDER_TYPE AutoSkinnedColliderType = SKINNED_MESH_COLLIDER_TYPE.Box; /// /// Should we be attempting to compute penetration and depenetrate the colliders on the skinned mesh? /// [SerializeField] public bool AutoSkinnedDepenetrate; /// /// Are we displaying with indentation? /// [SerializeField] public bool AutoSkinnedIndents = true; /// /// number of times to run depenetration methods before stopping. /// [SerializeField] public int AutoSkinnedIterativeDepenetrationCount = 15; /// /// Are we displaying with paired bones? /// [SerializeField] public bool AutoSkinnedPairing = true; /// /// Are we using per-bone settings /// [SerializeField] public bool AutoSkinnedPerBoneSettings; /// /// Amount of collider shrinking (along the various shift's) to do before trying to shift depenetrate. /// [SerializeField] public float AutoSkinnedShrinkAmount = 0.5f; [Tooltip("Enables using bone position distances during pairing of bones. (AutoSkinnedPairedDistanceDelta controls the distance when enabled.")] [SerializeField] public bool AutoSkinnedUseDistanceDeltaPairing = true; [Tooltip("Max distance difference between possible bone pairs to still be considered as a pair. Checked along with length of child bone-chain.")] [SerializeField] public float AutoSkinnedPairedDistanceDelta = 0.01f; /// /// The way we should sort the bone list in auto-skinned. /// [SerializeField] public SKINNED_MESH_DEPENETRATE_ORDER AutoSkinnedDepenetrateOrder; /// /// Key to hold before box selection to only add vertices in the box. /// [SerializeField] public KeyCode BoxSelectPlusKey; /// /// Key to hold before box selection to only remove vertices in the box. /// [SerializeField] public KeyCode BoxSelectMinusKey; /// /// Capsule collider generation method to use when creating a capsule collider. /// [SerializeField] public CAPSULE_COLLIDER_METHOD CapsuleColliderMethod; /// /// when enabled, when generating multiple convex mesh colliders with vhacd, they are all combined and stored in a single asset file. /// [SerializeField] public bool CombinedVHACDColliders; /// /// A helpful common multiplier for all scales when using any scaling method. /// [SerializeField] public float CommonScalingMultiplier = 1.0f; /// /// should created meshes used in convex mesh colliders be read/write enabled /// [SerializeField] public bool ConvexMeshReadWriteEnabled = true; [Tooltip("Default scale of the displayed boxes / gizmos around vertices. Combined with common scaling multiplier.")] /// /// Default scale of displayed vertices used along with the common scaling multiplier. /// [SerializeField] public float DefaultScale = 0.01f; /// /// scale for vertices that are hovered / will be added to the selected vertices /// [SerializeField] public float HoveredScaleMult = 1.0f; /// /// scale multiplier for vertices when using display all vertices /// [SerializeField] public float DisplayAllScaleMult = 1.0f; /// /// scale multiplier for vertices that will be removed from the selected vertices /// [SerializeField] public float OverlapScaleMult = 1.0f; /// /// scale multiplier for vertices that are currently selected. /// [SerializeField] public float SelectedScaleMult = 1.0f; /// /// The method to use when creating a collider: if and how a gameobject should be made to hold the collider. /// [SerializeField] public COLLIDER_HOLDER ColliderHolder = COLLIDER_HOLDER.Default; /// /// key to press to create from the current preview. /// [SerializeField] public KeyCode CreateFromPreviewKey; /// /// Should cylinder orientation field apply to capsules as well. /// [SerializeField] public bool CylinderAsCapsuleOrientation = false; /// /// number of sides when creating a cylinder collider. /// [SerializeField] public int CylinderNumberOfSides = 16; /// /// Method to use to decide which axis a cylinder should be oriented on. /// [SerializeField] public CYLINDER_ORIENTATION CylinderOrientation; /// /// Offset in degrees when creating a cylinder. /// [SerializeField] public float CylinderRotationOffset = 0.0f; /// /// Should tips be displayed? /// [SerializeField] public bool DisplayTips; /// /// Should we display compute shader / gizmos on all the vertices? /// [SerializeField] public bool DisplayAllVertices; /// /// Display vertices colour /// [SerializeField] public Color DisplayVerticesColour; [SerializeField] public bool EnableVertexToolsShortcuts = true; /// /// Type of gizmos to use when drawing gizmos for vertices /// public GIZMO_TYPE GizmoType; /// /// Hover vertices scaling colour /// [SerializeField] public Color HoverVertColour; /// /// Number of points to generate around a rounded portion of a collider like sphere or capsules /// [SerializeField] public int MergeCollidersRoundnessAccuracy = 10; /// /// Method to use when generating mesh colliders /// [SerializeField] public MESH_COLLIDER_METHOD MeshColliderMethod; /// /// Overlapped vertice scaling colour /// [SerializeField] public Color OverlapSelectedVertColour; /// /// Key used to select points (any point on a mesh that isn't a vertex) /// [SerializeField] public KeyCode PointSelectKeyCode; [SerializeField] public bool PopupDialogOnFinish; /// /// Collider type we want to preview /// [SerializeField] public CREATE_COLLIDER_TYPE PreviewColliderType; /// /// Color of lines to draw previewed colliders with. /// [SerializeField] public Color PreviewDrawColor; /// /// Are previews enabled? /// [SerializeField] public bool PreviewEnabled; /// /// Raycast delay time, ie only check / select at increments of this time. /// [SerializeField] public float RaycastDelayTime; /// /// Render point method /// [SerializeField] public RENDER_POINT_TYPE RenderPointType; /// /// Should colliders that are merged together be removed after merging is completed? /// [SerializeField] public bool RemoveMergedColliders; /// /// If true, puts rotated colliders on the same layer as the selected gameobject. /// [SerializeField] public bool CopyParentObjectLayer; /// /// Should the rotated colliders pivot be created at the center of the points, or at 0? /// [SerializeField] public bool RotatedColliderPivotAtCenter; /// /// Settings of the current rotate and duplicate section in collider creation. /// [SerializeField] public EasyColliderRotateDuplicate rotatedDupeSettings; /// /// When true, meshes created from creating convex hulls are saved as assets. /// [SerializeField] public bool SaveConvexHullAsAsset; /// /// Specifies how to search for a location to save the convex hull .asset files. /// [SerializeField] public CONVEX_HULL_SAVE_METHOD ConvexHullSaveMethod = CONVEX_HULL_SAVE_METHOD.PrefabMesh; /// /// if SaveConvexHullMeshAtSelected is false, saves at the path specified. /// [SerializeField] public string SaveConvexHullPath; /// /// Provides a subfolder to save colliders in an asset path when saving near the mesh /// IE: if the mesh/prefab is found in an Environments/Meshes folder, an Environments/Meshes/ConvexHulls folder would be created to store the collision meshes /// if using anything other than CONVEX_HULL_SAVE_METHOD.Folder /// [SerializeField] public string SaveConvexHullSubFolder; /// /// Suffix with which to save convex hulls. /// [SerializeField] public string SaveConvexHullSuffix; /// /// Selected vertice scaling colour /// [SerializeField] public Color SelectedVertColour; [SerializeField] public KeyCode ShortcutInvert = KeyCode.I; [SerializeField] public KeyCode ShortcutGrow = KeyCode.G; [SerializeField] public KeyCode ShortcutGrowLast = KeyCode.L; [SerializeField] public KeyCode ShortcutClear = KeyCode.C; [SerializeField] public KeyCode ShortcutRing = KeyCode.R; /// /// Should the number of selected vertices be displayed in the ui? /// [SerializeField] public bool ShowSelectedVertexCount; /// /// Sphere method to use when creating a sphere collider. /// public SPHERE_COLLIDER_METHOD SphereColliderMethod; /// /// Should HandleUtility.GetHandleSize be used when using gizmos to draw to keep gizmo size constant regardless of distance to camera? /// [SerializeField] public bool UseFixedGizmoScale; /// /// Enables using left click to select vertices, and right click to select points. /// [SerializeField] public bool UseMouseClickSelection = true; [SerializeField] public NORMAL_OFFSET VertexNormalOffsetType = NORMAL_OFFSET.Both; /// /// Amount to offset the vertex (in direction of it's averaged normal) /// [SerializeField] public float VertexNormalOffset = 0f; /// /// Amount to inset the vertex (in opposite direction of it's averaged normal) /// [SerializeField] public float VertexNormalInset = 0f; /// /// Method used when raycasting for closest vertices, add (only snap to unselected verts), remove (only snap to selected verts), both (default) /// [SerializeField] public VERTEX_SNAP_METHOD VertexSnapMethod; /// /// Key used to select vertices. /// [SerializeField] public KeyCode VertSelectKeyCode; /// /// Should we update the VHACD calculation and preview as parameters change? /// [SerializeField] public bool VHACDPreview; /// /// For editor window tab tracking, maintains previously open tab. /// [SerializeField] public ECE_WINDOW_TAB CurrentWindowTab; /// /// Sets all values to default values. /// public void SetDefaultValues() { #region VHACD settings #if (!UNITY_EDITOR_LINUX) VHACDParameters = new VHACDParameters(); VHACDPreview = true; #endif #endregion #region other settings AutoIncludeChildSkinnedMeshes = true; AutoSelectOnPrefabOpen = false; DisplayTips = true; DisplayAllVertices = false; PopupDialogOnFinish = false; PreviewEnabled = true; RaycastDelayTime = 0.1f; ShowSelectedVertexCount = false; rotatedDupeSettings = new EasyColliderRotateDuplicate(); RotatedColliderPivotAtCenter = false; CylinderAsCapsuleOrientation = false; #endregion #region autoskinned preferences AutoSkinnedMinBoneWeight = 0.5f; AutoSkinnedDepenetrate = false; AutoSkinnedIterativeDepenetrationCount = 15; AutoSkinnedPairing = true; AutoSkinnedIndents = true; AutoSkinnedColliderType = SKINNED_MESH_COLLIDER_TYPE.Box; AutoSkinnedShrinkAmount = 0.5f; // I find outside in to give the best results generally. AutoSkinnedDepenetrateOrder = SKINNED_MESH_DEPENETRATE_ORDER.OutsideIn; AutoSkinnedForce256Triangles = true; AutoSkinnedUseDistanceDeltaPairing = true; AutoSkinnedPairedDistanceDelta = 0.01f; #endregion #region inputs // shifts do not work. BoxSelectMinusKey = KeyCode.S; BoxSelectPlusKey = KeyCode.A; CreateFromPreviewKey = KeyCode.BackQuote; PointSelectKeyCode = KeyCode.B; UseMouseClickSelection = true; VertSelectKeyCode = KeyCode.V; EnableVertexToolsShortcuts = true; ShortcutInvert = KeyCode.I; ShortcutGrow = KeyCode.G; ShortcutGrowLast = KeyCode.L; ShortcutClear = KeyCode.C; ShortcutRing = KeyCode.R; #endregion #region Collider Methods CapsuleColliderMethod = CAPSULE_COLLIDER_METHOD.MinMax; MeshColliderMethod = MESH_COLLIDER_METHOD.QuickHull; PreviewColliderType = CREATE_COLLIDER_TYPE.BOX; SphereColliderMethod = SPHERE_COLLIDER_METHOD.MinMax; #endregion #region Collider Settings / Paramaters MergeCollidersRoundnessAccuracy = 10; VertexNormalOffset = 0f; VertexNormalInset = 0f; VertexNormalOffsetType = NORMAL_OFFSET.Both; ColliderHolder = COLLIDER_HOLDER.Default; CylinderNumberOfSides = 16; CylinderOrientation = CYLINDER_ORIENTATION.Automatic; CylinderRotationOffset = 0.0f; MeshColliderMethod = MESH_COLLIDER_METHOD.QuickHull; RemoveMergedColliders = true; CopyParentObjectLayer = true; #endregion #region drawing CommonScalingMultiplier = 1.0f; DefaultScale = 0.01f; HoveredScaleMult = 1.0f; DisplayAllScaleMult = 1.0f; OverlapScaleMult = 1.0f; SelectedScaleMult = 1.0f; DisplayVerticesColour = Color.blue; GizmoType = GIZMO_TYPE.SPHERE; HoverVertColour = Color.cyan; OverlapSelectedVertColour = Color.red; PreviewDrawColor = Color.cyan; if (SystemInfo.graphicsShaderLevel < 45) { RenderPointType = RENDER_POINT_TYPE.GIZMOS; } else { RenderPointType = RENDER_POINT_TYPE.SHADER; } SelectedVertColour = Color.green; UseFixedGizmoScale = true; #endregion #region Save Convex Hull Settings ConvexHullSaveMethod = CONVEX_HULL_SAVE_METHOD.PrefabMesh; ResetDefaultSavePath(); SaveConvexHullAsAsset = true; SaveConvexHullSuffix = "_ConvexHull_"; ConvexMeshReadWriteEnabled = true; SaveConvexHullSubFolder = ""; #endregion } private static EasyColliderPreferences _Prefereneces; public static EasyColliderPreferences Preferences { get { if (_Prefereneces == null) { // lazy load preferences when needed. _Prefereneces = FindOrCreatePreferences(); } return _Prefereneces; } } private static EasyColliderPreferences FindOrCreatePreferences() { EasyColliderPreferences preferences; string[] ecp = AssetDatabase.FindAssets("EasyColliderPreferences t:ScriptableObject"); string assetPath = ""; if (ecp.Length > 0) { assetPath = AssetDatabase.GUIDToAssetPath(ecp[0]); if (ecp.Length > 1) { Debug.LogWarning("Easy Collider Editor has found multiple preferences files. Using the one located at " + assetPath); } preferences = AssetDatabase.LoadAssetAtPath(assetPath, typeof(EasyColliderPreferences)) as EasyColliderPreferences; } else { ecp = AssetDatabase.FindAssets("EasyColliderWindow t:script"); if (ecp.Length > 0) { assetPath = AssetDatabase.GUIDToAssetPath(ecp[0]); if (ecp.Length > 1) { Debug.LogWarning("Easy Collider Editor has found multiple preferences files. Using the one located at " + assetPath); } } // preferences = AssetDatabase.LoadAssetAtPath(assetPath, typeof(EasyColliderPreferences)) as EasyColliderPreferences; // Create a new preferences file. string prefPath = assetPath.Remove(assetPath.Length - 21) + "EasyColliderPreferences.asset"; preferences = CreateInstance(); preferences.SetDefaultValues(); AssetDatabase.CreateAsset(preferences, prefPath); AssetDatabase.SaveAssets(); Debug.LogWarning("Easy Collider Editor did not find a preferences file, new preferences file created at " + prefPath); } return preferences; } static string defaultFolderName = "Convex Hulls"; /// /// Resets the default save path to the location of the preferences scriptable object. /// public bool ResetDefaultSavePath() { // path to this preferences object. SaveConvexHullPath = AssetDatabase.GetAssetPath(MonoScript.FromScriptableObject(this)); SaveConvexHullPath = SaveConvexHullPath.Remove(SaveConvexHullPath.LastIndexOf("/")) + "/"; string rootPath = SaveConvexHullPath.Remove(SaveConvexHullPath.LastIndexOf("/Scripts/"), 9); // if the preferences is in soemthing other than Assets (like packages, create a new folder at the root to hold convex hulls) if (!SaveConvexHullPath.StartsWith("Assets")) { if (!AssetDatabase.IsValidFolder("Assets/Convex Hulls")) { AssetDatabase.CreateFolder("Assets", "Convex Hulls"); AssetDatabase.Refresh(); Debug.LogWarning("A folder has been created at: Assets/Convex Hulls to save convex mesh collider assets because Easy Collider exists in the packages folder. Folder to save assets in can be changed in Easy Collider Editor's preferences foldout."); } SaveConvexHullPath = "Assets/Convex Hulls/"; return true; } // remove invalid characters. SaveConvexHullPath = string.Join("", SaveConvexHullPath.Split(Path.GetInvalidPathChars())); // try creating and saving a Convex Hull specific folder if it doesn't exist. if (!AssetDatabase.IsValidFolder(rootPath + "/" + defaultFolderName)) { AssetDatabase.CreateFolder(rootPath, defaultFolderName); AssetDatabase.Refresh(); if (AssetDatabase.IsValidFolder(rootPath + "/" + defaultFolderName)) { SaveConvexHullPath = rootPath + "/" + defaultFolderName + "/"; return true; } } else { SaveConvexHullPath = rootPath + "/" + defaultFolderName + "/"; } return false; } public int GetCreationValuesHashCode() { return 0; } } } #endif