BITFALL/Assets/MagicaCloth2/Scripts/Editor/Cloth/MagicaClothEditor.cs

871 lines
40 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// Magica Cloth 2.
// Copyright (c) 2023 MagicaSoft.
// https://magicasoft.jp
using UnityEditor;
using UnityEngine;
namespace MagicaCloth2
{
/// <summary>
/// MagicaClothコンポーネントのエディタ拡張
/// </summary>
[CustomEditor(typeof(MagicaCloth))]
[CanEditMultipleObjects]
public class MagicaClothEditor : Editor
{
//=========================================================================================
private void Awake()
{
// 選択のたびに呼ばれるのでMonoの動作とは異なる
//Debug.Log("MagicaClothEditor.Awake");
}
private void OnEnable()
{
//Debug.Log("MagicaClothEditor.OnEnable");
ClothEditorManager.OnEditMeshBuildComplete += OnEditMeshBuildComplete;
}
private void OnDisable()
{
//Debug.Log("MagicaClothEditor.OnDisable");
ClothEditorManager.OnEditMeshBuildComplete -= OnEditMeshBuildComplete;
ClothPainter.ExitPaint();
}
private void OnDestroy()
{
// 選択が外れるたびに呼ばれるのでMonoの動作とは異なる
//Debug.Log("MagicaClothEditor.OnDestroy");
//Debug.Log(target != null);
}
private void OnValidate()
{
// どうもMonoのValidateは違う
//Debug.Log("MagicaClothEditor.OnValidate");
}
private void Reset()
{
//Debug.Log("MagicaClothEditor.Reset");
}
//=========================================================================================
int oldAcitve = -1;
//=========================================================================================
/// <summary>
/// 編集用のセレクションデータを取得する
/// </summary>
/// <param name="cloth"></param>
/// <param name="editMesh"></param>
/// <returns></returns>
public SelectionData GetSelectionData(MagicaCloth cloth, VirtualMesh editMesh)
{
// すでにセレクションデータが存在し、かつユーザー編集データならばコンバートする
var selectionData = ClothEditorManager.CreateAutoSelectionData(cloth, cloth.SerializeData, editMesh);
if (cloth.GetSerializeData2().selectionData != null && cloth.GetSerializeData2().selectionData.userEdit)
{
//Debug.Log($"セレクションデータコンバート!");
selectionData.ConvertFrom(cloth.GetSerializeData2().selectionData);
selectionData.userEdit = true;
}
return selectionData;
}
/// <summary>
/// エディットメッシュの構築完了通知(成否問わず)
/// </summary>
void OnEditMeshBuildComplete()
{
//Debug.Log($"MagicaClothInspector. OnEditMeshBuildComplete.");
Repaint();
}
/// <summary>
/// インスペクターGUI
/// </summary>
public override void OnInspectorGUI()
{
var cloth = target as MagicaCloth;
// 状態
DispVersion();
DispStatus();
DispProxyMesh();
// 設定
serializedObject.Update();
Undo.RecordObject(cloth, "MagicaCloth2");
EditorGUILayout.Space();
ClothMainInspector();
EditorGUILayout.Space();
EditorGUILayout.Space();
EditorGUILayout.Space();
EditorGUILayout.Space();
EditorGUILayout.Space();
ClothParameterInspector();
EditorGUILayout.Space();
EditorGUILayout.Space();
GizmoInspector();
EditorGUILayout.Space();
ClothPreBuildInspector();
serializedObject.ApplyModifiedProperties();
//DrawDefaultInspector();
// アクティブが変更された場合は編集メッシュを再構築する
int nowActive = cloth.isActiveAndEnabled ? 1 : 0;
if (nowActive != oldAcitve)
{
//Debug.Log($"[{cloth.name}] rebuild. active:{nowActive}");
oldAcitve = nowActive;
ClothEditorManager.RegisterComponent(cloth, nowActive > 0 ? GizmoType.Active : 0, true);
}
}
/// <summary>
/// クロスペイントの適用
/// </summary>
/// <param name="selectiondata"></param>
internal void ApplyClothPainter(SelectionData selectionData)
{
if (selectionData == null || selectionData.IsValid() == false)
return;
var cloth = target as MagicaCloth;
// セレクションデータ格納
ClothEditorManager.ApplySelectionData(cloth, selectionData);
}
/// <summary>
/// クロスペイントの変更による編集メッシュの再構築
/// </summary>
internal void UpdateEditMesh()
{
var cloth = target as MagicaCloth;
// 編集用メッシュの再構築
ClothEditorManager.RegisterComponent(cloth, GizmoType.Active, true); // 強制更新
}
//=========================================================================================
void DispVersion()
{
EditorGUILayout.LabelField($"Version {AboutMenu.MagicaClothVersion}");
//using (new EditorGUILayout.HorizontalScope())
//{
// //GUILayout.FlexibleSpace();
// EditorGUILayout.Space();
// EditorGUILayout.LabelField($"Version {AboutMenu.MagicaClothVersion}", GUILayout.Width(100));
//}
}
void DispStatus()
{
var cloth = target as MagicaCloth;
if (EditorApplication.isPlaying)
{
StaticStringBuilder.Clear();
StaticStringBuilder.AppendLine("[State]");
StaticStringBuilder.Append(cloth.Process.IsState(ClothProcess.State_UsePreBuild) ? "Pre-Build Construction" : "Runtime Construction");
DispClothStatus(StaticStringBuilder.ToString(), cloth.Process.Result, true);
}
else
{
var preBuildData = cloth.GetSerializeData2().preBuildData;
if (preBuildData.enabled)
{
// pre-build
DispClothStatus("[Pre-Build Construction]", preBuildData.DataValidate(), false);
}
else
{
// runtime
DispClothStatus("[Runtime Construction]", ClothEditorManager.GetResultCode(cloth), true);
}
}
}
void DispClothStatus(string title, ResultCode result, bool dispWarning)
{
StaticStringBuilder.Clear();
StaticStringBuilder.AppendLine(title);
// normal / error
MessageType mtype = MessageType.Info;
if (result.IsError())
mtype = MessageType.Error;
var infoMessage = result.GetResultInformation();
if (infoMessage != null)
{
StaticStringBuilder.AppendLine(result.GetResultString());
StaticStringBuilder.AppendLine(infoMessage);
}
else
{
StaticStringBuilder.AppendLine(result.GetResultString());
}
EditorGUILayout.HelpBox(StaticStringBuilder.ToString(), mtype);
// warning
if (dispWarning && result.IsWarning())
{
mtype = MessageType.Warning;
infoMessage = result.GetWarningInformation();
if (infoMessage != null)
EditorGUILayout.HelpBox($"{result.GetWarningString()}\n{infoMessage}", mtype);
else
EditorGUILayout.HelpBox(result.GetWarningString(), mtype);
}
}
void DispProxyMesh()
{
var cloth = target as MagicaCloth;
VirtualMeshContainer cmesh;
if (EditorApplication.isPlaying)
{
cmesh = cloth.Process?.ProxyMeshContainer;
}
else
{
cmesh = ClothEditorManager.GetEditMeshContainer(cloth);
}
if (cmesh == null || cmesh.shareVirtualMesh == null)
return;
var vmesh = cmesh.shareVirtualMesh;
StaticStringBuilder.Clear();
if (EditorApplication.isPlaying)
StaticStringBuilder.AppendLine("[Proxy Mesh]");
else
StaticStringBuilder.AppendLine("[Edit Mesh]");
if (EditorApplication.isPlaying)
StaticStringBuilder.AppendLine($"Visible: {!cloth.Process.IsCullingInvisible()}");
StaticStringBuilder.AppendLine($"Vertex: {vmesh.VertexCount}");
StaticStringBuilder.AppendLine($"Edge: {vmesh.EdgeCount}");
StaticStringBuilder.AppendLine($"Triangle: {vmesh.TriangleCount}");
StaticStringBuilder.AppendLine($"SkinBoneCount: {vmesh.SkinBoneCount}");
StaticStringBuilder.Append($"TransformCount: {cmesh.GetTransformCount()}");
EditorGUILayout.HelpBox(StaticStringBuilder.ToString(), MessageType.Info);
}
void ClothMainInspector()
{
var cloth = target as MagicaCloth;
var clothType = cloth.SerializeData.clothType;
bool isBoneSpring = clothType == ClothProcess.ClothType.BoneSpring;
bool runtime = EditorApplication.isPlaying;
// 同期状態
bool sync = EditorApplication.isPlaying && cloth.SyncCloth != null;
EditorGUILayout.LabelField("Main", EditorStyles.boldLabel);
// Cloth
{
var clothTypeProperty = serializedObject.FindProperty("serializeData.clothType");
using (new EditorGUI.DisabledScope(runtime))
{
EditorGUILayout.PropertyField(clothTypeProperty, new GUIContent("Cloth Type"));
}
var paintMode = serializedObject.FindProperty("serializeData.paintMode");
using (new EditorGUI.IndentLevelScope())
{
if (clothType == ClothProcess.ClothType.BoneCloth)
{
EditorGUILayout.PropertyField(serializedObject.FindProperty("serializeData.rootBones"));
EditorGUILayout.PropertyField(serializedObject.FindProperty("serializeData.connectionMode"));
EditorGUILayout.PropertyField(serializedObject.FindProperty("serializeData.rootRotation"));
EditorGUILayout.PropertyField(serializedObject.FindProperty("serializeData.rotationalInterpolation"));
}
else if (clothType == ClothProcess.ClothType.BoneSpring)
{
EditorGUILayout.PropertyField(serializedObject.FindProperty("serializeData.rootBones"));
// BoneSpringでは接続モードは指定させない。内部ではLineで固定される。
using (new EditorGUILayout.HorizontalScope())
{
EditorGUILayout.LabelField("ConnectionMode");
EditorGUILayout.LabelField("[Line]");
}
EditorGUILayout.PropertyField(serializedObject.FindProperty("serializeData.rootRotation"));
EditorGUILayout.PropertyField(serializedObject.FindProperty("serializeData.rotationalInterpolation"));
}
else if (clothType == ClothProcess.ClothType.MeshCloth)
{
EditorGUILayout.PropertyField(serializedObject.FindProperty("serializeData.sourceRenderers"));
EditorGUILayout.PropertyField(serializedObject.FindProperty("serializeData.reductionSetting"));
}
EditorGUILayout.Space();
EditorGUILayout.PropertyField(serializedObject.FindProperty("serializeData.updateMode"));
EditorGUILayout.PropertyField(serializedObject.FindProperty("serializeData.animationPoseRatio"));
EditorGUILayout.PropertyField(serializedObject.FindProperty("serializeData.normalAxis"));
EditorGUILayout.PropertyField(serializedObject.FindProperty("serializeData.normalAlignmentSetting.alignmentMode"), new GUIContent("Normal Alignment"));
if (cloth.SerializeData.normalAlignmentSetting.alignmentMode == NormalAlignmentSettings.AlignmentMode.Transform)
{
EditorGUILayout.PropertyField(serializedObject.FindProperty("serializeData.normalAlignmentSetting.adjustmentTransform"));
}
if (clothType == ClothProcess.ClothType.MeshCloth)
{
EditorGUILayout.Space();
EditorGUILayout.PropertyField(paintMode);
if (paintMode.enumValueIndex != 0)
{
EditorGUILayout.PropertyField(serializedObject.FindProperty("serializeData.paintMaps"));
}
}
}
// ペイントボタン
if (paintMode.enumValueIndex == 0)
{
EditorGUILayout.Space();
PaintButton(ClothPainter.PaintMode.Attribute);
}
else
EditorGUILayout.Space();
}
// Custom Skinning
if (isBoneSpring == false)
{
Foldout("Custom Skinning", serializedObject.FindProperty("serializeData.customSkinningSetting.enable"), null, () =>
{
EditorGUILayout.PropertyField(serializedObject.FindProperty("serializeData.customSkinningSetting.skinningBones"));
});
}
// Culling
Foldout("Culling", null, () =>
{
if (sync == false)
{
EditorGUILayout.PropertyField(serializedObject.FindProperty("serializeData.cullingSettings.cameraCullingMode"));
EditorGUILayout.PropertyField(serializedObject.FindProperty("serializeData.cullingSettings.cameraCullingMethod"));
if (cloth.SerializeData.cullingSettings.cameraCullingMethod == CullingSettings.CameraCullingMethod.ManualRenderer)
{
EditorGUILayout.PropertyField(serializedObject.FindProperty("serializeData.cullingSettings.cameraCullingRenderers"));
}
}
else
{
// 同期中は操作不可
using (new EditorGUI.DisabledScope(true))
{
using (new EditorGUILayout.HorizontalScope())
{
EditorGUILayout.LabelField("Camera Culling Mode");
EditorGUILayout.LabelField("(Synchronizing)");
}
using (new EditorGUILayout.HorizontalScope())
{
EditorGUILayout.LabelField("Camera Culling Method");
EditorGUILayout.LabelField("(Synchronizing)");
}
}
}
});
}
void ClothPreBuildInspector()
{
var cloth = target as MagicaCloth;
bool generation = false;
using (new EditorGUI.DisabledScope(EditorApplication.isPlaying))
{
Foldout("Pre-Build", serializedObject.FindProperty("serializeData2.preBuildData.enabled"), null, () =>
{
// information
var preBuildData = cloth.GetSerializeData2().preBuildData;
if (preBuildData.UsePreBuild())
{
DispClothStatus("[Pre-Build Construction]", preBuildData.DataValidate(), false);
}
EditorGUILayout.PropertyField(serializedObject.FindProperty("serializeData2.preBuildData.buildId"), new GUIContent("Build ID"));
EditorGUILayout.PropertyField(serializedObject.FindProperty("serializeData2.preBuildData.preBuildScriptableObject"), new GUIContent("Write Object"));
using (var horizontalScope = new GUILayout.HorizontalScope())
{
EditorGUILayout.Space();
GUI.backgroundColor = Color.red;
if (GUILayout.Button("Create PreBuild Data"))
{
generation = true;
}
GUI.backgroundColor = Color.white;
EditorGUILayout.Space();
}
});
}
if (generation)
{
// PreBuildデータ構築実行
Develop.Log($"Start PreBuild data creation.");
var preBuildResult = PreBuildDataCreation.CreatePreBuildData(cloth);
Develop.Log($"PreBuild data creation completed. [{cloth.GetSerializeData2().preBuildData.buildId}] : {preBuildResult.GetResultString()}");
}
}
void ClothParameterInspector()
{
var cloth = target as MagicaCloth;
var clothType = cloth.SerializeData.clothType;
bool isBoneSpring = clothType == ClothProcess.ClothType.BoneSpring;
// 同期状態
bool sync = EditorApplication.isPlaying && cloth.SyncCloth != null;
ClothPresetUtility.DrawPresetButton(cloth, cloth.SerializeData);
// Force
Foldout("Force", null, () =>
{
if (isBoneSpring == false)
{
EditorGUILayout.PropertyField(serializedObject.FindProperty("serializeData.gravity"), new GUIContent("Gravity"));
EditorGUILayout.PropertyField(serializedObject.FindProperty("serializeData.gravityDirection"));
EditorGUILayout.PropertyField(serializedObject.FindProperty("serializeData.gravityFalloff"));
}
EditorGUILayout.PropertyField(serializedObject.FindProperty("serializeData.damping"));
EditorGUILayout.PropertyField(serializedObject.FindProperty("serializeData.stablizationTimeAfterReset"), new GUIContent("Stablization Time"));
});
// Spring
if (isBoneSpring)
{
Foldout("Spring", serializedObject.FindProperty("serializeData.springConstraint.useSpring"), null, () =>
{
EditorGUILayout.PropertyField(serializedObject.FindProperty("serializeData.springConstraint.springPower"));
EditorGUILayout.PropertyField(serializedObject.FindProperty("serializeData.springConstraint.limitDistance"));
EditorGUILayout.PropertyField(serializedObject.FindProperty("serializeData.springConstraint.normalLimitRatio"));
EditorGUILayout.PropertyField(serializedObject.FindProperty("serializeData.springConstraint.springNoise"));
});
}
// Angle Restoration
Foldout("Angle Restoration", serializedObject.FindProperty("serializeData.angleRestorationConstraint.useAngleRestoration"), null, () =>
{
EditorGUILayout.PropertyField(serializedObject.FindProperty("serializeData.angleRestorationConstraint.stiffness"));
EditorGUILayout.PropertyField(serializedObject.FindProperty("serializeData.angleRestorationConstraint.velocityAttenuation"));
if (isBoneSpring == false)
{
EditorGUILayout.PropertyField(serializedObject.FindProperty("serializeData.angleRestorationConstraint.gravityFalloff"));
}
}
);
// Angle Limit
Foldout("Angle Limit", serializedObject.FindProperty("serializeData.angleLimitConstraint.useAngleLimit"), null, () =>
{
EditorGUILayout.PropertyField(serializedObject.FindProperty("serializeData.angleLimitConstraint.limitAngle"));
EditorGUILayout.PropertyField(serializedObject.FindProperty("serializeData.angleLimitConstraint.stiffness"));
}
);
// Shape
// BoneSpringではすべて定数なので隠蔽する
if (isBoneSpring == false)
{
Foldout("Shape Restoration", null, () =>
{
EditorGUILayout.PropertyField(serializedObject.FindProperty("serializeData.distanceConstraint.stiffness"), new GUIContent("Distance Stiffness"));
EditorGUILayout.PropertyField(serializedObject.FindProperty("serializeData.tetherConstraint.distanceCompression"), new GUIContent("Tether Compression"));
EditorGUILayout.PropertyField(serializedObject.FindProperty("serializeData.triangleBendingConstraint.stiffness"), new GUIContent("Triangle Bending Stiffness"));
});
}
// Inertia
Foldout("Inertia", null, () =>
{
if (sync == false)
{
EditorGUILayout.PropertyField(serializedObject.FindProperty("serializeData.inertiaConstraint.worldInertia"));
EditorGUILayout.PropertyField(serializedObject.FindProperty("serializeData.inertiaConstraint.movementSpeedLimit"), new GUIContent("World Movement Speed Limit"));
EditorGUILayout.PropertyField(serializedObject.FindProperty("serializeData.inertiaConstraint.rotationSpeedLimit"), new GUIContent("World Rotation Speed Limit"));
EditorGUILayout.PropertyField(serializedObject.FindProperty("serializeData.inertiaConstraint.teleportMode"));
EditorGUILayout.PropertyField(serializedObject.FindProperty("serializeData.inertiaConstraint.teleportDistance"));
EditorGUILayout.PropertyField(serializedObject.FindProperty("serializeData.inertiaConstraint.teleportRotation"));
}
else
{
// 同期中は操作不可
using (new EditorGUI.DisabledScope(true))
{
using (new EditorGUILayout.HorizontalScope())
{
EditorGUILayout.LabelField("World Inertia");
EditorGUILayout.LabelField("(Synchronizing)");
}
using (new EditorGUILayout.HorizontalScope())
{
EditorGUILayout.LabelField("World Movement Speed Limit");
EditorGUILayout.LabelField("(Synchronizing)");
}
using (new EditorGUILayout.HorizontalScope())
{
EditorGUILayout.LabelField("World Rotation Speed Limit");
EditorGUILayout.LabelField("(Synchronizing)");
}
using (new EditorGUILayout.HorizontalScope())
{
EditorGUILayout.LabelField("Teleport Mode");
EditorGUILayout.LabelField("(Synchronizing)");
}
using (new EditorGUILayout.HorizontalScope())
{
EditorGUILayout.LabelField("Teleport Distance");
EditorGUILayout.LabelField("(Synchronizing)");
}
using (new EditorGUILayout.HorizontalScope())
{
EditorGUILayout.LabelField("Teleport Rotation");
EditorGUILayout.LabelField("(Synchronizing)");
}
}
}
EditorGUILayout.Space();
EditorGUILayout.PropertyField(serializedObject.FindProperty("serializeData.inertiaConstraint.localInertia"), new GUIContent("Local Inertia"));
EditorGUILayout.PropertyField(serializedObject.FindProperty("serializeData.inertiaConstraint.localMovementSpeedLimit"));
EditorGUILayout.PropertyField(serializedObject.FindProperty("serializeData.inertiaConstraint.localRotationSpeedLimit"));
EditorGUILayout.PropertyField(serializedObject.FindProperty("serializeData.inertiaConstraint.depthInertia"), new GUIContent("Local Depth Inertia"));
EditorGUILayout.PropertyField(serializedObject.FindProperty("serializeData.inertiaConstraint.centrifualAcceleration"));
EditorGUILayout.PropertyField(serializedObject.FindProperty("serializeData.inertiaConstraint.particleSpeedLimit"));
});
// Motion
if (isBoneSpring == false)
{
Foldout("Movement Limit", null, () =>
{
var useMaxDistance = serializedObject.FindProperty("serializeData.motionConstraint.useMaxDistance");
var useBackstop = serializedObject.FindProperty("serializeData.motionConstraint.useBackstop");
EditorGUILayout.PropertyField(useMaxDistance);
using (new EditorGUI.DisabledScope(!useMaxDistance.boolValue))
{
EditorGUILayout.PropertyField(serializedObject.FindProperty("serializeData.motionConstraint.maxDistance"));
}
EditorGUILayout.PropertyField(useBackstop);
using (new EditorGUI.DisabledScope(!useBackstop.boolValue))
{
EditorGUILayout.PropertyField(serializedObject.FindProperty("serializeData.motionConstraint.backstopRadius"));
EditorGUILayout.PropertyField(serializedObject.FindProperty("serializeData.motionConstraint.backstopDistance"));
}
EditorGUILayout.PropertyField(serializedObject.FindProperty("serializeData.motionConstraint.stiffness"));
var paintMode = serializedObject.FindProperty("serializeData.paintMode");
if (paintMode.enumValueIndex == 0)
PaintButton(ClothPainter.PaintMode.Motion);
}
);
}
// Collider Collision
Foldout("Collider Collision", null, () =>
{
if (isBoneSpring)
{
using (new EditorGUILayout.HorizontalScope())
{
EditorGUILayout.LabelField("Mode");
EditorGUILayout.LabelField("[Point]");
}
}
else
{
EditorGUILayout.PropertyField(serializedObject.FindProperty("serializeData.colliderCollisionConstraint.mode"));
}
EditorGUILayout.PropertyField(serializedObject.FindProperty("serializeData.radius"));
if (clothType == ClothProcess.ClothType.BoneSpring)
{
EditorGUILayout.PropertyField(serializedObject.FindProperty("serializeData.colliderCollisionConstraint.limitDistance"));
EditorGUILayout.PropertyField(serializedObject.FindProperty("serializeData.colliderCollisionConstraint.collisionBones"));
}
else
{
EditorGUILayout.PropertyField(serializedObject.FindProperty("serializeData.colliderCollisionConstraint.friction"));
}
EditorGUILayout.PropertyField(serializedObject.FindProperty("serializeData.colliderCollisionConstraint.colliderList"));
}
);
// Self Collision
if (isBoneSpring == false)
{
Foldout("Self Collision", "Self Collision (Beta)", () =>
{
EditorGUILayout.PropertyField(serializedObject.FindProperty("serializeData.selfCollisionConstraint.selfMode"));
var syncMode = serializedObject.FindProperty("serializeData.selfCollisionConstraint.syncMode");
EditorGUILayout.PropertyField(syncMode);
if (syncMode.enumValueIndex != 0)
{
EditorGUILayout.PropertyField(serializedObject.FindProperty("serializeData.selfCollisionConstraint.syncPartner"));
}
EditorGUILayout.PropertyField(serializedObject.FindProperty("serializeData.selfCollisionConstraint.surfaceThickness"));
EditorGUILayout.PropertyField(serializedObject.FindProperty("serializeData.selfCollisionConstraint.clothMass"));
}
);
}
// Wind
Foldout("Wind", null, () =>
{
EditorGUILayout.PropertyField(serializedObject.FindProperty("serializeData.wind.influence"));
EditorGUILayout.PropertyField(serializedObject.FindProperty("serializeData.wind.frequency"));
EditorGUILayout.PropertyField(serializedObject.FindProperty("serializeData.wind.turbulence"));
EditorGUILayout.PropertyField(serializedObject.FindProperty("serializeData.wind.blend"), new GUIContent("Noise Blend"));
EditorGUILayout.PropertyField(serializedObject.FindProperty("serializeData.wind.synchronization"));
EditorGUILayout.PropertyField(serializedObject.FindProperty("serializeData.wind.depthWeight"));
EditorGUILayout.PropertyField(serializedObject.FindProperty("serializeData.wind.movingWind"));
});
}
/// <summary>
/// 各プロパティの設定範囲.デフォルトは(0.0 ~ 1.0)
/// </summary>
/// <param name="propertyName"></param>
/// <returns></returns>
public static Vector2 GetPropertyMinMax(string propertyName)
{
var minmax = new Vector2(0.0f, 1.0f);
switch (propertyName)
{
case "radius":
minmax.Set(0.001f, 0.5f);
break;
case "limitAngle":
minmax.Set(0.0f, 180.0f);
break;
case "maxDistance":
minmax.Set(0.0f, 5.0f);
break;
case "surfaceThickness":
minmax.Set(Define.System.SelfCollisionThicknessMin, Define.System.SelfCollisionThicknessMax);
break;
case "movementSpeedLimit":
case "localMovementSpeedLimit":
minmax.Set(0.0f, Define.System.MaxMovementSpeedLimit);
break;
case "rotationSpeedLimit":
case "localRotationSpeedLimit":
minmax.Set(0.0f, Define.System.MaxRotationSpeedLimit);
break;
case "particleSpeedLimit":
minmax.Set(0.0f, Define.System.MaxParticleSpeedLimit);
break;
}
return minmax;
}
void GizmoInspector()
{
#if MC2_DEBUG
EditorGUILayout.PropertyField(serializedObject.FindProperty("gizmoSerializeData"));
#else
FoldOut("Gizmos", null, () =>
{
EditorGUILayout.PropertyField(serializedObject.FindProperty("gizmoSerializeData.always"));
EditorGUILayout.PropertyField(serializedObject.FindProperty("gizmoSerializeData.clothDebugSettings.enable"));
EditorGUILayout.PropertyField(serializedObject.FindProperty("gizmoSerializeData.clothDebugSettings.ztest"));
EditorGUILayout.PropertyField(serializedObject.FindProperty("gizmoSerializeData.clothDebugSettings.position"));
EditorGUILayout.PropertyField(serializedObject.FindProperty("gizmoSerializeData.clothDebugSettings.axis"));
EditorGUILayout.PropertyField(serializedObject.FindProperty("gizmoSerializeData.clothDebugSettings.shape"));
EditorGUILayout.PropertyField(serializedObject.FindProperty("gizmoSerializeData.clothDebugSettings.baseLine"));
EditorGUILayout.PropertyField(serializedObject.FindProperty("gizmoSerializeData.clothDebugSettings.depth"));
EditorGUILayout.PropertyField(serializedObject.FindProperty("gizmoSerializeData.clothDebugSettings.collider"));
EditorGUILayout.PropertyField(serializedObject.FindProperty("gizmoSerializeData.clothDebugSettings.animatedPosition"));
EditorGUILayout.PropertyField(serializedObject.FindProperty("gizmoSerializeData.clothDebugSettings.animatedAxis"));
EditorGUILayout.PropertyField(serializedObject.FindProperty("gizmoSerializeData.clothDebugSettings.animatedShape"));
EditorGUILayout.PropertyField(serializedObject.FindProperty("gizmoSerializeData.clothDebugSettings.inertiaCenter"));
//EditorGUILayout.PropertyField(serializedObject.FindProperty("gizmoSerializeData.clothDebugSettings.basicPosition"));
//EditorGUILayout.PropertyField(serializedObject.FindProperty("gizmoSerializeData.clothDebugSettings.basicAxis"));
//EditorGUILayout.PropertyField(serializedObject.FindProperty("gizmoSerializeData.clothDebugSettings.basicShape"));
});
#endif
}
//=========================================================================================
/// <summary>
/// 折りたたみ制御
/// </summary>
/// <param name="foldKey">折りたたみ保存キー</param>
/// <param name="title"></param>
/// <param name="drawAct">内容描画アクション</param>
/// <param name="enableAct">有効フラグアクション(null=無効)</param>
/// <param name="enable">現在の有効フラグ</param>
public void Foldout(
string foldKey,
string title = null,
System.Action drawAct = null,
System.Action<bool> enableAct = null,
bool enable = true
)
{
var style = new GUIStyle("ShurikenModuleTitle");
style.font = new GUIStyle(EditorStyles.label).font;
style.border = new RectOffset(15, 7, 4, 4);
style.fixedHeight = 22;
style.contentOffset = new Vector2(20f, -2f);
var rect = GUILayoutUtility.GetRect(16f, 22f, style);
GUI.backgroundColor = Color.white;
GUI.Box(rect, title ?? foldKey, style);
var e = Event.current;
bool foldOut = EditorPrefs.GetBool(foldKey);
if (enableAct == null)
{
if (e.type == EventType.Repaint)
{
var arrowRect = new Rect(rect.x + 4f, rect.y + 2f, 13f, 13f);
EditorStyles.foldout.Draw(arrowRect, false, false, foldOut, false);
}
}
else
{
// 有効チェック
var toggleRect = new Rect(rect.x + 4f, rect.y + 4f, 13f, 13f);
bool sw = GUI.Toggle(toggleRect, enable, string.Empty, new GUIStyle("ShurikenCheckMark"));
if (sw != enable)
{
enableAct(sw);
}
}
if (e.type == EventType.MouseDown && rect.Contains(e.mousePosition))
{
foldOut = !foldOut;
EditorPrefs.SetBool(foldKey, foldOut);
e.Use();
}
if (foldOut && drawAct != null)
{
using (new EditorGUI.IndentLevelScope())
{
using (new EditorGUI.DisabledScope(!enable))
{
drawAct();
}
}
}
}
/// <summary>
/// 折りたたみ制御Boolプロパティによるチェックあり
/// </summary>
/// <param name="foldKey"></param>
/// <param name="boolProperty"></param>
/// <param name="title"></param>
/// <param name="drawAct"></param>
public void Foldout(
string foldKey,
SerializedProperty boolProperty,
string title = null,
System.Action drawAct = null
)
{
Foldout(
foldKey, title, drawAct,
(sw) => boolProperty.boolValue = sw,
boolProperty.boolValue
);
}
void FoldOut(string key, string title = null, System.Action drawAct = null)
{
bool foldOut1 = EditorPrefs.GetBool(key);
bool foldOut2 = EditorGUILayout.Foldout(foldOut1, title ?? key);
if (foldOut2)
{
using (new EditorGUI.IndentLevelScope())
{
drawAct?.Invoke();
}
}
if (foldOut1 != foldOut2)
{
EditorPrefs.SetBool(key, foldOut2);
}
}
void PaintButton(ClothPainter.PaintMode paintMode)
{
if (EditorApplication.isPlaying)
return;
var cloth = target as MagicaCloth;
using (new EditorGUILayout.HorizontalScope())
{
switch (paintMode)
{
case ClothPainter.PaintMode.Attribute:
GUI.backgroundColor = new Color(0.5f, 1.0f, 0.5f);
break;
case ClothPainter.PaintMode.Motion:
GUI.backgroundColor = new Color(0.0f, 1.0f, 1.0f);
break;
}
EditorGUILayout.Space();
bool edit = ClothPainter.HasEditCloth(cloth);
//var icon = edit ? EditorGUIUtility.IconContent("winbtn_win_close") : EditorGUIUtility.IconContent("d_editicon.sml");
//var icon = EditorGUIUtility.IconContent("d_Grid.PaintTool");// 良い
var icon = EditorGUIUtility.IconContent("d_editicon.sml");
if (GUILayout.Button(icon, GUILayout.Width(40)))
{
if (edit == false)
{
// 最新の編集メッシュからセレクションデータを生成する
var editMeshContainer = ClothEditorManager.GetEditMeshContainer(cloth);
if (editMeshContainer != null && editMeshContainer.shareVirtualMesh != null)
{
// すでにセレクションデータが存在し、かつユーザー編集データならばコンバートする
var selectionData = GetSelectionData(cloth, editMeshContainer.shareVirtualMesh);
// セレクションデータにメッシュの最大接続距離を記録する
selectionData.maxConnectionDistance = editMeshContainer.shareVirtualMesh.maxVertexDistance.Value;
// ペイント開始
ClothPainter.EnterPaint(paintMode, this, cloth, editMeshContainer, selectionData);
SceneView.RepaintAll();
}
}
else
{
ClothPainter.ExitPaint();
SceneView.RepaintAll();
}
}
EditorGUILayout.Space();
GUI.backgroundColor = Color.white;
}
EditorGUILayout.Space(10);
}
}
}