123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400 |
-
- // =================================
- // Namespaces.
- // =================================
- using UnityEngine;
- using System.Collections.Generic;
- // =================================
- // Define namespace.
- // =================================
- namespace MirzaBeig
- {
- namespace Scripting
- {
- namespace Effects
- {
- // =================================
- // Classes.
- // =================================
- [RequireComponent(typeof(ParticleSystem))]
- public class ParticleFlocking : MonoBehaviour
- {
- // =================================
- // Nested classes and structures.
- // =================================
- // ...
- public struct Voxel
- {
- public Bounds bounds;
- public int[] particles;
- public int particleCount;
- }
- // =================================
- // Variables.
- // =================================
- // ...
- [Header("N^2 Mode Settings")]
- public float maxDistance = 0.5f;
- [Header("Forces")]
- public float cohesion = 0.5f;
- public float separation = 0.25f;
- [Header("Voxel Mode Settings")]
- public bool useVoxels = true;
- public bool voxelLocalCenterFromBounds = true;
- public float voxelVolume = 8.0f;
- public int voxelsPerAxis = 5;
- int previousVoxelsPerAxisValue;
- Voxel[] voxels;
- new ParticleSystem particleSystem;
- ParticleSystem.Particle[] particles;
- Vector3[] particlePositions;
- ParticleSystem.MainModule particleSystemMainModule;
-
- [Header("General Performance Settings")]
- [Range(0.0f, 1.0f)]
- public float delay = 0.0f;
- float timer;
- public bool alwaysUpdate = false;
- bool visible;
- // =================================
- // Functions.
- // =================================
- // ...
- void Start()
- {
- particleSystem = GetComponent<ParticleSystem>();
- particleSystemMainModule = particleSystem.main;
- }
- // ...
- void OnBecameVisible()
- {
- visible = true;
- }
- void OnBecameInvisible()
- {
- visible = false;
- }
- // ...
- void buildVoxelGrid()
- {
- int voxelCount =
- voxelsPerAxis * voxelsPerAxis * voxelsPerAxis;
- voxels = new Voxel[voxelCount];
- float voxelSize = voxelVolume / voxelsPerAxis;
- float voxelSizeHalf = voxelSize / 2.0f;
- float voxelVolumeHalf = voxelVolume / 2.0f;
- Vector3 positionBase = transform.position;
- int i = 0;
- for (int x = 0; x < voxelsPerAxis; x++)
- {
- float posX = (-voxelVolumeHalf + voxelSizeHalf) + (x * voxelSize);
- for (int y = 0; y < voxelsPerAxis; y++)
- {
- float posY = (-voxelVolumeHalf + voxelSizeHalf) + (y * voxelSize);
- for (int z = 0; z < voxelsPerAxis; z++)
- {
- float posZ = (-voxelVolumeHalf + voxelSizeHalf) + (z * voxelSize);
- voxels[i].particleCount = 0;
- voxels[i].bounds = new Bounds(positionBase + new Vector3(posX, posY, posZ), Vector3.one * voxelSize);
- i++;
- }
- }
- }
- }
- // ...
- void LateUpdate()
- {
- if (alwaysUpdate || visible)
- {
- if (useVoxels)
- {
- int voxelCount =
- voxelsPerAxis * voxelsPerAxis * voxelsPerAxis;
- if (voxels == null || voxels.Length < voxelCount)
- {
- buildVoxelGrid();
- }
- }
- int maxParticles = particleSystemMainModule.maxParticles;
- if (particles == null || particles.Length < maxParticles)
- {
- particles = new ParticleSystem.Particle[maxParticles];
- particlePositions = new Vector3[maxParticles];
- if (useVoxels)
- {
- for (int i = 0; i < voxels.Length; i++)
- {
- voxels[i].particles = new int[maxParticles];
- }
- }
- }
- timer += Time.deltaTime;
- if (timer >= delay)
- {
- float deltaTime = timer;
- timer = 0.0f;
- particleSystem.GetParticles(particles);
- int particleCount = particleSystem.particleCount;
- float cohesionDeltaTime = cohesion * deltaTime;
- float separationDeltaTime = separation * deltaTime;
- for (int i = 0; i < particleCount; i++)
- {
- particlePositions[i] = particles[i].position;
- }
- if (useVoxels)
- {
- int voxelCount = voxels.Length;
- float voxelSize = voxelVolume / voxelsPerAxis;
- for (int i = 0; i < particleCount; i++)
- {
- for (int j = 0; j < voxelCount; j++)
- {
- if (voxels[j].bounds.Contains(particlePositions[i]))
- {
- voxels[j].particles[voxels[j].particleCount] = i;
- voxels[j].particleCount++;
- break;
- }
- }
- }
- for (int i = 0; i < voxelCount; i++)
- {
- if (voxels[i].particleCount > 1)
- {
- for (int j = 0; j < voxels[i].particleCount; j++)
- {
- Vector3 directionToLocalCenter;
- Vector3 localCenter = particlePositions[voxels[i].particles[j]];
- if (voxelLocalCenterFromBounds)
- {
- directionToLocalCenter = voxels[i].bounds.center - particlePositions[voxels[i].particles[j]];
- }
- else
- {
- for (int k = 0; k < voxels[i].particleCount; k++)
- {
- if (k == j)
- {
- continue;
- }
- localCenter += particlePositions[voxels[i].particles[k]];
- }
- localCenter /= voxels[i].particleCount;
- directionToLocalCenter = localCenter - particlePositions[voxels[i].particles[j]];
- }
- float distanceToLocalCenterSqr = directionToLocalCenter.sqrMagnitude;
- directionToLocalCenter.Normalize();
- Vector3 force = Vector3.zero;
- force += directionToLocalCenter * cohesionDeltaTime;
- force -= directionToLocalCenter * ((1.0f - (distanceToLocalCenterSqr / voxelSize)) * separationDeltaTime);
- Vector3 particleVelocity = particles[voxels[i].particles[j]].velocity;
- particleVelocity.x += force.x;
- particleVelocity.y += force.y;
- particleVelocity.z += force.z;
- particles[voxels[i].particles[j]].velocity = particleVelocity;
- }
- voxels[i].particleCount = 0;
- }
- }
- }
- else
- {
- float maxDistanceSqr = maxDistance * maxDistance;
- Vector3 p1p2_difference;
- for (int i = 0; i < particleCount; i++)
- {
- int localCount = 1;
- Vector3 localCenter = particlePositions[i];
- for (int j = 0; j < particleCount; j++)
- {
- if (j == i)
- {
- continue;
- }
- p1p2_difference.x = particlePositions[i].x - particlePositions[j].x;
- p1p2_difference.y = particlePositions[i].y - particlePositions[j].y;
- p1p2_difference.z = particlePositions[i].z - particlePositions[j].z;
- float distanceSqr = Vector3.SqrMagnitude(p1p2_difference);
- // TODO: Expand vector arithmetic for performance.
- if (distanceSqr <= maxDistanceSqr)
- {
- localCount++;
- localCenter += particlePositions[j];
- }
- }
- if (localCount != 1)
- {
- localCenter /= localCount;
- Vector3 directionToLocalCenter = localCenter - particlePositions[i];
- float distanceToLocalCenterSqr = directionToLocalCenter.sqrMagnitude;
- directionToLocalCenter.Normalize();
- Vector3 force = Vector3.zero;
- force += directionToLocalCenter * cohesionDeltaTime;
- force -= directionToLocalCenter * ((1.0f - (distanceToLocalCenterSqr / maxDistanceSqr)) * separationDeltaTime);
- Vector3 particleVelocity = particles[i].velocity;
- particleVelocity.x += force.x;
- particleVelocity.y += force.y;
- particleVelocity.z += force.z;
- particles[i].velocity = particleVelocity;
- }
- //Vector3 velocity = particles[i].velocity;
- //if (velocity != Vector3.zero)
- //{
- // particles[i].rotation3D = Quaternion.LookRotation(velocity, Vector3.up).eulerAngles;
- //}
- }
- }
- particleSystem.SetParticles(particles, particleCount);
- }
- }
- }
- // ...
- void OnDrawGizmosSelected()
- {
- //buildVoxelGrid();
- //for (int i = 0; i < voxels.Length; i++)
- //{
- // Gizmos.DrawWireCube(voxels[i].bounds.center, voxels[i].bounds.size);
- //}
- float size = voxelVolume / voxelsPerAxis;
- float sizeHalf = size / 2.0f;
- float totalSizeHalf = voxelVolume / 2.0f;
- Vector3 positionBase = transform.position;
- Gizmos.color = Color.red;
- Gizmos.DrawWireCube(positionBase, Vector3.one * voxelVolume);
- Gizmos.color = Color.white;
- for (int x = 0; x < voxelsPerAxis; x++)
- {
- float posX = (-totalSizeHalf + sizeHalf) + (x * size);
- for (int y = 0; y < voxelsPerAxis; y++)
- {
- float posY = (-totalSizeHalf + sizeHalf) + (y * size);
- for (int z = 0; z < voxelsPerAxis; z++)
- {
- float posZ = (-totalSizeHalf + sizeHalf) + (z * size);
- Gizmos.DrawWireCube(positionBase + new Vector3(posX, posY, posZ), Vector3.one * size);
- }
- }
- }
- }
- // =================================
- // End functions.
- // =================================
- }
- // =================================
- // End namespace.
- // =================================
- }
- }
- }
- // =================================
- // --END-- //
- // =================================
|