using KdTree.Math;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Pulse : MonoBehaviour
{
private static Vector3[] randomSpherePoints = null;
private static KdTree.KdTree<float, int> randomSphereKd = new KdTree.KdTree<float, int>(3, new SphereMath());
private static Dictionary<int, List<Vector3>> separatedPoints = new Dictionary<int, List<Vector3>>();
private class SphereMath : FloatMath
{
public override float MinValue => -1;
public override float MaxValue => 1;
public override float DistanceSquaredBetweenPoints(float[] a, float[] b)
{
Vector3 normA = new Vector3(a[0], a[1], a[2]);
Vector3 normB = new Vector3(b[0], b[1], b[2]);
return Mathf.Atan2(Vector3.Cross(normA, normB).magnitude, Vector3.Dot(normA, normB));
}
}
private static int randomSpherePointsCount = 300;
private static void GenerateRandomPoints()
{
if (randomSpherePoints != null) return;
randomSpherePoints = new Vector3[randomSpherePointsCount];
for (int i = 0; i < randomSpherePointsCount; i++)
{
bool ok = false;
while (!ok)
{
Vector3 r = UnityEngine.Random.insideUnitSphere;
if (r.sqrMagnitude > 0.000001f)
{
ok = true;
r.Normalize();
randomSpherePoints[i] = r;
randomSphereKd.Add(new float[] { r.x, r.y, r.z }, 0);
}
}
}
}
/*
private class KdTreePoints : IEnumerable<Vector3>
{
private class KdTreeEnumerator : IEnumerator<Vector3>
{
public Vector3 Current => new Vector3(underlying.Current.Point[0], underlying.Current.Point[1], underlying.Current.Point[2]);
object IEnumerator.Current => Current;
public void Dispose() => underlying.Dispose();
public bool MoveNext() => underlying.MoveNext();
public void Reset() => underlying.Reset();
private IEnumerator<KdTree.KdTreeNode<float, int>> underlying;
public KdTreeEnumerator(KdTree.KdTree<float, int> tree)
{
this.underlying = tree.GetEnumerator();
}
}
private KdTree.KdTree<float, int> tree;
public KdTreePoints(KdTree.KdTree<float, int> tree)
{
this.tree = tree;
}
public IEnumerator<Vector3> GetEnumerator() => new KdTreeEnumerator(tree);
IEnumerator IEnumerable.GetEnumerator() => new KdTreeEnumerator(tree);
}
*/
private const float R1_SPHERE_AREA = 4 * Mathf.PI;
private static float ArcLengthOfArea(float area)
{
// area = 2πd^2(1−cos(l / d)), where d = 1 is the sphere radius, and l is the arclength (disk radius)
// area = 2π(1-cos(l))
// area = 2π-2πcos(l)
// 2π-area=2πcos(l)
// (2π-area)/2π=cos(l)
// 1-(area/2π)=cos(l)
// l = acos(1-area/2π)
return Mathf.Acos(1 - area / (Mathf.PI * 2));
}
private static IEnumerable<Vector3> GetNumRandomPointsOnSphere(int numPoints)
{
if (separatedPoints.ContainsKey(numPoints)) return separatedPoints[numPoints];
GenerateRandomPoints();
HashSet<Vector3> remaining = new HashSet<Vector3>(randomSpherePoints);
List<Vector3> points = new List<Vector3>();
float areaPerPoint = R1_SPHERE_AREA / numPoints;
float arclengthPerPoint = ArcLengthOfArea(areaPerPoint);
while (points.Count < numPoints && remaining.Count > 0)
{
int random = Random.Range(0, remaining.Count);
foreach (Vector3 r in remaining)
{
if (random == 0)
{
points.Add(r);
remaining.Remove(r);
foreach (KdTree.KdTreeNode<float, int> close in randomSphereKd.RadialSearch(new float[] { r.x, r.y, r.z }, arclengthPerPoint))
{
remaining.Remove(new Vector3(close.Point[0], close.Point[1], close.Point[2]));
}
break;
}
else
{
random--;
}
}
}
separatedPoints[numPoints] = points;
return separatedPoints[numPoints];
}
public float Lobes = 10;
public float TimeScale = 1;
public float Amount = 0.6f;
private Mesh mesh;
private Vector3[] originalPoints;
private Vector3[] originalNormals;
private Vector3[] points;
// Start is called before the first frame update
void Start()
{
MeshFilter mf = GetComponent<MeshFilter>();
//mesh = GameObject.Instantiate(mf.mesh);
//mf.mesh = mesh;
mesh = mf.mesh;
mesh.RecalculateNormals();
originalPoints = mesh.vertices;
originalNormals = mesh.normals;
points = new Vector3[originalPoints.Length];
}
// Update is called once per frame
void Update()
{
for (int i = 0; i < originalPoints.Length; i++)
{
Vector3 o = originalPoints[i];
Vector3 n = originalNormals[i];
float angleUp = Mathf.Atan2(new Vector2(o.x, o.z).magnitude, o.y);
float expand = Mathf.Sin(Mathf.Atan2(o.x, o.z) * Mathf.Round(Lobes * angleUp) * Mathf.Sin(angleUp * Lobes) + Time.realtimeSinceStartup * Mathf.PI * TimeScale) * Amount;
points[i] = o + n * expand;
}
mesh.vertices = points;
mesh.RecalculateNormals();
mesh.RecalculateBounds();
}
}