//=========================================================================================
        /// <summary>
        /// クロスに紐づくコライダーの表示
        /// </summary>
        /// <param name="scr"></param>
        public static void DrawCollider(PhysicsTeam team)
        {
            if (ClothMonitorMenu.Monitor.UI.DrawClothCollider == false)
            {
                return;
            }

            var colliderlist = team.TeamData.ColliderList;

            foreach (var collider in colliderlist)
            {
                if (collider == null || collider.isActiveAndEnabled == false)
                {
                    continue;
                }
                if (collider is MagicaSphereCollider)
                {
                    MagicaSphereColliderGizmoDrawer.DrawGizmo(collider as MagicaSphereCollider, true);
                }
                else if (collider is MagicaCapsuleCollider)
                {
                    MagicaCapsuleColliderGizmoDrawer.DrawGizmo(collider as MagicaCapsuleCollider, true);
                }
            }
        }
Exemple #2
0
        //=========================================================================================
        /// <summary>
        /// チームを作成する
        /// </summary>
        /// <returns></returns>
        public int CreateTeam(PhysicsTeam team, uint flag)
        {
            var data = new TeamData();

            flag     |= Flag_Enable;
            flag     |= Flag_Reset_WorldInfluence; // 移動影響リセット
            data.flag = flag;

            data.friction        = 0;
            data.boneIndex       = team != null ? 0 : -1; // グローバルチームはボーン無し
            data.initScale       = 0;
            data.scaleDirection  = 1;
            data.scaleRatio      = 1;
            data.quaternionScale = 1;
            //data.directionalDampingBoneIndex = team != null ? 0 : -1; // グローバルチームはボーン無し
            //data.directionalDampingLocalDir = new float3(0, 1, 0);
            data.timeScale            = 1.0f;
            data.blendRatio           = 1.0f;
            data.forceMassInfluence   = 1.0f;
            data.forceWindInfluence   = 1.0f;
            data.forceWindRandomScale = 0.0f;

            // 拘束チームインデックス
            data.restoreDistanceGroupIndex = -1;
            data.triangleBendGroupIndex    = -1;
            data.clampDistanceGroupIndex   = -1;
            data.clampDistance2GroupIndex  = -1;
            data.clampPositionGroupIndex   = -1;
            data.clampRotationGroupIndex   = -1;
            data.restoreRotationGroupIndex = -1;
            data.adjustRotationGroupIndex  = -1;
            data.springGroupIndex          = -1;
            data.volumeGroupIndex          = -1;
            data.airLineGroupIndex         = -1;
            data.lineWorkerGroupIndex      = -1;
            data.triangleWorkerGroupIndex  = -1;
            data.selfCollisionGroupIndex   = -1;
            data.edgeCollisionGroupIndex   = -1;
            data.penetrationGroupIndex     = -1;
            data.baseSkinningGroupIndex    = -1;

            int teamId = teamDataList.Add(data);

            teamMassList.Add(new CurveParam(1.0f));
            teamGravityList.Add(new CurveParam());
            teamDragList.Add(new CurveParam());
            teamMaxVelocityList.Add(new CurveParam());
            //teamDirectionalDampingList.Add(new CurveParam());

            teamWorldInfluenceList.Add(new WorldInfluence());

            teamComponentDict.Add(teamId, team);

            if (team != null)
            {
                activeTeamCount++;
            }

            return(teamId);
        }
        static void DrawLineRuntimeSub(
            PhysicsTeam team,
            Color color,
            RestoreDistanceConstraint.RestoreDistanceData[] distanceDataList
            )
        {
            if (distanceDataList == null || distanceDataList.Length == 0)
            {
                return;
            }

            var manager = MagicaPhysicsManager.Instance;

            Gizmos.color = color;
            int cnt = distanceDataList.Length;

            for (int i = 0; i < cnt; i++)
            {
                var data = distanceDataList[i];
                int vindex0, vindex1;
                vindex0 = data.vertexIndex;
                vindex1 = data.targetVertexIndex;

                int pindex0 = team.ParticleChunk.startIndex + vindex0;
                int pindex1 = team.ParticleChunk.startIndex + vindex1;

                Vector3 pos0 = manager.Particle.posList[pindex0];
                Vector3 pos1 = manager.Particle.posList[pindex1];

                Gizmos.DrawLine(pos0, pos1);
            }
        }
        //=========================================================================================
#if false
        static void DrawAdjustRotationLineRuntime(
            PhysicsTeam team,
            ClothData clothData
            )
        {
            if (ClothMonitorMenu.Monitor.UI.DrawAdjustRotationLine == false)
            {
                return;
            }

            var manager = MagicaPhysicsManager.Instance;

            Gizmos.color = GizmoUtility.ColorAdjustLine;

            int cnt = clothData.AdjustRotationConstraintCount;

            for (int i = 0; i < cnt; i++)
            {
                var data   = clothData.adjustRotationDataList[i];
                int tindex = data.targetIndex;
                if (tindex < 0)
                {
                    tindex = -tindex - 1;
                }

                int pindex0 = team.ParticleChunk.startIndex + data.keyIndex;
                int pindex1 = team.ParticleChunk.startIndex + tindex;

                Vector3 pos0 = manager.Particle.posList[pindex0];
                Vector3 pos1 = manager.Particle.posList[pindex1];

                Gizmos.DrawLine(pos0, pos1);
            }
        }
Exemple #5
0
        //=========================================================================================
        /// <summary>
        /// ブレンド率設定インスペクタ
        /// </summary>
        protected void UserBlendInspector()
        {
            PhysicsTeam scr = target as PhysicsTeam;

            EditorGUILayout.Space();
            EditorGUILayout.Space();
            EditorGUILayout.Slider(serializedObject.FindProperty("userBlendWeight"), 0.0f, 1.0f, "Blend Weight");
        }
        /// <summary>
        /// アバター着せ替えによるボーン置換
        /// </summary>
        /// <param name="boneReplaceDict"></param>
        public void ReplaceBone(PhysicsTeam team, ClothParams param, Dictionary <Transform, Transform> boneReplaceDict)
        {
            // この呼び出しは ClothActive() の前なので注意!

            // ワールド移動影響ボーン切り替え
            Transform influenceTarget = param.GetInfluenceTarget();

            if (influenceTarget && boneReplaceDict.ContainsKey(influenceTarget))
            {
                param.SetInfluenceTarget(boneReplaceDict[influenceTarget]);
            }
        }
