Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- using System;
- using System.Diagnostics;
- using System.Linq;
- using TMPro;
- using Unity.Collections;
- using Unity.Jobs;
- using Unity.VisualScripting;
- using UnityEngine;
- using UnityEngine.Profiling;
- using Unity.Mathematics;
- using UnityEngine.Serialization;
- using Debug = UnityEngine.Debug;
- using Random = UnityEngine.Random;
- public class Simulation : MonoBehaviour
- {
- public struct Particle
- {
- public float2 position, velocity;
- public float mass;
- public Color color;
- }
- public int particleCount;
- public float radius;
- public float mass;
- public float timeScale;
- [Range(1, 2)]
- public float centerConcentration;
- public float galaxySize;
- public Gradient velocityGradient;
- [Range(0, 1)] public float approximationThreshold;
- [Range(0, 1)] public float approximationSmoothing;
- public int treeSize;
- [Header("")]
- public bool centerAttraction;
- public float centerMass;
- public float particleForce;
- public Material material;
- NativeArray<Particle> particles;
- NativeArray<Particle> renderParticles;
- QuadTree quadTree;
- new ParticleRenderer renderer;
- Particle center;
- TextMeshProUGUI latency;
- System.Random random;
- NativeArray<Color> sampledGradient;
- QuadTree[,] trees;
- JobHandle handle;
- public static int HalfScreenSize = 7;
- void Start()
- {
- center = new Particle
- {
- position = Vector2.zero,
- velocity = Vector2.zero,
- mass = centerMass
- };
- random = new System.Random(0);
- particles = new NativeArray<Particle>(particleCount + 1, Allocator.Persistent);
- renderParticles = new NativeArray<Particle>(particleCount + 1, Allocator.Persistent);
- particles[0] = center;
- trees = new QuadTree[treeSize, treeSize];
- sampledGradient = SampleGradient(velocityGradient, 256);
- for (int i = 1; i < particleCount; i++)
- {
- particles[i] = ParticlePositionAndVelocity();
- }
- //latency = GameObject.Find("Latency").GetComponent<TextMeshProUGUI>();
- renderer = new(particles, material, radius);
- quadTree = new();
- }
- Particle ParticlePositionAndVelocity()
- {
- Particle particle;
- while (true)
- {
- // Generate radius using a quadratic distribution for higher central density
- float radius = Mathf.Pow(Random.value, centerConcentration) * galaxySize; // Adjust power for density control
- float angle = Random.Range(0f, Mathf.PI * 2f); // Uniform angle
- // Convert polar coordinates to Cartesian
- Vector2 pos = new Vector2(radius * Mathf.Cos(angle), radius * Mathf.Sin(angle));
- float centerDist = pos.magnitude;
- // Calculate circular orbit velocity
- float force = Mathf.Sqrt(centerMass / centerDist) * particleForce;
- Vector2 tangentDirection = new Vector2(-pos.y, pos.x).normalized; // Tangential direction
- Vector2 velocity = tangentDirection * force;
- // Skip if position is too close to the center to avoid instabilities
- float noise = Mathf.PerlinNoise((pos.x + 1000) * 4, (pos.y + 1000) * 4);
- if (centerDist > 0.2f && (noise > .8f || random.NextDouble() < .1f))
- {
- particle = new Particle
- {
- position = pos,
- velocity = velocity,
- mass = mass,
- color = velocityGradient.Evaluate(noise + 1 - centerDist / galaxySize)
- };
- break;
- }
- }
- return particle;
- }
- void FixedUpdate()
- {
- float startTime = Time.realtimeSinceStartup;
- handle.Complete();
- Profiler.BeginSample("UpdatePositions");
- UpdatePositions(Time.fixedDeltaTime * timeScale);
- Profiler.EndSample();
- for (int i = 0; i < particles.Length; i++)
- {
- renderParticles[i] = particles[i];
- }
- RebuildQuadTree();
- ScheduleAccelerationJob(Time.fixedDeltaTime * timeScale);
- //latency.text = Mathf.RoundToInt(Time.realtimeSinceStartup - startTime) * 1000f + " ms";
- }
- void Update()
- {
- renderer.Render(renderParticles);
- }
- void OnDestroy()
- {
- handle.Complete();
- renderer.ReleaseBuffers();
- particles.Dispose();
- renderParticles.Dispose();
- sampledGradient.Dispose();
- }
- void RebuildQuadTree()
- {
- quadTree = new();
- Profiler.BeginSample("Insert");
- InsertJob job = new()
- {
- particles = particles,
- nodes = quadTree.nodes
- };
- job.Schedule().Complete();
- Profiler.EndSample();
- Profiler.BeginSample("Propagate");
- quadTree.Propagate();
- Profiler.EndSample();
- }
- void ScheduleAccelerationJob(float deltaTime)
- {
- AccelerationJob job = new()
- {
- nodes = quadTree.nodes,
- particles = particles,
- theta = approximationThreshold,
- epsilon = approximationSmoothing,
- deltaTime = deltaTime
- };
- handle = job.Schedule(particles.Length, 64);
- }
- void UpdatePositions(float deltaTime)
- {
- float minPosX = -HalfScreenSize + radius;
- float maxPosX = HalfScreenSize - radius;
- float minPosY = -HalfScreenSize + radius;
- float maxPosY = HalfScreenSize - radius;
- UpdateParticlesJob job = new()
- {
- particles = particles,
- gradient = sampledGradient,
- gradientResolution = sampledGradient.Length,
- deltaTime = deltaTime,
- minPosX = minPosX,
- maxPosX = maxPosX,
- minPosY = minPosY,
- maxPosY = maxPosY,
- rng = new Unity.Mathematics.Random(1)
- };
- job.Schedule(particles.Length, 64).Complete();
- }
- NativeArray<Color> SampleGradient(Gradient gradient, int resolution)
- {
- NativeArray<Color> gradientArray = new(resolution, Allocator.Persistent);
- for (int i = 0; i < resolution; i++)
- {
- gradientArray[i] = gradient.Evaluate((float)i / resolution);
- }
- return gradientArray;
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement