using System; using System.Collections.Generic; using System.Linq; using UniGLTF.SpringBoneJobs.Blittables; using UnityEngine; using UnityEngine.UIElements; using UniVRM10; namespace RotateParticle.Components { [AddComponentMenu("RotateParticle/WarpRoot")] [DisallowMultipleComponent] /// /// Warp の root にアタッチする。 /// 子孫の Transform がすべて登録される。 /// public class WarpRoot : MonoBehaviour { public static BlittableJointMutable DefaultSetting() { return new BlittableJointMutable { stiffnessForce = 1.0f, gravityPower = 0, gravityDir = new Vector3(0, -1.0f, 0), dragForce = 0.4f, radius = 0.02f, }; } public enum ParticleMode { /// /// Use BaseSettings /// Base, /// /// Use specific settings /// Override, /// /// no animation /// Disabled, } /// /// VRM10SpringBoneJoint に相当する /// [Serializable] public struct Particle { public Transform Transform; public ParticleMode Mode; public BlittableJointMutable Settings; public Particle(Transform t, ParticleMode mode, BlittableJointMutable settings) { Transform = t; Mode = mode; Settings = settings; } public Particle(Transform t, BlittableJointMutable settings) : this(t, ParticleMode.Override, settings) { } public Particle(Transform t) : this(t, ParticleMode.Base, DefaultSetting()) { } } [SerializeField] public BlittableJointMutable BaseSettings = DefaultSetting(); /// /// null のときは world root ではなく model root で処理 /// [SerializeField] public Transform Center; /// /// 枝分かれ不可 /// [SerializeField] private List m_particles = new(); public IReadOnlyList Particles => m_particles; [SerializeField] public List ColliderGroups = new(); // uitool kit 向け public List> m_rootitems; // 逆引き Dictionary m_map = new(); void Reset() { m_particles = GetComponentsInChildren().Skip(1).Select(x => new Particle(x)).ToList(); } void OnValidate() { m_map.Clear(); for (int i = 0; i < m_particles.Count; ++i) { var p = m_particles[i]; if (p.Mode == ParticleMode.Base) { p.Settings = BaseSettings; m_particles[i] = p; } m_map.Add(p.Transform, i); } m_rootitems = MakeTree(-1); } public List> MakeTree(int id) { List> items = new(); foreach (Transform child_transform in id==-1 ? transform : m_particles[id].Transform) { var child_id = m_map[child_transform]; var item = (child_transform.childCount > 0) ? new TreeViewItemData(child_id, m_particles[child_id], MakeTree(child_id)) : new TreeViewItemData(child_id, m_particles[child_id]) ; items.Add(item); } return items; } public Particle GetParticle(int id) { return m_particles[id]; } public void UseBaseSettings(Transform t) { if (t == null) return; for (int i = 0; i < m_particles.Count; ++i) { var p = m_particles[i]; if (p.Transform == t) { p.Mode = ParticleMode.Base; p.Settings = BaseSettings; m_particles[i] = p; break; } } } public void SetSettings(Transform t, BlittableJointMutable settings) { if (t == null) return; for (int i = 0; i < m_particles.Count; ++i) { var p = m_particles[i]; if (p.Transform == t) { p.Mode = ParticleMode.Override; p.Settings = settings; m_particles[i] = p; break; } } } // internal List ToList() // { // throw new NotImplementedException(); // } public void OnDrawGizmosSelected() { Gizmos.DrawSphere(transform.position, BaseSettings.radius); foreach (var p in Particles) { if (p.Transform == null || p.Mode == ParticleMode.Disabled) { continue; } Gizmos.DrawWireSphere(p.Transform.position, p.Settings.radius); if (TryGetClosestParent(p.Transform, out var parent)) { Gizmos.DrawLine(p.Transform.position, parent.position); } } } bool TryGetClosestParent(Transform t, out Transform parent) { var current = t.parent; while (current != null) { if (current == transform) { parent = transform; return true; } var index = m_map[current]; var p = m_particles[index]; if (p.Mode != ParticleMode.Disabled) { parent = p.Transform; return true; } } parent = default; return false; } } }