BITFALL/Assets/Plugins/MagicaCloth2/Scripts/Editor/Cloth/ClothEditorManager.cs

960 lines
38 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 System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Unity.Mathematics;
using UnityEditor;
using UnityEditor.Callbacks;
using UnityEditor.Compilation;
#if UNITY_2020
using UnityEditor.Experimental.SceneManagement;
#else
using UnityEditor.SceneManagement;
#endif
using UnityEngine;
namespace MagicaCloth2
{
/// <summary>
/// エディタ編集時のコンポーネント管理
/// </summary>
[InitializeOnLoad]
public class ClothEditorManager
{
/// <summary>
/// コンポーネント情報
/// </summary>
class ClothInfo
{
public ResultCode result = ResultCode.Empty;
public bool building;
public GizmoType gizmoType;
public ClothBehaviour component;
public int componentHash;
public VirtualMesh editMesh;
public int nextBuildHash;
public int importCount;
}
static Dictionary<int, ClothInfo> editClothDict = new Dictionary<int, ClothInfo>();
static List<int> destroyList = new List<int>();
static List<ClothInfo> drawList = new List<ClothInfo>();
static CancellationTokenSource cancelToken = new CancellationTokenSource();
static bool isValid = false;
static internal Action OnEditMeshBuildComplete;
//=========================================================================================
static ClothEditorManager()
{
Develop.DebugLog($"ClothEditorManager Initialize!");
Dispose();
// スクリプトコンパイルコールバック
CompilationPipeline.compilationStarted -= OnStartCompile;
CompilationPipeline.compilationStarted += OnStartCompile;
// シーンビューにGUIを描画するためのコールバック
SceneView.duringSceneGui -= OnSceneGUI;
SceneView.duringSceneGui += OnSceneGUI;
// プレハブステージ
PrefabStage.prefabStageClosing -= OnPrefabStageClosing;
PrefabStage.prefabStageClosing += OnPrefabStageClosing;
// Undo/Redo
Undo.undoRedoPerformed -= OnUndoRedoPerformed;
Undo.undoRedoPerformed += OnUndoRedoPerformed;
isValid = true;
}
/// <summary>
/// エディタの実行状態が変更された場合に呼び出される
/// </summary>
[InitializeOnLoadMethod]
static void PlayModeStateChange()
{
EditorApplication.playModeStateChanged += (mode) =>
{
//Develop.DebugLog($"PlayModeStateChanged:{mode}");
if (mode == UnityEditor.PlayModeStateChange.ExitingEditMode || mode == UnityEditor.PlayModeStateChange.ExitingPlayMode)
{
//Develop.DebugLog($"PlayModeStateChange. Exit Editor mode!");
Dispose();
isValid = false;
}
if (mode == UnityEditor.PlayModeStateChange.EnteredEditMode || mode == UnityEditor.PlayModeStateChange.EnteredPlayMode)
{
//Develop.DebugLog($"PlayModeStateChange. Enter Editor mode!");
isValid = true;
}
};
}
/// <summary>
/// スクリプトコンパイル開始
/// </summary>
/// <param name="obj"></param>
static void OnStartCompile(object obj)
{
Develop.DebugLog($"start compile.");
Dispose();
isValid = false;
}
/// <summary>
/// ビルド完了時
/// </summary>
/// <param name="target"></param>
/// <param name="pathToBuiltProject"></param>
[PostProcessBuildAttribute(1)]
static void OnPostprocessBuild(BuildTarget target, string pathToBuiltProject)
{
Develop.DebugLog($"build compile.");
isValid = true;
}
/// <summary>
/// プレハブステージが閉じる時
/// </summary>
/// <param name="obj"></param>
static void OnPrefabStageClosing(PrefabStage pstage)
{
ForceUpdateAllComponents();
}
/// <summary>
/// Undo/Redo実行時
/// </summary>
static void OnUndoRedoPerformed()
{
ForceUpdateAllComponents();
}
/// <summary>
/// MagidaClothコンポーネントの登録および編集メッシュの作成/更新
/// </summary>
/// <param name="component"></param>
public static void RegisterComponent(ClothBehaviour component, GizmoType gizmoType, bool forceUpdate = false)
{
//Develop.DebugLog($"RegisterComponent:{component.name}, isValid:{isValid}");
if (isValid == false)
return;
if (component == null)
return;
// ペイント中は無効
if (ClothPainter.IsPainting())
return;
int id = component.GetInstanceID();
MagicaCloth cloth = component as MagicaCloth;
//if (cloth)
// Develop.DebugLog($"Register Cloth:{component.name}, gizmoType:{gizmoType}");
// ギズモ表示判定
if (gizmoType.HasFlag(GizmoType.Active))
{
gizmoType = GizmoType.Active;
}
else
{
// ★何故かGizmoType.InSelectionHierarchyが正常に判定できないので手動で解決する(2022/10/14)
// ★GizmoType.InSelectionHierarchyがバグっている
gizmoType = 0;
var t = component.transform.parent;
var activeT = Selection.activeTransform;
if (activeT)
{
while (t)
{
if (t == activeT)
{
gizmoType = GizmoType.Selected;
break;
}
else
t = t.parent;
}
}
// 常に表示
if (cloth && cloth.GizmoSerializeData.IsAlways())
gizmoType = GizmoType.Active;
}
// クロス指定のコライダー表示
if (cloth && cloth.GizmoSerializeData.clothDebugSettings.collider && gizmoType != 0)
{
foreach (var col in cloth.SerializeData.colliderCollisionConstraint.colliderList)
{
RegisterComponent(col, gizmoType);
}
}
lock (editClothDict)
{
if (editClothDict.ContainsKey(id) == false)
{
//Debug.Log($"登録:{component.name}");
var info = new ClothInfo();
info.building = false;
info.result = ResultCode.Empty;
info.component = component;
info.editMesh = null;
info.gizmoType = gizmoType;
info.componentHash = 0;
info.nextBuildHash = 0;
info.importCount = 1;
editClothDict.Add(id, info);
}
else
{
if (gizmoType > editClothDict[id].gizmoType)
editClothDict[id].gizmoType = gizmoType;
}
}
// EditMesh作成(MagicaClothコンポーネントのみ)
if (cloth && EditorApplication.isPlaying == false)
{
int hash = component.GetHashCode();
lock (editClothDict)
{
if (editClothDict.ContainsKey(id))
{
var info = editClothDict[id];
// ハッシュにはインポート回数を乗算する
hash *= (info.importCount + 1);
// ハッシュが異なる場合のみ再構築/もしくは強制更新
if (info.componentHash != hash || forceUpdate)
{
// 現在作成中ならば次の作成候補として登録
if (info.building)
{
info.nextBuildHash = hash;
}
// そうでなければ作成を開始する
else
{
info.componentHash = hash;
info.nextBuildHash = 0;
if (cloth.isActiveAndEnabled)
{
// スレッドで作成
info.building = true;
var _ = CreateOrUpdateEditMesh(id, cloth, cancelToken.Token);
}
}
}
}
}
}
}
public static VirtualMesh GetEditMesh(ClothBehaviour comp)
{
if (isValid == false)
return null;
if (comp == null)
return null;
int id = comp.GetInstanceID();
VirtualMesh vmesh = null;
lock (editClothDict)
{
vmesh = editClothDict.ContainsKey(id) ? editClothDict[id].editMesh : null;
}
return vmesh;
}
/// <summary>
/// 現在のコンポーネント状態を返す
/// </summary>
/// <param name="comp"></param>
/// <returns></returns>
public static ResultCode GetResultCode(ClothBehaviour comp)
{
if (comp == null)
return ResultCode.Empty;
int id = comp.GetInstanceID();
lock (editClothDict)
{
if (editClothDict.ContainsKey(id))
return editClothDict[id].result;
else
return ResultCode.Empty;
}
}
static void Dispose()
{
cancelToken.Cancel();
cancelToken.Dispose();
cancelToken = new CancellationTokenSource();
destroyList.Clear();
drawList.Clear();
lock (editClothDict)
{
foreach (var info in editClothDict.Values)
{
info?.editMesh?.Dispose();
}
editClothDict.Clear();
}
}
/// <summary>
/// コンポーネントの削除チェック
/// </summary>
static void DestroyCheck()
{
lock (editClothDict)
{
destroyList.Clear();
foreach (var kv in editClothDict)
{
if (kv.Value.component == null)
{
destroyList.Add(kv.Key);
}
}
foreach (var id in destroyList)
{
//Debug.Log($"削除");
editClothDict[id].editMesh?.Dispose();
editClothDict.Remove(id);
}
destroyList.Clear();
}
}
/// <summary>
/// アセット更新にともなう編集用メッシュの更新
/// </summary>
/// <param name="importedAssets"></param>
public static void UpdateFromAssetImport(string[] importedAssets)
{
if (importedAssets == null || importedAssets.Length == 0)
return;
var importedAssetSet = new HashSet<string>(importedAssets);
// クロスコンポーネントがインポートされたアセットを参照している場合は再構築フラグを立てる
var updateDict = new Dictionary<ClothBehaviour, GizmoType>();
lock (editClothDict)
{
foreach (var cinfo in editClothDict.Values)
{
var cloth = cinfo.component as MagicaCloth;
if (cloth)
{
bool update = false;
var sdata = cloth.SerializeData;
// source renderes
if (sdata.clothType == ClothProcess.ClothType.MeshCloth)
{
foreach (var ren in sdata.sourceRenderers)
{
if (ren && importedAssetSet.Contains(AssetDatabase.GetAssetPath(ren)))
update = true;
}
}
// paint maps
if (sdata.clothType == ClothProcess.ClothType.MeshCloth && sdata.paintMode != ClothSerializeData.PaintMode.Manual)
{
foreach (var map in sdata.paintMaps)
{
if (map && importedAssetSet.Contains(AssetDatabase.GetAssetPath(map)))
update = true;
}
}
if (update)
{
// 再構築フラグ
// インポートカウントを増加させることでハッシュ値を変化させる
cinfo.importCount++;
updateDict.Add(cinfo.component, cinfo.gizmoType);
}
}
}
}
// 再構築開始
foreach (var kv in updateDict)
{
RegisterComponent(kv.Key, kv.Value);
}
}
/// <summary>
/// 強制的にすべてのコンポーネントの更新フラグを立てる
/// </summary>
static void ForceUpdateAllComponents()
{
lock (editClothDict)
{
foreach (var cinfo in editClothDict.Values)
{
var cloth = cinfo.component as MagicaCloth;
if (cloth)
{
// 再構築フラグ
// インポートカウントを増加させることでハッシュ値を変化させる
// 次のギズモ表示もしくはペイント時に再構築される
cinfo.importCount++;
}
}
}
}
//=========================================================================================
/// <summary>
/// 編集用メッシュの作成/更新
/// </summary>
/// <param name="id"></param>
/// <param name="cloth"></param>
/// <param name="createSelectionData"></param>
/// <param name="ct"></param>
/// <returns></returns>
static async Task CreateOrUpdateEditMesh(int id, MagicaCloth cloth, CancellationToken ct)
{
// ■メインスレッド
Develop.DebugLog($"Create and update edit meshes: {cloth.name}");
var sdata = cloth.SerializeData;
var sdata2 = cloth.GetSerializeData2();
var setupList = new List<RenderSetupData>();
VirtualMesh editMesh = null;
ResultCode result = new ResultCode();
try
{
// ■メインスレッド
if (cloth == null || isValid == false)
{
result.SetError(Define.Result.CreateCloth_InvalidCloth);
throw new MagicaClothProcessingException();
}
// メッシュを構築するための最低限のデータが揃っているか確認
if (sdata.IsValid() == false)
{
result.SetResult(Define.Result.Empty);
throw new MagicaClothProcessingException();
}
// セットアップデータの作成
if (sdata.clothType == ClothProcess.ClothType.MeshCloth)
{
foreach (var ren in sdata.sourceRenderers)
{
if (ren)
{
var setup = new RenderSetupData(ren);
if (setup.IsFaild())
{
setup.Dispose();
result.Set(setup.result);
throw new MagicaClothProcessingException();
}
setupList.Add(setup);
}
else
{
result.SetError(Define.Result.CreateCloth_NoRenderer);
throw new MagicaClothProcessingException();
}
}
}
else if (sdata.clothType == ClothProcess.ClothType.BoneCloth)
{
var setup = new RenderSetupData(cloth.ClothTransform, sdata.rootBones, sdata.connectionMode, cloth.name);
setupList.Add(setup);
}
if (setupList.Count == 0)
{
result.SetError(Define.Result.CreateCloth_InvalidSetupList);
throw new MagicaClothProcessingException();
}
// クロスコンポーネントトランスフォーム情報
var clothTransformRecord = new TransformRecord(cloth.ClothTransform);
// 法線調整用トランスフォーム
var normalAdjustmentTransformRecored = new TransformRecord(
sdata.normalAlignmentSetting.adjustmentTransform ?
sdata.normalAlignmentSetting.adjustmentTransform :
cloth.ClothTransform
);
// ペイントマップデータの作成(これはメインスレッドでのみ作成可能)
var paintMapDataList = new List<ClothProcess.PaintMapData>();
if (sdata.clothType == ClothProcess.ClothType.MeshCloth && sdata.paintMode != ClothSerializeData.PaintMode.Manual)
{
var ret = cloth.Process.GeneratePaintMapDataList(paintMapDataList);
if (ret.IsError())
{
result = ret;
throw new MagicaClothProcessingException();
}
if (paintMapDataList.Count != setupList.Count)
{
result.SetError(Define.Result.CreateCloth_PaintMapCountMismatch);
throw new MagicaClothProcessingException();
}
}
// エディットメッシュ作成
// メッシュはセンター空間で作成される
ct.ThrowIfCancellationRequested();
editMesh = new VirtualMesh("EditMesh");
if (sdata.clothType == ClothProcess.ClothType.MeshCloth)
{
// MeshClothではクロストランスフォームを追加しておく
editMesh.SetTransform(cloth.ClothTransform);
}
editMesh.result.SetProcess();
// ■スレッド
await Task.Run(() =>
{
try
{
// MeshCloth/BoneClothで処理が一部異なる
ct.ThrowIfCancellationRequested();
if (sdata.clothType == ClothProcess.ClothType.MeshCloth)
{
foreach (var setup in setupList)
{
// レンダーメッシュ作成
using var renderMesh = new VirtualMesh($"[{setup.name}]");
renderMesh.result.SetProcess();
// インポート
renderMesh.ImportFrom(setup);
//Debug.Log($"(IMPORT) {renderMesh}");
if (renderMesh.IsError)
continue;
renderMesh.result.SetSuccess();
// マージ
editMesh.AddMesh(renderMesh);
}
//Debug.Log($"(MERGE) {editMesh}");
// リダクション
if (editMesh.VertexCount > 1 && sdata.reductionSetting.IsEnabled)
{
editMesh.Reduction(sdata.reductionSetting, ct);
if (editMesh.IsError)
{
result = editMesh.result;
throw new MagicaClothProcessingException();
}
//Debug.Log($"(REDUCTION) {editMesh}");
}
}
else if (sdata.clothType == ClothProcess.ClothType.BoneCloth)
{
// import
editMesh.ImportFrom(setupList[0]);
if (editMesh.IsError)
{
result = editMesh.result;
throw new MagicaClothProcessingException();
}
//Debug.Log($"(IMPORT) {editMesh}");
}
// 元の頂点から結合頂点へのインデックスを初期化
if (editMesh.joinIndices.IsCreated == false)
{
editMesh.joinIndices = new Unity.Collections.NativeArray<int>(editMesh.VertexCount, Unity.Collections.Allocator.Persistent);
JobUtility.SerialNumberRun(editMesh.joinIndices, editMesh.VertexCount); // 連番をつける
}
// 最適化
ct.ThrowIfCancellationRequested();
editMesh.Optimization();
if (editMesh.IsError)
{
result = editMesh.result;
throw new MagicaClothProcessingException();
}
//Debug.Log($"(OPTIMIZE) {editMesh}");
}
catch (OperationCanceledException)
{
throw;
}
catch (MagicaClothProcessingException)
{
throw;
}
catch (Exception exception)
{
Debug.LogException(exception);
result.SetError(Define.Result.CreateCloth_Exception);
throw;
}
}, ct);
// ■メインスレッド
// セレクションデータの作成
// まだセレクションデータが未編集の場合は作り直す
ct.ThrowIfCancellationRequested();
{
if (sdata2.selectionData == null || sdata2.selectionData.IsValid() == false || sdata2.selectionData.userEdit == false)
{
// 新規作成
var selectionData = CreateAutoSelectionData(cloth, sdata, editMesh);
// 格納
//ApplySelectionData(cloth, selectionData);
sdata2.selectionData = selectionData;
}
}
// ■スレッド
await Task.Run(() =>
{
try
{
// MeshClothでペイントテクスチャ指定の場合はセレクションデータを生成する
ct.ThrowIfCancellationRequested();
var selectionData = sdata2.selectionData;
if (sdata.clothType == ClothProcess.ClothType.MeshCloth && sdata.paintMode != ClothSerializeData.PaintMode.Manual)
{
// ペイントマップからセレクションデータを生成する
var ret = cloth.Process.GenerateSelectionDataFromPaintMap(editMesh, clothTransformRecord, setupList, paintMapDataList, out selectionData);
if (ret.IsError())
{
result = ret;
throw new MagicaClothProcessingException();
}
}
// セレクションデータから頂点属性を付与する
ct.ThrowIfCancellationRequested();
if (selectionData.IsValid())
{
editMesh.ApplySelectionAttribute(selectionData);
}
// ProxyMeshへの変換属性決定後に実行
ct.ThrowIfCancellationRequested();
editMesh.ConvertProxyMesh(cloth.SerializeData, null, null, normalAdjustmentTransformRecored);
if (editMesh.IsError)
{
result = editMesh.result;
throw new MagicaClothProcessingException();
}
//Debug.Log($"(PROXY) {editMesh}");
#if false
// pitch/yaw個別制限はv1.0では実装しないので一旦停止
// 角度制限計算用回転を作成
ct.ThrowIfCancellationRequested();
editMesh.CreateAngleCalcLocalRotation(sdata.normalCalculation, sdata.normalCalculationCenter);
if (editMesh.IsError)
throw new InvalidOperationException();
#endif
// 完了
ct.ThrowIfCancellationRequested();
editMesh.result.SetSuccess();
}
catch (OperationCanceledException)
{
throw;
}
catch (MagicaClothProcessingException)
{
throw;
}
catch (Exception exception)
{
Debug.LogException(exception);
result.SetError(Define.Result.CreateCloth_Exception);
throw;
}
}, ct);
// ■メインスレッド
if (cloth == null)
{
//result.SetError(Define.Result.CreateCloth_InvalidCloth);
//throw new MagicaClothProcessingException();
// キャンセル扱いにする
throw new OperationCanceledException();
}
// 成功
Develop.DebugLog($"(FINAL PROXY) {editMesh}");
result.SetSuccess();
}
catch (MagicaClothProcessingException)
{
if (result.IsNone()) result.SetError(Define.Result.CreateCloth_UnknownError);
result.DebugLog();
}
catch (OperationCanceledException)
{
Develop.DebugLog($"Editor mesh build canceled!");
result.SetCancel();
}
catch (Exception exception)
{
Debug.LogException(exception);
result.SetError(Define.Result.CreateCloth_Exception);
}
finally
{
// 状態変更
lock (editClothDict)
{
if (editClothDict.ContainsKey(id))
{
var info = editClothDict[id];
info.building = false;
info.result = result;
info.editMesh?.Dispose();
if (result.IsSuccess())
{
info.editMesh = editMesh;
editMesh = null;
Develop.DebugLog($"Registration Complete : {cloth.name}");
}
else
{
info.editMesh = null;
}
}
}
// dispose
foreach (var setup in setupList)
{
setup?.Dispose();
}
editMesh?.Dispose();
//span.DebugLog();
// 引き続き再構築の実行判定
lock (editClothDict)
{
if (editClothDict.ContainsKey(id))
{
var info = editClothDict[id];
info.building = false;
if (info.nextBuildHash != 0 && cloth)
{
if (info.nextBuildHash == info.componentHash)
{
info.nextBuildHash = 0;
}
else
{
info.componentHash = info.nextBuildHash;
info.nextBuildHash = 0;
info.building = true;
info.result.Clear();
var _ = CreateOrUpdateEditMesh(id, cloth, ct);
}
}
}
}
SceneView.RepaintAll();
// ビルド完了通知
OnEditMeshBuildComplete?.Invoke();
}
}
/// <summary>
/// セレクションデータをシリアライズ化する
/// </summary>
/// <param name="cloth"></param>
/// <param name="selectionData"></param>
public static void ApplySelectionData(MagicaCloth cloth, SelectionData selectionData)
{
if (cloth == null || selectionData == null || selectionData.IsValid() == false)
return;
if (cloth.GetSerializeData2().selectionData != null && cloth.GetSerializeData2().selectionData.Compare(selectionData))
return; // 変更なし
//Debug.Log($"セレクションデータ格納!");
Undo.RecordObject(cloth, "Paint");
// 最終的に[SerializeReference]から[SerializeField]に変更(2022/12/18)
cloth.GetSerializeData2().selectionData = selectionData;
EditorUtility.SetDirty(cloth);
}
/// <summary>
/// 編集メッシュから自動でセレクションデータを生成する(メインスレッドのみ)
/// </summary>
/// <param name="sdata"></param>
/// <param name="emesh"></param>
/// <param name="setupList"></param>
/// <returns></returns>
public static SelectionData CreateAutoSelectionData(MagicaCloth cloth, ClothSerializeData sdata, VirtualMesh emesh)
{
var selectionData = new SelectionData(emesh, float4x4.identity);
int cnt = selectionData.Count;
if (cnt == 0)
return selectionData;
// BoneClothはRootをFixedに定義する、それ以外はMove
if (sdata.clothType == ClothProcess.ClothType.BoneCloth)
{
selectionData.Fill(VertexAttribute.Move);
// BoneClothではセットアップデータのrootのみ固定に設定する
using var setup = new RenderSetupData(cloth.ClothTransform, sdata.rootBones, sdata.connectionMode, cloth.name);
foreach (int id in setup.rootTransformIdList)
{
int rootIndex = setup.GetTransformIndexFromId(id);
selectionData.attributes[rootIndex] = VertexAttribute.Fixed;
}
}
// MeshClothではすべて固定で定義する
else
{
selectionData.Fill(VertexAttribute.Invalid);
}
return selectionData;
}
//=========================================================================================
/// <summary>
/// シーンビューへのギズモ描画
/// </summary>
/// <param name="sceneView"></param>
static void OnSceneGUI(SceneView sceneView)
{
if (isValid == false)
return;
// コンポーネント削除チェック
DestroyCheck();
// コンポーネントギズモ描画
if (Event.current.type == EventType.Repaint)
{
//Develop.DebugLog($"Repaint. F:{Time.frameCount}");
drawList.Clear();
bool isPainting = ClothPainter.IsPainting();
bool isPlaying = EditorApplication.isPlaying;
var camPos = sceneView.camera.transform.position;
Quaternion camRot = sceneView.camera.transform.rotation;
lock (editClothDict)
{
foreach (var info in editClothDict.Values)
{
if (info == null || info.component == null)
continue;
if (info.component.isActiveAndEnabled == false)
continue;
// 描画フラグ
if (info.gizmoType.HasFlag(GizmoType.Active) == false && info.gizmoType.HasFlag(GizmoType.Selected) == false)
continue;
if (info.component is MagicaCloth && info.gizmoType.HasFlag(GizmoType.Active) == false)
continue;
// ペイント中は表示しない
if (isPainting)
continue;
// コンポーネント距離(ただし非選択時のみ)
bool selected = Selection.Contains(info.component.gameObject);
if (selected == false)
{
float dist = Vector3.Distance(camPos, info.component.transform.position);
if (dist >= 20.0f) // 20m
continue;
}
// 選択状態
selected = info.gizmoType.HasFlag(GizmoType.Active);
// Collider
if (info.component is ColliderComponent)
{
GizmoUtility.DrawCollider(info.component as ColliderComponent, camRot, true, selected);
}
// MagicaCloth
else if (info.component is MagicaCloth)
{
var cloth = info.component as MagicaCloth;
// Cloth
if (cloth.GizmoSerializeData.clothDebugSettings.enable)
{
//Debug.Log($"ペイントくろす");
if (isPlaying)
ClothEditorUtility.DrawClothRuntime(cloth.Process, cloth.GizmoSerializeData.clothDebugSettings, selected);
else
ClothEditorUtility.DrawClothEditor(info.editMesh, cloth.GizmoSerializeData.clothDebugSettings, cloth.SerializeData, selected, false, false);
}
#if MC2_DEBUG
// Proxy Mesh
if (cloth.GizmoSerializeData.proxyDebugSettings.enable)
{
if (isPlaying)
VirtualMeshEditorUtility.DrawRuntimeGizmos(cloth.Process, false, cloth.Process.ProxyMesh, cloth.GizmoSerializeData.proxyDebugSettings, selected, true);
else
VirtualMeshEditorUtility.DrawGizmos(info.editMesh, cloth.GizmoSerializeData.proxyDebugSettings, selected, true);
}
// Mapping Mesh
if (cloth.GizmoSerializeData.mappingDebugSettings.enable)
{
if (isPlaying)
{
var renderMeshInfo = cloth.Process.GetRenderMeshInfo(cloth.GizmoSerializeData.debugMappingIndex);
if (renderMeshInfo != null && renderMeshInfo.renderMesh != null)
VirtualMeshEditorUtility.DrawRuntimeGizmos(cloth.Process, true, renderMeshInfo.renderMesh, cloth.GizmoSerializeData.mappingDebugSettings, selected, true);
}
}
#endif // MC2_DEBUG
}
// 描画フラグoff
info.gizmoType = 0;
}
}
}
}
}
}