Exemple #7
0
        /// <summary>
        /// コライダー設定インスペクタ
        /// </summary>
        protected void ColliderInspector()
        {
            PhysicsTeam scr = target as PhysicsTeam;

            EditorGUILayout.Space();
            EditorGUILayout.Space();
            EditorGUILayout.LabelField("Collider", EditorStyles.boldLabel);
            EditorGUILayout.PropertyField(serializedObject.FindProperty("teamData.mergeAvatarCollider"));
            EditorInspectorUtility.DrawObjectList <ColliderComponent>(
                serializedObject.FindProperty("teamData.colliderList"),
                scr.gameObject,
                true, true
                );
        }
Exemple #8
0
        public void ClothInactive(PhysicsTeam team)
        {
            if (MagicaPhysicsManager.IsInstance() == false)
            {
                return;
            }

            var manager = MagicaPhysicsManager.Instance;

            // 自身の登録ボーン開放
            manager.Bone.RemoveBone(teamBoneIndex);
            manager.Team.SetBoneIndex(team.TeamId, -1);

            manager.Bone.RemoveBone(teamDirectionalDampingBoneIndex);
            manager.Team.SetDirectionalDampingBoneIndex(team.TeamId, false, -1, 0);
        }
Exemple #9
0
        //=========================================================================================
        /// <summary>
        /// クロス破棄
        /// </summary>
        public void ClothDispose(PhysicsTeam team)
        {
            if (MagicaPhysicsManager.IsInstance() == false)
            {
                return;
            }

            // コンストレイント解放
            MagicaPhysicsManager.Instance.Compute.RemoveTeam(team.TeamId);

            // パーティクル解放
            team.RemoveAllParticle();

            // 自身の登録ボーン開放
            //MagicaPhysicsManager.Instance.Bone.RemoveBone(teamBoneIndex);
        }
Exemple #10
0
        //=========================================================================================
        public void ClothActive(PhysicsTeam team, ClothParams param, ClothData clothData)
        {
            var manager = MagicaPhysicsManager.Instance;

            // ワールド移動影響ボーンを登録
            Transform influenceTarget = param.GetInfluenceTarget() ? param.GetInfluenceTarget() : team.transform;

            teamBoneIndex = manager.Bone.AddBone(influenceTarget);
            manager.Team.SetBoneIndex(team.TeamId, teamBoneIndex);
            team.InfluenceTarget = influenceTarget;

            // 重力方向減衰ボーンを登録
            //Debug.Log("Damp dir:" + clothData.directionalDampingUpDir);
            influenceTarget = param.DirectionalDampingObject ? param.DirectionalDampingObject : team.transform;
            teamDirectionalDampingBoneIndex = manager.Bone.AddBone(influenceTarget);
            manager.Team.SetDirectionalDampingBoneIndex(team.TeamId, param.UseDirectionalDamping, teamDirectionalDampingBoneIndex, clothData.directionalDampingUpDir);
        }
 //=========================================================================================
 /// <summary>
 /// ランタイム状態でのライン表示
 /// </summary>
 /// <param name="scr"></param>
 /// <param name="deformer"></param>
 /// <param name="clothData"></param>
 static void DrawLineRuntime(
     PhysicsTeam team,
     ClothData clothData,
     ClothSetup setup,
     List <int> selList
     )
 {
     if (ClothMonitorMenu.Monitor.UI.DrawClothStructDistanceLine)
     {
         DrawLineRuntimeSub(team, GizmoUtility.ColorStructLine, clothData.structDistanceDataList);
     }
     if (ClothMonitorMenu.Monitor.UI.DrawClothBendDistanceLine)
     {
         DrawLineRuntimeSub(team, GizmoUtility.ColorBendLine, clothData.bendDistanceDataList);
     }
     if (ClothMonitorMenu.Monitor.UI.DrawClothNearDistanceLine)
     {
         DrawLineRuntimeSub(team, GizmoUtility.ColorNearLine, clothData.nearDistanceDataList);
     }
 }
        //=========================================================================================
        /// <summary>
        /// ランタイム状態での回転ライン表示
        /// </summary>
        /// <param name="scr"></param>
        /// <param name="deformer"></param>
        /// <param name="clothData"></param>
        static void DrawRotationLineRuntime(
            PhysicsTeam team,
            ClothData clothData,
            ClothSetup setup,
            List <int> selList
            )
        {
            if (ClothMonitorMenu.Monitor.UI.DrawClothRotationLine == false)
            {
                return;
            }
            if (clothData == null)
            {
                return;
            }
            if (clothData.parentList == null || clothData.parentList.Count != clothData.VertexUseCount)
            {
                return;
            }

            var manager = MagicaPhysicsManager.Instance;

            Gizmos.color = GizmoUtility.ColorRotationLine;

            for (int i = 0; i < clothData.VertexUseCount; i++)
            {
                int pi = clothData.parentList[i];
                if (pi < 0)
                {
                    continue;
                }

                int pindex0 = team.ParticleChunk.startIndex + i;
                int pindex1 = team.ParticleChunk.startIndex + pi;

                Vector3 pos0 = manager.Particle.posList[pindex0];
                Vector3 pos1 = manager.Particle.posList[pindex1];

                Gizmos.DrawLine(pos0, pos1);
            }
        }
        //=========================================================================================
#if false
        /// <summary>
        /// ランタイム状態でのボリューム表示
        /// </summary>
        /// <param name="scr"></param>
        /// <param name="deformer"></param>
        /// <param name="clothData"></param>
        static void DrawVolumeRuntime(
            PhysicsTeam team,
            ClothData clothData,
            ClothSetup setup
            )
        {
            if (ClothMonitorMenu.Monitor.UI.DrawClothVolume == false)
            {
                return;
            }

            var manager = MagicaPhysicsManager.Instance;

            Gizmos.color = GizmoUtility.ColorTriangle;
            int cnt = clothData.VolumeConstraintCount;

            for (int i = 0; i < cnt; i++)
            {
                var data = clothData.volumeDataList[i];

                int pindex0 = team.ParticleChunk.startIndex + data.vindex0;
                int pindex1 = team.ParticleChunk.startIndex + data.vindex1;
                int pindex2 = team.ParticleChunk.startIndex + data.vindex2;
                int pindex3 = team.ParticleChunk.startIndex + data.vindex3;

                Vector3 pos0 = manager.Particle.posList[pindex0];
                Vector3 pos1 = manager.Particle.posList[pindex1];
                Vector3 pos2 = manager.Particle.posList[pindex2];
                Vector3 pos3 = manager.Particle.posList[pindex3];

                Gizmos.DrawLine(pos0, pos1);
                Gizmos.DrawLine(pos0, pos2);
                Gizmos.DrawLine(pos0, pos3);
                Gizmos.DrawLine(pos1, pos2);
                Gizmos.DrawLine(pos2, pos3);
                Gizmos.DrawLine(pos3, pos1);
            }
        }
        //=========================================================================================
        public void ClothActive(PhysicsTeam team, ClothParams param, ClothData clothData)
        {
            var manager = MagicaPhysicsManager.Instance;

            // ワールド移動影響ボーンを登録
            Transform influenceTarget = param.GetInfluenceTarget() ? param.GetInfluenceTarget() : team.transform;

            teamBoneIndex = manager.Bone.AddBone(influenceTarget);
            manager.Team.SetBoneIndex(team.TeamId, teamBoneIndex, clothData.initScale);
            team.InfluenceTarget = influenceTarget;

            // 重力方向減衰ボーンを登録
            //Debug.Log("Damp dir:" + clothData.directionalDampingUpDir);
            //influenceTarget = param.DirectionalDampingObject ? param.DirectionalDampingObject : team.transform;
            //teamDirectionalDampingBoneIndex = manager.Bone.AddBone(influenceTarget);
            //manager.Team.SetDirectionalDampingBoneIndex(team.TeamId, param.UseDirectionalDamping, teamDirectionalDampingBoneIndex, clothData.directionalDampingUpDir);

            // ベーススキニング用ボーンを登録
            //foreach (var bone in team.TeamData.SkinningBoneList)
            //{
            //    var boneIndex = manager.Bone.AddBone(bone);
            //    manager.Team.AddSkinningBoneIndex(team.TeamId, boneIndex);
            //}
        }
        //=========================================================================================
        /// <summary>
        /// ランタイム状態での浸透制限表示
        /// </summary>
        /// <param name="team"></param>
        /// <param name="clothData"></param>
        /// <param name="selList"></param>
        static void DrawPenetrationRuntime(
            PhysicsTeam team,
            ClothParams param,
            ClothData clothData,
            List <int> selList
            )
        {
            if (ClothMonitorMenu.Monitor.UI.DrawClothPenetration == false)
            {
                return;
            }

            if (clothData.penetrationDataList == null)
            {
                return;
            }
            if (clothData.penetrationReferenceList == null)
            {
                return;
            }

            //var mode = param.GetPenetrationMode();
            var mode = clothData.penetrationMode;

            var colliderlist = team.TeamData.ColliderList;

            int vcnt = clothData.useVertexList.Count;

            for (int i = 0; i < vcnt; i++)
            {
                int vindex = clothData.useVertexList[i];
                if (IsMove(vindex, selList) == false)
                {
                    continue;
                }

                int     pindex = team.ParticleChunk.startIndex + i;
                Vector3 pos    = MagicaPhysicsManager.Instance.Particle.posList[pindex];

                if (i >= clothData.penetrationReferenceList.Length)
                {
                    return;
                }
                var refdata = clothData.penetrationReferenceList[i];
                for (int j = 0; j < refdata.count; j++)
                {
                    var dindex = refdata.startIndex + j;
                    var data   = clothData.penetrationDataList[dindex];
                    if (data.IsValid() == false)
                    {
                        continue;
                    }

                    if (mode == ClothParams.PenetrationMode.SurfacePenetration)
                    {
                    }
                    else if (mode == ClothParams.PenetrationMode.ColliderPenetration)
                    {
                        int cindex = data.colliderIndex;
                        if (cindex >= colliderlist.Count)
                        {
                            continue;
                        }

                        var col = colliderlist[cindex];
                        if (col == null)
                        {
                            continue;
                        }

                        var cp = col.transform.TransformPoint(data.localPos);
                        //var pos = cp + col.transform.TransformDirection(data.localDir) * data.distance;

                        Gizmos.color = GizmoUtility.ColorPenetration;
                        Gizmos.DrawLine(pos, cp);
                    }
                }
            }
        }
        public static bool DrawClothGizmo(
            PhysicsTeam team,
            ClothData clothData,
            ClothParams param,
            ClothSetup setup,
            IEditorMesh editorMesh,
            IEditorCloth editorCloth
            )
        {
            if (ClothMonitorMenu.Monitor.UI.DrawCloth == false)
            {
                return(false);
            }

            if (ClothMonitorMenu.Monitor.UI.DrawClothVertex == false &&
                ClothMonitorMenu.Monitor.UI.DrawClothDepth == false &&
                ClothMonitorMenu.Monitor.UI.DrawClothBase == false &&
                ClothMonitorMenu.Monitor.UI.DrawClothCollider == false &&
                ClothMonitorMenu.Monitor.UI.DrawClothStructDistanceLine == false &&
                ClothMonitorMenu.Monitor.UI.DrawClothBendDistanceLine == false &&
                ClothMonitorMenu.Monitor.UI.DrawClothNearDistanceLine == false &&
                ClothMonitorMenu.Monitor.UI.DrawClothRotationLine == false &&
                ClothMonitorMenu.Monitor.UI.DrawClothTriangleBend == false &&
                ClothMonitorMenu.Monitor.UI.DrawClothPenetration == false
                //&& ClothMonitorMenu.Monitor.UI.DrawClothBaseSkinning == false
                && ClothMonitorMenu.Monitor.UI.DrawClothAxis == false
                //&& ClothMonitorMenu.Monitor.UI.DrawClothVolume == false
#if MAGICACLOTH_DEBUG
                && ClothMonitorMenu.Monitor.UI.DrawClothVertexNumber == false &&
                ClothMonitorMenu.Monitor.UI.DrawClothVertexIndex == false &&
                ClothMonitorMenu.Monitor.UI.DrawPenetrationOrigin == false
                //&& ClothMonitorMenu.Monitor.UI.DrawAdjustRotationLine == false
#endif
                )
            {
                return(false);
            }

            if (clothData == null)
            {
                return(false);
            }

            if (Application.isPlaying)
            {
                if (clothData == null)
                {
                    return(false);
                }

                if (team.IsActive() == false)
                {
                    return(false);
                }

                // 頂点使用状態
                //var useList = editorCloth.GetUseList();
                var selList = editorCloth.GetSelectionList();

                // 頂点情報
                DrawVertexRuntime(team, clothData, param, setup, selList);

                // コライダー
                DrawCollider(team);

                // ライン
                DrawLineRuntime(team, clothData, setup, selList);

                // トライアングルベンド
                DrawTriangleBendRuntime(team, clothData, setup);

                // 回転ライン
                DrawRotationLineRuntime(team, clothData, setup, selList);

                // コライダー移動制限
                DrawPenetrationRuntime(team, param, clothData, selList);

                // ボリューム
                //DrawVolumeRuntime(team, clothData, setup);

                // 回転調整ライン
                //DrawAdjustRotationLineRuntime(team, clothData);
            }
            else
            {
                // メッシュ頂点法線接線
                List <Vector3> posList;
                List <Vector3> norList;
                List <Vector3> tanList;
                int            vcnt = editorMesh.GetEditorPositionNormalTangent(out posList, out norList, out tanList);

                // 頂点使用状態
                //var useList = editorCloth.GetUseList();
                var selList = editorCloth.GetSelectionList();

                // 頂点情報
                DrawVertexClothData(clothData, param, vcnt, posList, norList, tanList, selList);

                // コライダー
                DrawCollider(team);

                // ライン
                DrawLineClothData(clothData, posList, selList);

                // トライアングルベンド
                DrawTriangleBendClothData(clothData, posList);

                // 回転ライン
                DrawRotationLineClothData(clothData, posList, selList);

                // コライダー移動制限
                DrawPenetrationClothData(team, param, clothData, posList, norList, tanList, selList);

                // ベーススキニング
                //DrawBaseSkinningClothData(team, clothData, posList, selList);

                // ボリューム
                //DrawVolumeClothData(clothData, posList);

                // 回転調整ライン
                //DrawAdjustRotationLineClothData(clothData, posList);
            }

            return(true);
        }
