// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. See LICENSE in the project root for license information. using System.Collections.Generic; using UnityEngine; namespace HoloToolkit.Unity.UX { [ExecuteInEditMode] public class LineObjectSwarm : MonoBehaviour { const int RandomValueResolution = 1024; public List<Transform> Objects = new List<Transform>(); [Range(0, 100)] public int Seed = 0; [SerializeField] private LineBase source; [Header("Noise Settings")] public float ScaleMultiplier = 10f; public float SpeedMultiplier = 1f; public float StrengthMultiplier = 0.5f; public Vector3 AxisStrength = Vector3.one; public Vector3 AxisSpeed = Vector3.one; public Vector3 AxisOffset = Vector3.zero; private Vector3[] prevPoints; private System.Random randomPosition; private System.Random randomRotation; private FastSimplexNoise noise = new FastSimplexNoise(); [Header("Swarm Settings")] [Range(0f, 1f)] public float NormalizedDistance = 0f; public Vector3 SwarmScale = Vector3.one; public AnimationCurve ObjectScale = AnimationCurve.Linear(0f, 1f, 1f, 1f); public AnimationCurve ObjectOffset = AnimationCurve.Linear(0f, 0f, 1f, 0f); public RotationTypeEnum RotationTypeOverride = RotationTypeEnum.None; public bool SwarmVelocities = true; public float VelocityBlend = 0.5f; public Vector3 RotationOffset = Vector3.zero; public Vector3 AxisScale = Vector3.one; public virtual LineBase Source { get { if (source == null) { source = GetComponent<LineBase>(); } return source; } set { source = value; if (source == null) { enabled = false; } } } public Vector3 GetRandomPoint() { Vector3 randomPoint = Vector3.one; randomPoint.x = (float)randomPosition.Next(-RandomValueResolution, RandomValueResolution) / (RandomValueResolution * 2); randomPoint.y = (float)randomPosition.Next(-RandomValueResolution, RandomValueResolution) / (RandomValueResolution * 2); randomPoint.z = (float)randomPosition.Next(-RandomValueResolution, RandomValueResolution) / (RandomValueResolution * 2); return Vector3.Scale(randomPoint, SwarmScale); } public void Update() { UpdateCollection(); #if UNITY_EDITOR UnityEditor.EditorUtility.SetDirty(gameObject); #endif } public void UpdateCollection() { if (Source == null) { return; } if (prevPoints == null || prevPoints.Length != Objects.Count) { prevPoints = new Vector3[Objects.Count]; } randomPosition = new System.Random(Seed); Vector3 linePoint = source.GetPoint(NormalizedDistance); Quaternion lineRotation = source.GetRotation(NormalizedDistance, RotationTypeOverride); for (int i = 0; i < Objects.Count; i++) { if (Objects[i] == null) { continue; } Vector3 point = source.transform.TransformVector(GetRandomPoint()); point.x = (float)(point.x + (noise.Evaluate((point.x + AxisOffset.x) * ScaleMultiplier, Time.unscaledTime * AxisSpeed.x * SpeedMultiplier)) * AxisStrength.x * StrengthMultiplier); point.y = (float)(point.y + (noise.Evaluate((point.y + AxisOffset.y) * ScaleMultiplier, Time.unscaledTime * AxisSpeed.y * SpeedMultiplier)) * AxisStrength.y * StrengthMultiplier); point.z = (float)(point.z + (noise.Evaluate((point.z + AxisOffset.z) * ScaleMultiplier, Time.unscaledTime * AxisSpeed.z * SpeedMultiplier)) * AxisStrength.z * StrengthMultiplier); Objects[i].position = point + linePoint; if (SwarmVelocities) { Vector3 velocity = prevPoints[i] - point; Objects[i].rotation = Quaternion.Lerp(lineRotation, Quaternion.LookRotation(velocity, Vector3.up), VelocityBlend); } else { Objects[i].rotation = lineRotation; } Objects[i].Rotate(RotationOffset); prevPoints[i] = point; } } } }