// Magica Cloth. // Copyright (c) MagicaSoft, 2020-2022. // https://magicasoft.jp using System.Collections.Generic; using Unity.Mathematics; using UnityEngine; #if UNITY_EDITOR using UnityEditor; #endif namespace MagicaCloth { /// /// メッシュスプリング /// [HelpURL("https://magicasoft.jp/magica-cloth-mesh-spring/")] [AddComponentMenu("MagicaCloth/MagicaMeshSpring", 100)] public class MagicaMeshSpring : BaseCloth { /// /// データバージョン /// private const int DATA_VERSION = 7; /// /// エラーデータバージョン /// private const int ERR_DATA_VERSION = 3; // 対象仮想メッシュデフォーマー [SerializeField] private MagicaVirtualDeformer virtualDeformer = null; [SerializeField] private int virtualDeformerHash; [SerializeField] private int virtualDeformerVersion; // センタートランスフォーム [SerializeField] private Transform centerTransform = null; public enum Axis { X, Y, Z, InverseX, InverseY, InverseZ, } [SerializeField] private Axis directionAxis; [SerializeField] private SpringData springData = null; [SerializeField] private int springDataHash; [SerializeField] private int springDataVersion; //========================================================================================= public override ComponentType GetComponentType() { return ComponentType.MeshSpring; } //========================================================================================= public override int GetDataHash() { int hash = base.GetDataHash(); hash += virtualDeformer.GetDataHash(); hash += centerTransform.GetDataHash(); hash += SpringData.GetDataHash(); return hash; } //========================================================================================= public VirtualMeshDeformer Deformer { get { if (virtualDeformer != null) return virtualDeformer.Deformer; return null; } } public SpringData SpringData { get { #if UNITY_EDITOR if (Application.isPlaying) return springData; else { // unity2019.3で参照がnullとなる不具合の対処(臨時) var so = new SerializedObject(this); return so.FindProperty("springData").objectReferenceValue as SpringData; } #else return springData; #endif } } public int UseVertexCount { get { if (SpringData == null) return 0; else return SpringData.UseVertexCount; } } public Transform CenterTransform { get { return centerTransform; } set { centerTransform = value; } } public Axis DirectionAxis { get { return directionAxis; } set { directionAxis = value; } } public Vector3 CenterTransformDirection { get { Vector3 dir = Vector3.forward; if (centerTransform) { switch (directionAxis) { case Axis.X: dir = centerTransform.right; break; case Axis.Y: dir = centerTransform.up; break; case Axis.Z: dir = centerTransform.forward; break; case Axis.InverseX: dir = -centerTransform.right; break; case Axis.InverseY: dir = -centerTransform.up; break; case Axis.InverseZ: dir = -centerTransform.forward; break; } } return dir; } } public SpringData.DeformerData GetDeformerData() { return SpringData.deformerData; } //========================================================================================= protected override void Reset() { base.Reset(); ResetParams(); } protected override void OnValidate() { base.OnValidate(); } //========================================================================================= /// /// クロス初期化 /// protected override void ClothInit() { // 中央トランスフォームに移動パーティクルを1つ設定する(これが揺れる) // クロスデータはこの場で作成する ClothData cdata = ShareDataObject.CreateShareData("ClothData_work"); cdata.selectionData.Add(SelectionData.Move); cdata.vertexFlagLevelList.Add(0); cdata.vertexDepthList.Add(0); cdata.rootList.Add(0); cdata.useVertexList.Add(0); cdata.initScale = SpringData.initScale; cdata.SaveDataHash = 1; cdata.SaveDataVersion = cdata.GetVersion(); cdata.clampRotationAlgorithm = ClothParams.Algorithm.Algorithm_2; cdata.restoreRotationAlgorithm = ClothParams.Algorithm.Algorithm_2; cdata.triangleBendAlgorithm = ClothParams.Algorithm.Algorithm_2; ClothData = cdata; // エラーが出ないように clothDataHash = cdata.SaveDataHash; clothDataVersion = cdata.SaveDataVersion; // クロス初期化 base.ClothInit(); // スプリングではClampPositonの速度制限は無視する MagicaPhysicsManager.Instance.Team.SetFlag(TeamId, PhysicsManagerTeamData.Flag_IgnoreClampPositionVelocity, true); } protected override void ClothActive() { base.ClothActive(); } /// /// 頂点ごとのパーティクルフラグ設定(不要な場合は0) /// /// /// protected override uint UserFlag(int index) { uint flag = 0; flag |= PhysicsManagerParticleData.Flag_Transform_Read_Base; // トランスフォームをbasePos/baseRotに読み込み flag |= PhysicsManagerParticleData.Flag_Transform_Read_Rot; // トランスフォームをrotに読み込む return flag; } /// /// 頂点ごとの連動トランスフォーム設定(不要な場合はnull) /// /// /// protected override Transform UserTransform(int index) { return CenterTransform; } /// /// 頂点ごとの連動トランスフォームのLocalPositionを返す(不要な場合は0) /// /// /// protected override float3 UserTransformLocalPosition(int vindex) { return CenterTransform.localPosition; } /// /// 頂点ごとの連動トランスフォームのLocalRotationを返す(不要な場合はquaternion.identity) /// /// /// protected override quaternion UserTransformLocalRotation(int vindex) { return CenterTransform.localRotation; } /// /// デフォーマーが必須か返す /// /// public override bool IsRequiresDeformer() { return true; } /// /// デフォーマーを返す /// /// /// public override BaseMeshDeformer GetDeformer() { if (virtualDeformer) { return virtualDeformer.Deformer; } return null; } /// /// クロス初期化時に必要なMeshDataを返す(不要ならnull) /// /// protected override MeshData GetMeshData() { // MeshSpringeには不要 return null; } /// /// クロス初期化の主にワーカーへの登録 /// protected override void WorkerInit() { // センターパーティクル int pindex = ParticleChunk.startIndex; // デフォーマーごとの設定 SpringMeshWorker worker = MagicaPhysicsManager.Instance.Compute.SpringMeshWorker; { // デフォーマー取得 var deformer = GetDeformer(); Debug.Assert(deformer != null); deformer.Init(); // スプリングデータ取得 var data = GetDeformerData(); Debug.Assert(data != null); // スプリングワーカー設定 var minfo = MagicaPhysicsManager.Instance.Mesh.GetVirtualMeshInfo(deformer.MeshIndex); for (int j = 0; j < data.UseVertexCount; j++) { int vindex = data.useVertexIndexList[j]; worker.Add(TeamId, minfo.vertexChunk.startIndex + vindex, pindex, data.weightList[j]); } } } /// /// デフォーマーごとの使用頂点設定 /// 使用頂点に対して AddUseVertex() / RemoveUseVertex() を実行する /// /// /// protected override void SetDeformerUseVertex(bool sw, BaseMeshDeformer deformer) { var data = GetDeformerData(); int vcnt = data.UseVertexCount; for (int j = 0; j < vcnt; j++) { int vindex = data.useVertexIndexList[j]; if (sw) deformer.AddUseVertex(vindex, false); else deformer.RemoveUseVertex(vindex, false); } } /// /// UnityPhyiscsでの更新の変更 /// 継承クラスは自身の使用するボーンの状態更新などを記述する /// /// protected override void ChangeUseUnityPhysics(bool sw) { base.ChangeUseUnityPhysics(sw); // デフォーマに伝達 virtualDeformer?.SetUseUnityPhysics(sw); } protected override void OnChangeCalculation() { base.OnChangeCalculation(); if (IsCalculate) { if (MagicaPhysicsManager.Instance.IsDelay) { // 読み込みボーンの未来予測をリセットする MagicaPhysicsManager.Instance.Particle.ResetFuturePredictionTransform(particleChunk); } } } //========================================================================================= public override int GetVersion() { return DATA_VERSION; } /// /// エラーとするデータバージョンを取得する /// /// public override int GetErrorVersion() { return ERR_DATA_VERSION; } /// /// データを検証して結果を格納する /// /// public override void CreateVerifyData() { base.CreateVerifyData(); virtualDeformerHash = virtualDeformer.SaveDataHash; virtualDeformerVersion = virtualDeformer.SaveDataVersion; springDataHash = SpringData.SaveDataHash; springDataVersion = SpringData.SaveDataVersion; } /// /// 現在のデータが正常(実行できる状態)か返す /// /// public override Define.Error VerifyData() { var baseError = base.VerifyData(); if (baseError != Define.Error.None) return baseError; if (virtualDeformer == null) return Define.Error.DeformerNull; var vdeformerError = virtualDeformer.VerifyData(); if (vdeformerError != Define.Error.None) return vdeformerError; if (virtualDeformerHash != virtualDeformer.SaveDataHash) return Define.Error.DeformerHashMismatch; if (virtualDeformerVersion != virtualDeformer.SaveDataVersion) return Define.Error.DeformerVersionMismatch; if (centerTransform == null) return Define.Error.CenterTransformNull; var sdata = SpringData; if (sdata == null) return Define.Error.SpringDataNull; var sdataError = sdata.VerifyData(); if (sdataError != Define.Error.None) return sdataError; if (springDataHash != sdata.SaveDataHash) return Define.Error.SpringDataHashMismatch; if (springDataVersion != sdata.SaveDataVersion) return Define.Error.SpringDataVersionMismatch; return Define.Error.None; } public override string GetInformation() { StaticStringBuilder.Clear(); var err = VerifyData(); if (err == Define.Error.None) { // OK StaticStringBuilder.AppendLine("Active: ", Status.IsActive); StaticStringBuilder.AppendLine($"Visible: {IsVisible}"); StaticStringBuilder.AppendLine($"Calculation:{IsCalculate}"); StaticStringBuilder.Append("Use Deformer Vertex: ", UseVertexCount); } else if (err == Define.Error.EmptyData) { StaticStringBuilder.Append(Define.GetErrorMessage(err)); } else { // エラー StaticStringBuilder.AppendLine("This mesh spring is in a state error!"); if (Application.isPlaying) { StaticStringBuilder.AppendLine("Execution stopped."); } else { StaticStringBuilder.AppendLine("Please recreate the mesh spring data."); } StaticStringBuilder.Append(Define.GetErrorMessage(err)); } return StaticStringBuilder.ToString(); } /// /// デフォーマーの検証 /// public void VerifyDeformer() { } //========================================================================================= /// /// ボーンを置換する /// /// public override void ReplaceBone(Dictionary boneReplaceDict) { if (centerTransform) { centerTransform = MeshUtility.GetReplaceBone(centerTransform, boneReplaceDict); } } /// /// 現在使用しているボーンを格納して返す /// /// public override HashSet GetUsedBones() { var bones = base.GetUsedBones(); bones.Add(centerTransform); return bones; } //========================================================================================= /// /// メッシュのワールド座標/法線/接線を返す(エディタ用) /// /// /// /// /// 頂点数 public override int GetEditorPositionNormalTangent(out List wposList, out List wnorList, out List wtanList) { wposList = new List(); wnorList = new List(); wtanList = new List(); var t = CenterTransform; if (t == null) return 0; wposList.Add(t.position); wnorList.Add(t.forward); var up = t.up; wtanList.Add(up); return 1; } /// /// メッシュのトライアングルリストを返す(エディタ用) /// /// public override List GetEditorTriangleList() { return null; } /// /// メッシュのラインリストを返す(エディタ用) /// /// public override List GetEditorLineList() { return null; } //========================================================================================= /// /// 頂点の選択状態をリストにして返す(エディタ用) /// 選択状態は ClothSelection.Invalid / ClothSelection.Fixed / ClothSelection.Move /// すべてがInvalidならばnullを返す /// /// public override List GetSelectionList() { return null; } /// /// 頂点の使用状態をリストにして返す(エディタ用) /// 数値が1以上ならば使用中とみなす /// すべて使用状態ならばnullを返す /// /// public override List GetUseList() { return null; } //========================================================================================= /// /// 共有データオブジェクト収集 /// /// public override List GetAllShareDataObject() { var sdata = base.GetAllShareDataObject(); sdata.Add(SpringData); return sdata; } /// /// sourceの共有データを複製して再セットする /// 再セットした共有データを返す /// /// /// public override ShareDataObject DuplicateShareDataObject(ShareDataObject source) { var sdata = base.DuplicateShareDataObject(source); if (sdata != null) return sdata; if (SpringData == source) { //springData = Instantiate(SpringData); springData = ShareDataObject.Clone(SpringData); return springData; } return null; } //========================================================================================= /// /// パラメータ初期化 /// void ResetParams() { clothParams.AlgorithmType = ClothParams.Algorithm.Algorithm_2; clothParams.SetRadius(0.05f, 0.05f); clothParams.SetMass(1.0f, 1.0f, false); clothParams.SetGravity(false, -5.0f, -5.0f); clothParams.SetDrag(true, 0.01f, 0.01f); clothParams.SetMaxVelocity(true, 3.0f, 3.0f); clothParams.SetWorldInfluence(2.0f, 0.5f, 1.0f); clothParams.SetTeleport(false); clothParams.SetClampDistanceRatio(false); clothParams.SetClampPositionLength(true, 0.1f, 0.1f, 1.0f, 1.0f, 1.0f, 0.2f); clothParams.SetClampRotationAngle(false); clothParams.SetRestoreDistance(1.0f); clothParams.SetRestoreRotation(false); clothParams.SetSpring(true, 0.02f, 0.14f, 1.0f, 1.0f, 1.0f, 1.0f); clothParams.SetSpringDirectionAtten(1.0f, 0.0f, 0.6f); clothParams.SetSpringDistanceAtten(1.0f, 0.0f, 0.4f); clothParams.SetAdjustRotation(ClothParams.AdjustMode.Fixed, 5.0f); clothParams.SetTriangleBend(false); clothParams.SetVolume(false); clothParams.SetCollision(false, 0.1f); clothParams.SetExternalForce(0.2f, 0.0f, 0.0f, 1.0f); } } }