Exemple #17
0
        //=========================================================================================
        /// <summary>
        /// ランタイムデータ変更
        /// </summary>
        public void ChangeData(PhysicsTeam team, ClothParams param)
        {
            if (Application.isPlaying == false)
            {
                return;
            }

            if (MagicaPhysicsManager.IsInstance() == false)
            {
                return;
            }

            if (team == null)
            {
                return;
            }

            var manager = MagicaPhysicsManager.Instance;
            var compute = manager.Compute;

            bool changeMass = false;

            // 半径
            if (param.ChangedParam(ClothParams.ParamType.Radius))
            {
                // これはパーティクルごと
                for (int i = 0; i < team.ParticleChunk.dataLength; i++)
                {
                    int   pindex = team.ParticleChunk.startIndex + i;
                    float depth  = manager.Particle.depthList[pindex];
                    float radius = param.GetRadius(depth);
                    manager.Particle.SetRadius(pindex, radius);
                }
            }

            // 重量
            if (param.ChangedParam(ClothParams.ParamType.Mass))
            {
                manager.Team.SetMass(team.TeamId, param.GetMass());
                changeMass = true;
            }

            // 重力係数
            if (param.ChangedParam(ClothParams.ParamType.Gravity))
            {
                manager.Team.SetGravity(team.TeamId, param.GetGravity());
                manager.Team.SetDirectionalDamping(team.TeamId, param.GetDirectionalDamping());
                manager.Team.SetFlag(team.TeamId, PhysicsManagerTeamData.Flag_DirectionalDamping, param.UseDirectionalDamping);
            }

            // 空気抵抗
            if (param.ChangedParam(ClothParams.ParamType.Drag))
            {
                manager.Team.SetDrag(team.TeamId, param.GetDrag());
            }

            // 最大速度
            if (param.ChangedParam(ClothParams.ParamType.MaxVelocity))
            {
                manager.Team.SetMaxVelocity(team.TeamId, param.GetMaxVelocity());
            }

            // 外力
            if (param.ChangedParam(ClothParams.ParamType.ExternalForce))
            {
                manager.Team.SetExternalForce(team.TeamId, param.MassInfluence, param.WindInfluence, param.WindRandomScale);
            }

            // チームの摩擦係数変更
            if (param.ChangedParam(ClothParams.ParamType.ColliderCollision))
            {
                manager.Team.SetFriction(team.TeamId, param.Friction);
            }

            // チームワールド移動影響変更
            if (param.ChangedParam(ClothParams.ParamType.WorldInfluence))
            {
                manager.Team.SetWorldInfluence(team.TeamId, param.GetWorldMoveInfluence(), param.GetWorldRotationInfluence(), param.UseResetTeleport, param.TeleportDistance, param.TeleportRotation);
            }

            // 距離復元拘束パラメータ再設定
            if (param.ChangedParam(ClothParams.ParamType.RestoreDistance) || changeMass)
            {
                compute.RestoreDistance.ChangeParam(
                    team.TeamId,
                    param.GetMass(),
                    param.RestoreDistanceVelocityInfluence,
                    param.GetStructDistanceStiffness(),
                    param.UseBendDistance,
                    param.GetBendDistanceStiffness(),
                    param.UseNearDistance,
                    param.GetNearDistanceStiffness()
                    );
            }

            // トライアングルベンド拘束パラメータ再設定
            if (param.ChangedParam(ClothParams.ParamType.TriangleBend))
            {
                compute.TriangleBend.ChangeParam(team.TeamId, param.UseTriangleBend, param.GetTriangleBendStiffness());
            }

            // ボリューム拘束パラメータ再設定
            //if (param.ChangedParam(ClothParams.ParamType.Volume))
            //{
            //    compute.Volume.ChangeParam(team.TeamId, param.UseVolume, param.GetVolumeStretchStiffness(), param.GetVolumeShearStiffness());
            //}

            // ルートからの最小最大距離拘束パラメータ再設定
            if (param.ChangedParam(ClothParams.ParamType.ClampDistance))
            {
                compute.ClampDistance.ChangeParam(team.TeamId, param.UseClampDistanceRatio, param.ClampDistanceMinRatio, param.ClampDistanceMaxRatio, param.ClampDistanceVelocityInfluence);
            }

            // 移動範囲拘束パラメータ再設定
            if (param.ChangedParam(ClothParams.ParamType.ClampPosition))
            {
                compute.ClampPosition.ChangeParam(team.TeamId, param.UseClampPositionLength, param.GetClampPositionLength(), param.ClampPositionAxisRatio, param.ClampPositionVelocityInfluence);
            }

            // 回転復元拘束パラメータ再設定
            if (param.ChangedParam(ClothParams.ParamType.RestoreRotation))
            {
                compute.RestoreRotation.ChangeParam(team.TeamId, param.UseRestoreRotation, param.GetRotationPower(), param.RestoreRotationVelocityInfluence);
            }

            // 最大回転拘束パラメータ再設定
            if (param.ChangedParam(ClothParams.ParamType.ClampRotation))
            {
                compute.ClampRotation.ChangeParam(
                    team.TeamId,
                    param.UseClampRotation,
                    param.GetClampRotationAngle(),
                    //param.GetClampRotationStiffness(),
                    param.ClampRotationVelocityInfluence
                    );
            }

            // スプリング回転調整パラメータ再設定(これはワーカー)
            if (param.ChangedParam(ClothParams.ParamType.AdjustRotation))
            {
                compute.AdjustRotationWorker.ChangeParam(team.TeamId, param.UseAdjustRotation, (int)param.AdjustRotationMode, param.AdjustRotationVector);
            }

            // コリジョン有無
            if (param.ChangedParam(ClothParams.ParamType.ColliderCollision))
            {
                manager.Team.SetFlag(team.TeamId, PhysicsManagerTeamData.Flag_Collision_KeepShape, param.KeepInitialShape);
                compute.Collision.ChangeParam(team.TeamId, param.UseCollision);
                //compute.EdgeCollision.ChangeParam(team.TeamId, param.UseCollision && param.UseEdgeCollision);
            }

            // スプリング拘束パラメータ再設定
            if (param.ChangedParam(ClothParams.ParamType.Spring))
            {
                compute.Spring.ChangeParam(team.TeamId, param.UseSpring, param.GetSpringPower());
            }

            // 回転補間
            if (param.ChangedParam(ClothParams.ParamType.RotationInterpolation))
            {
                compute.LineWorker.ChangeParam(team.TeamId, param.UseLineAvarageRotation);
                manager.Team.SetFlag(team.TeamId, PhysicsManagerTeamData.Flag_FixedNonRotation, param.UseFixedNonRotation);
            }

            //変更フラグクリア
            param.ClearChangeParam();
        }
