// Magica Cloth. // Copyright (c) MagicaSoft, 2020-2022. // https://magicasoft.jp using System.Collections.Generic; using Unity.Mathematics; using UnityEngine; namespace MagicaCloth { /// /// メッシュクロス /// [HelpURL("https://magicasoft.jp/magica-cloth-mesh-cloth/")] [AddComponentMenu("MagicaCloth/MagicaMeshCloth", 100)] public class MagicaMeshCloth : 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; //========================================================================================= public override ComponentType GetComponentType() { return ComponentType.MeshCloth; } //========================================================================================= /// /// データハッシュを求める /// /// public override int GetDataHash() { int hash = base.GetDataHash(); hash += virtualDeformer.GetDataHash(); return hash; } //========================================================================================= public VirtualMeshDeformer Deformer { get { if (virtualDeformer != null) return virtualDeformer.Deformer; return null; } } //========================================================================================= protected override void Reset() { base.Reset(); ResetParams(); } protected override void OnValidate() { base.OnValidate(); } protected override void OnInit() { base.OnInit(); } protected override void OnActive() { base.OnActive(); } protected override void OnInactive() { base.OnInactive(); } protected override void OnDispose() { base.OnDispose(); } //========================================================================================= /// /// 頂点ごとのパーティクルフラグ設定(不要な場合は0) /// /// /// protected override uint UserFlag(int index) { // メッシュクロスでは不要 return 0; } /// /// 頂点ごとの連動トランスフォーム設定(不要な場合はnull) /// /// /// protected override Transform UserTransform(int index) { // メッシュクロスでは不要 return null; } /// /// 頂点ごとの連動トランスフォームのLocalPositionを返す(不要な場合は0) /// /// /// protected override float3 UserTransformLocalPosition(int vindex) { // メッシュクロスでは不要 return 0; } /// /// 頂点ごとの連動トランスフォームのLocalRotationを返す(不要な場合はquaternion.identity) /// /// /// protected override quaternion UserTransformLocalRotation(int vindex) { // メッシュクロスでは不要 return quaternion.identity; } /// /// デフォーマーが必須か返す /// /// public override bool IsRequiresDeformer() { return true; } /// /// デフォーマーを返す /// /// /// public override BaseMeshDeformer GetDeformer() { return Deformer; } /// /// クロス初期化時に必要なMeshDataを返す(不要ならnull) /// /// protected override MeshData GetMeshData() { return Deformer.MeshData; } /// /// クロス初期化の主にワーカーへの登録 /// protected override void WorkerInit() { // デフォーマー頂点とパーティクルの連動登録 var meshParticleWorker = MagicaPhysicsManager.Instance.Compute.MeshParticleWorker; var minfo = MagicaPhysicsManager.Instance.Mesh.GetVirtualMeshInfo(Deformer.MeshIndex); var cdata = ClothData; for (int i = 0; i < cdata.VertexUseCount; i++) { int pindex = particleChunk.startIndex + i; int vindex = minfo.vertexChunk.startIndex + cdata.useVertexList[i]; if (pindex >= 0) meshParticleWorker.Add(TeamId, vindex, pindex); } } /// /// デフォーマーごとの使用頂点設定 /// 使用頂点に対して AddUseVertex() / RemoveUseVertex() を実行する /// /// /// protected override void SetDeformerUseVertex(bool sw, BaseMeshDeformer deformer) { var cdata = ClothData; for (int i = 0; i < cdata.VertexUseCount; i++) { // 未使用頂点は除く if (ClothData.IsInvalidVertex(i)) continue; int vindex = cdata.useVertexList[i]; bool fix = !ClothData.IsMoveVertex(i); if (sw) deformer.AddUseVertex(vindex, fix); else deformer.RemoveUseVertex(vindex, fix); } } /// /// UnityPhyiscsでの更新の変更 /// 継承クラスは自身の使用するボーンの状態更新などを記述する /// /// protected override void ChangeUseUnityPhysics(bool sw) { base.ChangeUseUnityPhysics(sw); // デフォーマに伝達 virtualDeformer?.SetUseUnityPhysics(sw); } //========================================================================================= 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; } /// /// 現在のデータが正常(実行できる状態)か返す /// /// public override Define.Error VerifyData() { var baseError = base.VerifyData(); if (baseError != Define.Error.None) return baseError; if (ClothData == null) return Define.Error.ClothDataNull; 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; return Define.Error.None; } /// /// データ検証の結果テキストを取得する /// /// public override string GetInformation() { // 仮想デフォーマー情報 StaticStringBuilder.Clear(); var err = VerifyData(); if (err == Define.Error.None) { // OK var cdata = ClothData; StaticStringBuilder.AppendLine("Active: ", Status.IsActive); StaticStringBuilder.AppendLine($"Visible: {IsVisible}"); StaticStringBuilder.AppendLine($"Calculation:{IsCalculate}"); StaticStringBuilder.AppendLine("Vertex: ", cdata.VertexUseCount); StaticStringBuilder.AppendLine("Clamp Distance: ", cdata.ClampDistanceConstraintCount); StaticStringBuilder.AppendLine("Clamp Position: ", clothParams.UseClampPositionLength ? cdata.VertexUseCount : 0); StaticStringBuilder.AppendLine("Clamp Rotation [", cdata.clampRotationAlgorithm, "] : ", cdata.GetClampRotationCount()); StaticStringBuilder.AppendLine("Struct Distance: ", cdata.StructDistanceConstraintCount / 2); StaticStringBuilder.AppendLine("Bend Distance: ", cdata.BendDistanceConstraintCount / 2); StaticStringBuilder.AppendLine("Near Distance: ", cdata.NearDistanceConstraintCount / 2); StaticStringBuilder.AppendLine("Restore Rotation [", cdata.restoreRotationAlgorithm, "] : ", cdata.GetRestoreRotationCount()); StaticStringBuilder.AppendLine("Triangle Bend [", cdata.triangleBendAlgorithm, "] : ", cdata.TriangleBendConstraintCount); StaticStringBuilder.AppendLine("Collider: ", teamData.ColliderCount); StaticStringBuilder.Append("Line Rotation: ", cdata.LineRotationWorkerCount); } else if (err == Define.Error.EmptyData) { StaticStringBuilder.Append(Define.GetErrorMessage(err)); } else { // エラー StaticStringBuilder.AppendLine("This mesh cloth is in a state error!"); if (Application.isPlaying) { StaticStringBuilder.AppendLine("Execution stopped."); } else { StaticStringBuilder.AppendLine("Please recreate the cloth data."); } StaticStringBuilder.Append(Define.GetErrorMessage(err)); } return StaticStringBuilder.ToString(); } public bool IsValidPointSelect() { if (ClothSelection == null) return false; if (Deformer.MeshData.ChildCount != ClothSelection.DeformerCount) return false; return true; } //========================================================================================= /// /// メッシュのワールド座標/法線/接線を返す(エディタ用) /// /// /// /// /// 頂点数 public override int GetEditorPositionNormalTangent(out List wposList, out List wnorList, out List wtanList) { return Deformer.GetEditorPositionNormalTangent(out wposList, out wnorList, out wtanList); } /// /// メッシュのトライアングルリストを返す(エディタ用) /// /// public override List GetEditorTriangleList() { return Deformer.GetEditorTriangleList(); } /// /// メッシュのラインリストを返す(エディタ用) /// /// public override List GetEditorLineList() { return Deformer.GetEditorLineList(); } //========================================================================================= /// /// 頂点の選択状態をリストにして返す(エディタ用) /// 選択状態は ClothSelection.Invalid / ClothSelection.Fixed / ClothSelection.Move /// すべてがInvalidならばnullを返す /// /// public override List GetSelectionList() { if (ClothSelection != null && virtualDeformer != null && Deformer.MeshData != null) return ClothSelection.GetSelectionData(Deformer.MeshData, Deformer.GetRenderDeformerMeshList()); else return null; } /// /// 頂点の使用状態をリストにして返す(エディタ用) /// 数値が1以上ならば使用中とみなす /// すべて使用状態ならばnullを返す /// /// public override List GetUseList() { if (Application.isPlaying && virtualDeformer != null) { if (Deformer != null) { var minfo = MagicaPhysicsManager.Instance.Mesh.GetVirtualMeshInfo(Deformer.MeshIndex); //var infoList = MagicaPhysicsManager.Instance.Mesh.virtualVertexInfoList; var vertexUseList = MagicaPhysicsManager.Instance.Mesh.virtualVertexUseList; var useList = new List(); for (int i = 0; i < minfo.vertexChunk.dataLength; i++) { //uint data = infoList[minfo.vertexChunk.startIndex + i]; //useList.Add((int)(data & 0xffff)); useList.Add(vertexUseList[minfo.vertexChunk.startIndex + i]); } return useList; } } return null; } //========================================================================================= /// /// 共有データオブジェクト収集 /// /// public override List GetAllShareDataObject() { var sdata = base.GetAllShareDataObject(); if (Deformer != null) sdata.Add(Deformer.MeshData); return sdata; } /// /// sourceの共有データを複製して再セットする /// 再セットした共有データを返す /// /// /// public override ShareDataObject DuplicateShareDataObject(ShareDataObject source) { var sdata = base.DuplicateShareDataObject(source); if (sdata != null) return sdata; if (Deformer.MeshData == source) { //Deformer.MeshData = Instantiate(Deformer.MeshData); Deformer.MeshData = ShareDataObject.Clone(Deformer.MeshData); return Deformer.MeshData; } return null; } //========================================================================================= /// /// パラメータ初期化 /// void ResetParams() { clothParams.AlgorithmType = ClothParams.Algorithm.Algorithm_2; clothParams.SetRadius(0.02f, 0.02f); clothParams.SetMass(10.0f, 1.0f, true, -0.5f, true); clothParams.SetGravity(true, -5.0f, -5.0f); clothParams.SetDrag(true, 0.01f, 0.01f); clothParams.SetMaxVelocity(true, 3.0f, 3.0f); clothParams.SetWorldInfluence(3.0f, 0.5f, 1.0f); clothParams.SetTeleport(false); clothParams.SetClampDistanceRatio(true, 0.5f, 1.05f, 0.1f); clothParams.SetClampPositionLength(false, 0.0f, 0.4f); clothParams.SetClampRotationAngle(false, 0.0f, 180.0f, 0.2f); clothParams.SetRestoreDistance(1.0f); clothParams.SetRestoreRotation(false, 0.03f, 0.005f, 0.3f); clothParams.SetSpring(false); clothParams.SetAdjustRotation(); clothParams.SetTriangleBend(true, 1.0f, 1.0f); clothParams.SetVolume(false); clothParams.SetCollision(false, 0.1f, 0.03f); clothParams.SetExternalForce(0.3f, 1.0f, 0.7f, 0.6f); } } }