PPTGeneratorImage.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332
  1. using UnityEngine;
  2. using System.Collections;
  3. using System.Threading;
  4. using PPTParticleSystem2D;
  5. //Generator for the PPT Particle System
  6. public class PPTGeneratorImage : MonoBehaviour
  7. {
  8. //Core of the PPT Particle System
  9. private PPTParticleSystem physics;
  10. //Texture to make as a particle system
  11. //Alpha Channel supported (each alpha = 0 means no particle)
  12. public Texture2D image;
  13. //Final ressolution for the particle system
  14. //Small value mean more resolution
  15. [Range(0.1f, 100)]
  16. public float resolution = 6;
  17. //A minium and maxim value for a random mass for the particles
  18. public float minimMassValue = 0.4f;
  19. public float maxMassValue = 0.8f;
  20. //Values for the spring and damping particles system
  21. public float springConstant=0.02f, damping=0.04f;
  22. //Alpha cut off value to make the particle system
  23. [Range(0, 1)]
  24. public float alphaCutOff = 0;
  25. //Particle Sistem from unity used to make the render of the particles
  26. public ParticleSystem ParticleSystem;
  27. //External forces applyied to the system
  28. public PPTForceParticle[] externalForces;
  29. //Use or not the localTransformPosition from the external forces
  30. public bool localPosition = false;
  31. //Particle method system to calculate the steps
  32. public PPTParticleSystem.IntegratorSystem integratorSystem;
  33. //Bolean flag to know if the particle system is loaded
  34. public bool isLoaded;
  35. //Value to make more viscosity effect
  36. [Range(0, 0.7f)]
  37. public float somedrag;
  38. //Enable or disable the srpings system
  39. public bool springsActivated = true;
  40. //size of the system
  41. public float size = 1;
  42. //Internal variables for the map of the texture.
  43. private int widthSmall, heightSmall, numPixelsSmall;
  44. private PPTParticle[] particles;
  45. private PPTSpring[] springs;
  46. private PPTParticle[] fixedParticles;
  47. private Color[] colors;
  48. private float[] forceInstance;
  49. private bool[] activeInstance;
  50. private PPTParticle[] instances;
  51. private PPTAttraction[,] attracts;
  52. private UnityEngine.ParticleSystem.Particle[] parts;
  53. private bool m_springsActivated=true;
  54. //Multi thread for optimitzation
  55. private Thread thread;
  56. private Mutex mainLoop;
  57. void OnApplicationQuit()
  58. {
  59. //Kill the thread from the PPTParticleSystem
  60. thread.Abort();
  61. }
  62. void Start()
  63. {
  64. //Start the loading for the PPTParticleSystem
  65. LoadParticles();
  66. }
  67. // Use this for initialization
  68. public void LoadParticles()
  69. {
  70. isLoaded = false;
  71. //get the final ressolution for the system
  72. widthSmall = (int)(image.width / resolution);
  73. heightSmall = (int)(image.height / resolution);
  74. numPixelsSmall = 0;
  75. for (int x = 0; x < widthSmall; x++)
  76. {
  77. for (int y = 0; y < heightSmall; y++)
  78. {
  79. //Count each particle from the alpha cut off
  80. Color c = image.GetPixel((int)(x * resolution), (int)(y * resolution));
  81. if (c.a > alphaCutOff)
  82. numPixelsSmall++;
  83. }
  84. }
  85. //numPixelsSmall had the final number of particles for all the system
  86. Debug.Log("Generator : PPTParticleSystem - width : " + widthSmall + " - height : " + heightSmall + " - number of particles : " + numPixelsSmall);
  87. //Define an array for the colors of the image
  88. colors = new Color[numPixelsSmall];
  89. //Define a PPTParticle system
  90. physics = new PPTParticleSystem(0f, somedrag);
  91. //Define the integrator system
  92. physics.setIntegrator(integratorSystem);
  93. //Define one particle array system
  94. particles = new PPTParticle[numPixelsSmall];
  95. //Define another array of the particle system for the static position
  96. fixedParticles = new PPTParticle[numPixelsSmall];
  97. //Define each spring for each particle
  98. springs = new PPTSpring[numPixelsSmall];
  99. //Define each attract for the external force
  100. attracts = new PPTAttraction[externalForces.Length, numPixelsSmall];
  101. //Define each external force instance
  102. instances = new PPTParticle[externalForces.Length];
  103. forceInstance = new float[externalForces.Length];
  104. activeInstance = new bool[externalForces.Length];
  105. //For each external force, make a fixed particle
  106. Vector3 v = new Vector3(0, 0, 0);
  107. for (int i = 0; i < externalForces.Length; i++)
  108. {
  109. if (localPosition)
  110. v = externalForces[i].transform.localPosition;
  111. else
  112. v = externalForces[i].transform.position;
  113. //Make a fixed particle
  114. instances[i] = physics.makeParticle(1, v.x, v.y, v.z);
  115. instances[i].makeFixed();
  116. forceInstance[i] = externalForces[i].forceParticle;
  117. activeInstance[i] = externalForces[i].gameObject.activeSelf;
  118. }
  119. //Now we work with the particle's system
  120. int a = 0;
  121. for (int x = 0; x < widthSmall; x++)
  122. {
  123. for (int y = 0; y < heightSmall; y++)
  124. {
  125. //get the current color of the image
  126. Color c = image.GetPixel((int)(x * resolution), (int)(y * resolution));
  127. //if alpha cut off
  128. if (c.a > alphaCutOff)
  129. {
  130. //get the current color
  131. colors[a] = image.GetPixel((int)(x * resolution), (int)(y * resolution));
  132. //make a particle
  133. particles[a] = physics.makeParticle(
  134. Random.Range(minimMassValue, maxMassValue),
  135. (x * resolution - widthSmall * resolution / 2)/(60/size),
  136. (y * resolution - heightSmall * resolution / 2)/(60/size), 0);
  137. //make a static particle
  138. fixedParticles[a] = physics.makeParticle(
  139. Random.Range(minimMassValue, maxMassValue),
  140. (x * resolution - widthSmall * resolution / 2)/(60/size),
  141. (y * resolution - heightSmall * resolution / 2)/(60/size), 0);
  142. //active the fixed particle for the static particle
  143. fixedParticles[a].makeFixed();
  144. int i = 0;
  145. //for each force...
  146. foreach (PPTParticle p in instances)
  147. {
  148. //apply the attracttion for each external force
  149. attracts[i, a] = physics.makeAttraction(particles[a], p, forceInstance[i], 0.1f);
  150. if (!activeInstance[i])
  151. //turn off the current attractot if the external force isn't enabled
  152. attracts[i, a].turnOff();
  153. i++;
  154. }
  155. //Finally make the spring joint between particle and fixed particle
  156. springs[a] = physics.makeSpring(particles[a], fixedParticles[a], springConstant, damping, 0);
  157. a++;
  158. }
  159. }
  160. }
  161. //Particle system loaded
  162. isLoaded = true;
  163. //Internal array of particles to work with the Unityt particle system
  164. parts = new ParticleSystem.Particle[numPixelsSmall];
  165. mainLoop = new Mutex(true);
  166. thread = new Thread(runPhysics);
  167. //Atart a thread to make the particle system run
  168. thread.Start();
  169. //Getting the actual Unity particle system to make the new one
  170. if (ParticleSystem != null)
  171. {
  172. float particleSize = ParticleSystem.startSize;
  173. int i = numPixelsSmall;
  174. while (--i > -1)
  175. {
  176. ParticleSystem.Particle particle = new ParticleSystem.Particle();
  177. particle.position = new Vector2(particles[i].position.x,particles[i].position.y);
  178. particle.startLifetime = float.MaxValue;
  179. particle.remainingLifetime = float.MaxValue;
  180. particle.size = particleSize;
  181. particle.color = colors[i];
  182. parts[i] = particle;
  183. }
  184. ParticleSystem.SetParticles(parts, parts.Length);
  185. ParticleSystem.Play();
  186. }
  187. else {
  188. Debug.LogError("Particle system not setted! Please attach one Unity particle system to the PPTParticleSystem.");
  189. }
  190. }
  191. // Update is called once per frame
  192. void Update()
  193. {
  194. //For each force, update the state, force and position
  195. updateExternalForces();
  196. //Make the update of the particle system
  197. if (physics != null)
  198. updateParticleSystem();
  199. //Update the spring relations into the PPT Particle System
  200. updateSpringSystem();
  201. mainLoop.ReleaseMutex();
  202. mainLoop.WaitOne();
  203. }
  204. private void updateSpringSystem()
  205. {
  206. //Reload the spring state
  207. if (m_springsActivated != springsActivated)
  208. {
  209. m_springsActivated = springsActivated;
  210. foreach (PPTSpring s in springs)
  211. if (m_springsActivated)
  212. s.turnOn();
  213. else
  214. s.turnOff();
  215. }
  216. }
  217. private void updateExternalForces()
  218. {
  219. Vector3 v = new Vector3(0, 0, 0);
  220. for (int i = 0; i < externalForces.Length; i++)
  221. {
  222. if (localPosition)
  223. v = externalForces[i].transform.localPosition;
  224. else
  225. v = externalForces[i].transform.position;
  226. //Update position for each external force
  227. instances[i].position.x = v.x;
  228. instances[i].position.y = v.y;
  229. if (forceInstance[i] != externalForces[i].forceParticle || activeInstance[i] != externalForces[i].gameObject.activeSelf)
  230. {
  231. forceInstance[i] = externalForces[i].forceParticle;
  232. activeInstance[i] = externalForces[i].gameObject.activeSelf;
  233. if (activeInstance[i])
  234. for (int a = 0; a < numPixelsSmall; a++)
  235. {
  236. //Turn on and setup the force for the external force
  237. attracts[i, a].turnOn();
  238. attracts[i, a].setStrength(forceInstance[i]);
  239. }
  240. else
  241. for (int a = 0; a < numPixelsSmall; a++)
  242. //Turn off the external force
  243. attracts[i, a].turnOff();
  244. }
  245. }
  246. }
  247. public void runPhysics()
  248. {
  249. while (true)
  250. {
  251. //Thread to run the core of the PPT Particle System
  252. Thread.Sleep(0);
  253. physics.tick();
  254. mainLoop.WaitOne();
  255. mainLoop.ReleaseMutex();
  256. }
  257. }
  258. public void updateParticleSystem()
  259. {
  260. //Get the current array of particles
  261. ParticleSystem.GetParticles(parts);
  262. //For each particle of Unity particle system, update the position and life
  263. int i = Mathf.Min(numPixelsSmall, particles.Length);
  264. while (--i > -1)
  265. {
  266. parts[i].position = new Vector2(particles[i].position.x, particles[i].position.y);
  267. parts[i].remainingLifetime = float.MaxValue;
  268. }
  269. //Attach the new array to the current Unity particle system
  270. ParticleSystem.SetParticles(parts, particles.Length);
  271. }
  272. }