Exemple #18
0
        //=========================================================================================
        /// <summary>
        /// クロス初期化
        /// </summary>
        /// <param name="team"></param>
        /// <param name="meshData">メッシュデータ(不要ならnull)</param>
        /// <param name="clothData"></param>
        /// <param name="param"></param>
        /// <param name="funcUserFlag">各頂点の追加フラグ設定アクション</param>
        /// <param name="funcUserTransform">各頂点の連動トランスフォーム設定アクション</param>
        public void ClothInit(
            PhysicsTeam team,
            MeshData meshData,
            ClothData clothData,
            ClothParams param,
            System.Func <int, uint> funcUserFlag
            )
        {
            var manager = MagicaPhysicsManager.Instance;
            var compute = manager.Compute;

            // チームデータ設定
            manager.Team.SetMass(team.TeamId, param.GetMass());
            manager.Team.SetGravity(team.TeamId, param.GetGravity());
            manager.Team.SetDrag(team.TeamId, param.GetDrag());
            manager.Team.SetMaxVelocity(team.TeamId, param.GetMaxVelocity());
            manager.Team.SetFriction(team.TeamId, param.Friction);
            manager.Team.SetExternalForce(team.TeamId, param.MassInfluence, param.WindInfluence, param.WindRandomScale);
            manager.Team.SetDirectionalDamping(team.TeamId, param.GetDirectionalDamping());

            // ワールド移動影響
            manager.Team.SetWorldInfluence(team.TeamId, param.GetWorldMoveInfluence(), param.GetWorldRotationInfluence(), param.UseResetTeleport, param.TeleportDistance, param.TeleportRotation);

            int vcnt = clothData.VertexUseCount;

            Debug.Assert(vcnt > 0);
            Debug.Assert(clothData.useVertexList.Count > 0);

            // パーティクル追加(使用頂点のみ)
            var c = team.CreateParticle(team.TeamId, clothData.useVertexList.Count,
                                        // flag
                                        (i) =>
            {
                bool isFix = clothData.IsFixedVertex(i) || clothData.IsExtendVertex(i);     // 固定もしくは拡張
                uint flag  = 0;
                if (funcUserFlag != null)
                {
                    flag = funcUserFlag(i);     // ユーザーフラグ
                }
                if (isFix)
                {
                    flag |= (PhysicsManagerParticleData.Flag_Kinematic | PhysicsManagerParticleData.Flag_Step_Update);
                }
                flag |= (param.UseCollision && !isFix) ? PhysicsManagerParticleData.Flag_Collision : 0;
                flag |= PhysicsManagerParticleData.Flag_Reset_Position;
                return(flag);
            },
                                        // wpos
                                        null,
                                        // wrot
                                        null,
                                        // depth
                                        (i) =>
            {
                return(clothData.vertexDepthList[i]);
            },
                                        // radius
                                        (i) =>
            {
                float depth = clothData.vertexDepthList[i];
                return(param.GetRadius(depth));
            },
                                        // target local pos
                                        null
                                        );

            manager.Team.SetParticleChunk(team.TeamId, c);

            // 原点スプリング拘束
            if (param.UseSpring)
            {
                // 拘束データ
                int group = compute.Spring.AddGroup(
                    team.TeamId,
                    param.UseSpring,
                    param.GetSpringPower()
                    );
                var teamData = manager.Team.teamDataList[team.TeamId];
                teamData.springGroupIndex = group;
                manager.Team.teamDataList[team.TeamId] = teamData;
            }

            // 原点移動制限
            if (param.UseClampPositionLength)
            {
                // 拘束データ
                int group = compute.ClampPosition.AddGroup(
                    team.TeamId,
                    param.UseClampPositionLength,
                    param.GetClampPositionLength(),
                    param.ClampPositionAxisRatio,
                    param.ClampPositionVelocityInfluence
                    );
                var teamData = manager.Team.teamDataList[team.TeamId];
                teamData.clampPositionGroupIndex       = group;
                manager.Team.teamDataList[team.TeamId] = teamData;
            }

            // ルートからの最大最小距離拘束
            if (param.UseClampDistanceRatio && clothData.ClampDistanceConstraintCount > 0)
            {
                // 拘束データ
                int group = compute.ClampDistance.AddGroup(
                    team.TeamId,
                    param.UseClampDistanceRatio,
                    param.ClampDistanceMinRatio,
                    param.ClampDistanceMaxRatio,
                    param.ClampDistanceVelocityInfluence,
                    clothData.rootDistanceDataList,
                    clothData.rootDistanceReferenceList
                    );
                var teamData = manager.Team.teamDataList[team.TeamId];
                teamData.clampDistanceGroupIndex       = group;
                manager.Team.teamDataList[team.TeamId] = teamData;
            }

            // 距離復元拘束
            if (clothData.StructDistanceConstraintCount > 0 || clothData.BendDistanceConstraintCount > 0 || clothData.NearDistanceConstraintCount > 0)
            {
                // 拘束データ
                int group = compute.RestoreDistance.AddGroup(
                    team.TeamId,
                    param.GetMass(),
                    param.RestoreDistanceVelocityInfluence,
                    param.GetStructDistanceStiffness(),
                    clothData.structDistanceDataList,
                    clothData.structDistanceReferenceList,
                    param.UseBendDistance,
                    param.GetBendDistanceStiffness(),
                    clothData.bendDistanceDataList,
                    clothData.bendDistanceReferenceList,
                    param.UseNearDistance,
                    param.GetNearDistanceStiffness(),
                    clothData.nearDistanceDataList,
                    clothData.nearDistanceReferenceList
                    );
                var teamData = manager.Team.teamDataList[team.TeamId];
                teamData.restoreDistanceGroupIndex     = group;
                manager.Team.teamDataList[team.TeamId] = teamData;
            }

            // 回転復元拘束
            if (param.UseRestoreRotation && clothData.RestoreRotationConstraintCount > 0)
            {
                // 拘束データ
                int group = compute.RestoreRotation.AddGroup(
                    team.TeamId,
                    param.UseRestoreRotation,
                    param.GetRotationPower(),
                    param.RestoreRotationVelocityInfluence,
                    clothData.restoreRotationDataList,
                    clothData.restoreRotationReferenceList
                    );
                var teamData = manager.Team.teamDataList[team.TeamId];
                teamData.restoreRotationGroupIndex     = group;
                manager.Team.teamDataList[team.TeamId] = teamData;
            }

            // 最大回転復元拘束
            if (param.UseClampRotation && clothData.ClampRotationConstraintDataCount > 0)
            {
                // 拘束データ
                int group = compute.ClampRotation.AddGroup(
                    team.TeamId,
                    param.UseClampRotation,
                    param.GetClampRotationAngle(),
                    param.ClampRotationVelocityInfluence,
                    clothData.clampRotationDataList,
                    clothData.clampRotationRootInfoList
                    );
                var teamData = manager.Team.teamDataList[team.TeamId];
                teamData.clampRotationGroupIndex       = group;
                manager.Team.teamDataList[team.TeamId] = teamData;
            }

            // トライアングルベンド拘束
            if (param.UseTriangleBend && clothData.TriangleBendConstraintCount > 0)
            {
                int group = compute.TriangleBend.AddGroup(
                    team.TeamId,
                    param.UseTriangleBend,
                    param.GetTriangleBendStiffness(),
                    clothData.triangleBendDataList,
                    clothData.triangleBendReferenceList,
                    clothData.triangleBendWriteBufferCount
                    );
                var teamData = manager.Team.teamDataList[team.TeamId];
                teamData.triangleBendGroupIndex        = group;
                manager.Team.teamDataList[team.TeamId] = teamData;
            }

            // コライダーコリジョン
            if (param.UseCollision)
            {
                var teamData = manager.Team.teamDataList[team.TeamId];

                // 形状維持フラグ
                teamData.SetFlag(PhysicsManagerTeamData.Flag_Collision_KeepShape, param.KeepInitialShape);

                // エッジコリジョン拘束
                //if (param.UseEdgeCollision && clothData.EdgeCollisionConstraintCount > 0)
                //{
                //    int group = compute.EdgeCollision.AddGroup(
                //        team.TeamId,
                //        param.UseEdgeCollision,
                //        clothData.edgeCollisionDataList,
                //        clothData.edgeCollisionReferenceList,
                //        clothData.edgeCollisionWriteBufferCount
                //        );
                //    teamData.edgeCollisionGroupIndex = group;
                //}

                manager.Team.teamDataList[team.TeamId] = teamData;
            }

#if false
            // ボリューム拘束
            if (param.UseVolume && clothData.VolumeConstraintCount > 0)
            {
                //var sw = new StopWatch().Start();

                int group = compute.Volume.AddGroup(
                    team.TeamId,
                    param.UseVolume,
                    param.GetVolumeStretchStiffness(),
                    param.GetVolumeShearStiffness(),
                    clothData.volumeDataList,
                    clothData.volumeReferenceList,
                    clothData.volumeWriteBufferCount
                    );
                var teamData = manager.Team.teamDataList[team.TeamId];
                teamData.volumeGroupIndex = group;
                manager.Team.teamDataList[team.TeamId] = teamData;

                //sw.Stop();
                //Debug.Log("Volume.AddGroup():" + sw.ElapsedMilliseconds);
            }
#endif

            // 回転調整(これはワーカー)
            if (param.UseAdjustRotation && param.AdjustRotationMode != ClothParams.AdjustMode.None)
            {
                // 拘束データ
                int group = compute.AdjustRotationWorker.AddGroup(
                    team.TeamId,
                    param.UseAdjustRotation,
                    (int)param.AdjustRotationMode,
                    param.AdjustRotationVector,
                    clothData.adjustRotationDataList
                    );
                var teamData = manager.Team.teamDataList[team.TeamId];
                teamData.adjustRotationGroupIndex      = group;
                manager.Team.teamDataList[team.TeamId] = teamData;
            }

            // 回転補間(ワーカー)
            if (clothData.lineRotationDataList != null && clothData.lineRotationDataList.Length > 0)
            {
                // 拘束データ
                int group = compute.LineWorker.AddGroup(
                    team.TeamId,
                    param.UseLineAvarageRotation,
                    clothData.lineRotationDataList,
                    clothData.lineRotationRootInfoList
                    );
                var teamData = manager.Team.teamDataList[team.TeamId];
                teamData.lineWorkerGroupIndex          = group;
                manager.Team.teamDataList[team.TeamId] = teamData;
            }

            // 回転補間
            manager.Team.SetFlag(team.TeamId, PhysicsManagerTeamData.Flag_FixedNonRotation, param.UseFixedNonRotation);
        }
        //=========================================================================================
        /// <summary>
        /// ランタイム状態での頂点表示
        /// </summary>
        /// <param name="scr"></param>
        /// <param name="deformer"></param>
        /// <param name="clothData"></param>
        static void DrawVertexRuntime(
            PhysicsTeam team,
            ClothData clothData,
            ClothParams param,
            ClothSetup setup,
            List <int> selList
            )
        {
            bool drawVertex = ClothMonitorMenu.Monitor.UI.DrawClothVertex;
            bool drawRadius = ClothMonitorMenu.Monitor.UI.DrawClothRadius;
            bool drawDepth  = ClothMonitorMenu.Monitor.UI.DrawClothDepth;
            bool drawBase   = ClothMonitorMenu.Monitor.UI.DrawClothBase;
            bool drawAxis   = ClothMonitorMenu.Monitor.UI.DrawClothAxis;

#if MAGICACLOTH_DEBUG
            bool number          = ClothMonitorMenu.Monitor.UI.DrawClothVertexNumber;
            bool drawIndex       = ClothMonitorMenu.Monitor.UI.DrawClothVertexIndex;
            bool drawFriction    = ClothMonitorMenu.Monitor.UI.DrawClothFriction;
            bool drawDepthNumber = ClothMonitorMenu.Monitor.UI.DrawClothDepthNumber;
#else
            bool number          = false;
            bool drawIndex       = false;
            bool drawFriction    = false;
            bool drawDepthNumber = false;
#endif

            if (!number && !drawVertex && !drawDepth && !drawBase && !drawAxis && !drawIndex && !drawFriction && !drawDepthNumber)
            {
                return;
            }

            // チームスケール
            var   teamTransform = team.InfluenceTarget ? team.InfluenceTarget : team.transform;
            float teamScale     = clothData.initScale.magnitude > 0.0f ? teamTransform.lossyScale.magnitude / clothData.initScale.magnitude : 1.0f;

            int vcnt = clothData.useVertexList.Count;
            for (int i = 0; i < vcnt; i++)
            {
                int     vindex = clothData.useVertexList[i];
                int     pindex = team.ParticleChunk.startIndex + i;
                Vector3 pos    = MagicaPhysicsManager.Instance.Particle.posList[pindex];
                float   depth  = MagicaPhysicsManager.Instance.Particle.depthList[pindex];
                //float radius = PhysicsManager.Instance.Particle.radiusList[pindex];
                float radius = drawRadius ? MagicaPhysicsManager.Instance.Particle.radiusList[pindex].x * teamScale : 0.001f;
                //float radius = param.GetRadius(depth);

                if (drawVertex || drawDepth || drawAxis)
                {
                    Quaternion rot = MagicaPhysicsManager.Instance.Particle.rotList[pindex];
                    Gizmos.color = GetVertexColor(vindex, depth, selList);
                    GizmoUtility.DrawWireSphere(pos, rot, Vector3.one, radius, drawVertex || drawDepth, drawAxis);
                }
                if (drawBase)
                {
                    Vector3    bpos = MagicaPhysicsManager.Instance.Particle.basePosList[pindex];
                    Quaternion brot = MagicaPhysicsManager.Instance.Particle.baseRotList[pindex];
                    Gizmos.color = GizmoUtility.ColorBasePosition;
                    GizmoUtility.DrawWireSphere(bpos, brot, Vector3.one, radius, true, false);
                }

                if (number)
                {
                    Handles.Label(pos, i.ToString());
                }
                if (drawIndex)
                {
                    Handles.Label(pos, pindex.ToString());
                }
                if (drawFriction)
                {
                    float friction = MagicaPhysicsManager.Instance.Particle.frictionList[pindex];
                    Handles.Label(pos, string.Format("{0:#.##}", friction));
                }
                //if (drawDepthNumber)
                if (drawDepth)
                {
                    float d = MagicaPhysicsManager.Instance.Particle.depthList[pindex];
                    Handles.Label(pos, string.Format("{0:#.##}", d));
                }
            }
        }
        //=========================================================================================
#if false
        /// <summary>
        /// エディタ状態でのベーススキニング表示
        /// </summary>
        /// <param name="team"></param>
        /// <param name="clothData"></param>
        /// <param name="posList"></param>
        /// <param name="selList"></param>
        static void DrawBaseSkinningClothData(
            PhysicsTeam team,
            ClothData clothData,
            List <Vector3> posList,
            List <int> selList
            )
        {
            if (ClothMonitorMenu.Monitor.UI.DrawClothBaseSkinning == false)
            {
                return;
            }

            if (clothData.baseSkinningDataList == null)
            {
                return;
            }

            //var boneList = team.TeamData.SkinningBoneList;
            var boneList = team.TeamData.ColliderList;

            //Gizmos.color = GizmoUtility.ColorPenetration;
            for (int i = 0; i < clothData.VertexUseCount; i++)
            {
                int vindex = clothData.useVertexList[i];
                if (vindex >= posList.Count)
                {
                    continue;
                }
                if (IsMove(vindex, selList) == false)
                {
                    continue;
                }

                Vector3 pos = posList[vindex];

                for (int j = 0; j < Define.Compute.BaseSkinningWeightCount; j++)
                {
                    int dindex = i * Define.Compute.BaseSkinningWeightCount + j;
                    if (dindex >= clothData.baseSkinningDataList.Length)
                    {
                        return;
                    }

                    var data = clothData.baseSkinningDataList[dindex];
                    if (data.IsValid() == false)
                    {
                        continue;
                    }

                    int bindex = data.boneIndex;
                    if (bindex >= boneList.Count)
                    {
                        continue;
                    }

                    var bone = boneList[bindex];
                    if (bone == null)
                    {
                        continue;
                    }

                    //Gizmos.color = j == 0 ? Color.red : Color.yellow;
                    Gizmos.color = Color.gray;

#if true
                    Vector3 p, dir, d;
                    bone.CalcNearPoint(pos, out p, out dir, out d, true);
                    Gizmos.DrawLine(pos, p);
#else
                    //var cp = bone.TransformPoint(data.localPos);
                    Vector3 cp;
                    MeshUtility.ClosestPtBoneLine(pos, bone, 0.03f, out cp);
                    Gizmos.DrawLine(pos, cp);
#endif
                }
            }
        }
        //=========================================================================================
        /// <summary>
        /// ランタイム状態での浸透制限表示
        /// </summary>
        /// <param name="team"></param>
        /// <param name="clothData"></param>
        /// <param name="selList"></param>
        static void DrawPenetrationRuntime(
            PhysicsTeam team,
            ClothParams param,
            ClothData clothData,
            List <int> selList
            )
        {
#if !MAGICACLOTH_DEBUG
            if (ClothMonitorMenu.Monitor.UI.DrawClothPenetration == false)
            {
                return;
            }
#else
            if (ClothMonitorMenu.Monitor.UI.DrawClothPenetration == false && ClothMonitorMenu.Monitor.UI.DrawPenetrationOrigin == false)
            {
                return;
            }
#endif

            if (clothData.penetrationDataList == null)
            {
                return;
            }
            if (clothData.penetrationReferenceList == null)
            {
                return;
            }

            //var mode = param.GetPenetrationMode();
            var mode = clothData.penetrationMode;

            var colliderlist = team.TeamData.ColliderList;

            int vcnt = clothData.useVertexList.Count;
            for (int i = 0; i < vcnt; i++)
            {
                int vindex = clothData.useVertexList[i];
                if (IsMove(vindex, selList) == false)
                {
                    continue;
                }

                int     pindex = team.ParticleChunk.startIndex + i;
                Vector3 pos    = MagicaPhysicsManager.Instance.Particle.posList[pindex];

                if (i >= clothData.penetrationReferenceList.Length)
                {
                    return;
                }

#if MAGICACLOTH_DEBUG
                Vector3  cen   = Vector3.zero;
                Vector3  cdir  = Vector3.zero;
                int      ccnt  = 0;
                GUIStyle style = new GUIStyle();
                style.normal.textColor = Color.cyan;
#endif

                var refdata = clothData.penetrationReferenceList[i];
                for (int j = 0; j < refdata.count; j++)
                {
                    var dindex = refdata.startIndex + j;
                    var data   = clothData.penetrationDataList[dindex];
                    if (data.IsValid() == false)
                    {
                        continue;
                    }

                    if (mode == ClothParams.PenetrationMode.SurfacePenetration)
                    {
                    }
                    else if (mode == ClothParams.PenetrationMode.ColliderPenetration)
                    {
                        int cindex = data.colliderIndex;
                        if (cindex >= colliderlist.Count)
                        {
                            continue;
                        }

                        var col = colliderlist[cindex];
                        if (col == null)
                        {
                            continue;
                        }

                        var cp = col.transform.TransformPoint(data.localPos);

#if MAGICACLOTH_DEBUG
                        var dir = col.transform.TransformDirection(data.localDir);
                        var c   = cp + dir * data.distance;
                        cen  += c;
                        cdir += dir;
                        ccnt++;
#endif
                        if (ClothMonitorMenu.Monitor.UI.DrawClothPenetration)
                        {
                            Gizmos.color = GizmoUtility.ColorPenetration;
                            Gizmos.DrawLine(pos, cp);
                        }
                    }
                }

#if MAGICACLOTH_DEBUG
                if (ClothMonitorMenu.Monitor.UI.DrawPenetrationOrigin && ccnt > 0)
                {
                    cen         /= ccnt;
                    cdir        /= ccnt;
                    Gizmos.color = new Color(0.0f, 1.0f, 1.0f);
                    Gizmos.DrawSphere(cen, 0.002f);
                    Gizmos.color = Color.yellow;
                    Gizmos.DrawLine(cen, cen + cdir.normalized * 0.02f);
                    //Handles.color = Color.cyan;
                    Handles.Label(cen, i.ToString(), style);
                }
#endif
            }
        }
        /// <summary>
        /// エディタ状態での浸透制限表示
        /// </summary>
        /// <param name="team"></param>
        /// <param name="clothData"></param>
        /// <param name="posList"></param>
        /// <param name="selList"></param>
        static void DrawPenetrationClothData(
            PhysicsTeam team,
            ClothParams param,
            ClothData clothData,
            List <Vector3> posList,
            List <Vector3> norList,
            List <Vector3> tanList,
            List <int> selList
            )
        {
            if (ClothMonitorMenu.Monitor.UI.DrawClothPenetration == false)
            {
                return;
            }

            if (clothData.penetrationDataList == null)
            {
                return;
            }
            if (clothData.penetrationReferenceList == null)
            {
                return;
            }

            var colliderlist = team.TeamData.ColliderList;

            //var mode = param.GetPenetrationMode();
            var mode = clothData.penetrationMode;

            for (int i = 0; i < clothData.VertexUseCount; i++)
            {
                int vindex = clothData.useVertexList[i];
                if (vindex >= posList.Count)
                {
                    continue;
                }
                if (IsMove(vindex, selList) == false)
                {
                    continue;
                }

                //Vector3 pos = posList[vindex];

                if (i >= clothData.penetrationReferenceList.Length)
                {
                    return;
                }

                var refdata = clothData.penetrationReferenceList[i];
                for (int j = 0; j < refdata.count; j++)
                {
                    var dindex = refdata.startIndex + j;
                    var data   = clothData.penetrationDataList[dindex];
                    if (data.IsValid() == false)
                    {
                        continue;
                    }

                    if (mode == ClothParams.PenetrationMode.SurfacePenetration)
                    {
                        var pos   = posList[vindex];
                        var rot   = Quaternion.LookRotation(norList[vindex], tanList[vindex]);
                        var dir   = rot * data.localDir;
                        var depth = clothData.vertexDepthList[i];
                        var dist  = param.GetPenetrationDistance().Evaluate(depth);

                        Gizmos.color = GizmoUtility.ColorPenetration;
                        Gizmos.DrawLine(pos, pos + dir * dist);
                        break;
                    }
                    else if (mode == ClothParams.PenetrationMode.ColliderPenetration)
                    {
                        int cindex = data.colliderIndex;
                        if (cindex >= colliderlist.Count)
                        {
                            continue;
                        }

                        var col = colliderlist[cindex];
                        if (col == null)
                        {
                            continue;
                        }

                        var cp  = col.transform.TransformPoint(data.localPos);
                        var pos = cp + col.transform.TransformDirection(data.localDir) * data.distance;

                        Gizmos.color = GizmoUtility.ColorPenetration;
                        Gizmos.DrawLine(pos, cp);
                    }
                }
            }
        }