LightningBoltScript.cs 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829
  1. //
  2. // Procedural Lightning for Unity
  3. // (c) 2015 Digital Ruby, LLC
  4. // Source code may be used for personal or commercial projects.
  5. // Source code may NOT be redistributed or sold.
  6. //
  7. // uncomment to enable profiling using stopwatch and debug.log
  8. // #define ENABLE_PROFILING
  9. using System;
  10. using System.Collections;
  11. using System.Collections.Generic;
  12. using System.Diagnostics;
  13. using System.Threading;
  14. using UnityEngine;
  15. namespace DigitalRuby.ThunderAndLightning
  16. {
  17. /// <summary>
  18. /// Lightning bolt script
  19. /// </summary>
  20. public class LightningBoltScript : MonoBehaviour
  21. {
  22. #region Public variables
  23. /// <summary>The camera the lightning should be shown in. Defaults to the current camera, or the main camera if current camera is null. If you are using a different camera, you may want to put the lightning in it's own layer and cull that layer out of any other cameras.</summary>
  24. [Header("Lightning General Properties")]
  25. [Tooltip("The camera the lightning should be shown in. Defaults to the current camera, or the main camera if current camera is null. If you are using a different " +
  26. "camera, you may want to put the lightning in it's own layer and cull that layer out of any other cameras.")]
  27. public Camera Camera;
  28. /// <summary>Type of camera mode. Auto detects the camera and creates appropriate lightning. Can be overriden to do something more specific regardless of camera.</summary>
  29. [Tooltip("Type of camera mode. Auto detects the camera and creates appropriate lightning. Can be overriden to do something more specific regardless of camera.")]
  30. public CameraMode CameraMode = CameraMode.Auto;
  31. internal CameraMode calculatedCameraMode = CameraMode.Unknown;
  32. /// <summary>True if you are using world space coordinates for the lightning bolt, false if you are using coordinates relative to the parent game object.</summary>
  33. [Tooltip("True if you are using world space coordinates for the lightning bolt, false if you are using coordinates relative to the parent game object.")]
  34. public bool UseWorldSpace = true;
  35. /// <summary>Whether to compensate for the parent transform. Default is false. If true, rotation, scale and position are altered by the parent transform. Use this to fix scaling, rotation and other offset problems with the lightning.</summary>
  36. [Tooltip("Whether to compensate for the parent transform. Default is false. If true, rotation, scale and position are altered by the parent transform. " +
  37. "Use this to fix scaling, rotation and other offset problems with the lightning.")]
  38. public bool CompensateForParentTransform = false;
  39. /// <summary>Lightning quality setting. This allows setting limits on generations, lights and shadow casting lights based on the global quality setting.</summary>
  40. [Tooltip("Lightning quality setting. This allows setting limits on generations, lights and shadow casting lights based on the global quality setting.")]
  41. public LightningBoltQualitySetting QualitySetting = LightningBoltQualitySetting.UseScript;
  42. /// <summary>Whether to use multi-threaded generation of lightning. Lightning will be delayed by about 1 frame if this is turned on, but this can significantly improve performance.</summary>
  43. [Tooltip("Whether to use multi-threaded generation of lightning. Lightning will be delayed by about 1 frame if this is turned on, but this can significantly improve performance.")]
  44. public bool MultiThreaded;
  45. /// <summary>If non-zero, the Camera property is used to get distance of lightning from camera. Lightning generations is reduced for each distance from camera. For example, if LevelOfDetailDistance was 100 and the lightning was 200 away from camera, generations would be reduced by 2, to a minimum of 1.</summary>
  46. [Range(0.0f, 1000.0f)]
  47. [Tooltip("If non-zero, the Camera property is used to get distance of lightning from camera. Lightning generations is reduced for each distance from camera. For example, " +
  48. "if LevelOfDetailDistance was 100 and the lightning was 200 away from camera, generations would be reduced by 2, to a minimum of 1.")]
  49. public float LevelOfDetailDistance;
  50. /// <summary>True to use game time, false to use real time</summary>
  51. [Tooltip("True to use game time, false to use real time")]
  52. public bool UseGameTime;
  53. #if UNITY_EDITOR
  54. /// <summary>
  55. /// True to hide gizmos, false otherwise
  56. /// </summary>
  57. public bool HideGizmos;
  58. #endif
  59. /// <summary>Sort layer name</summary>
  60. [Header("Lightning 2D Settings")]
  61. [Tooltip("Sort layer name")]
  62. public string SortLayerName;
  63. /// <summary>Order in sort layer</summary>
  64. [Tooltip("Order in sort layer")]
  65. public int SortOrderInLayer;
  66. /// <summary>Soft particles factor. 0.01 to 3.0 are typical, 100.0 to disable.</summary>
  67. [Header("Lightning Rendering Properties")]
  68. [Tooltip("Soft particles factor. 0.01 to 3.0 are typical, 100.0 to disable.")]
  69. [Range(0.01f, 100.0f)]
  70. public float SoftParticlesFactor = 3.0f;
  71. /// <summary>The render queue for the lightning. -1 for default.</summary>
  72. [Tooltip("The render queue for the lightning. -1 for default.")]
  73. public int RenderQueue = -1;
  74. /// <summary>Lightning material for mesh renderer - glow</summary>
  75. [Tooltip("Lightning material for mesh renderer - glow")]
  76. public Material LightningMaterialMesh;
  77. /// <summary>Lightning material for mesh renderer - bolt</summary>
  78. [Tooltip("Lightning material for mesh renderer - bolt")]
  79. public Material LightningMaterialMeshNoGlow;
  80. /// <summary>The texture to use for the lightning bolts, or null for the material default texture.</summary>
  81. [Tooltip("The texture to use for the lightning bolts, or null for the material default texture.")]
  82. public Texture2D LightningTexture;
  83. /// <summary>The texture to use for the lightning glow, or null for the material default texture.</summary>
  84. [Tooltip("The texture to use for the lightning glow, or null for the material default texture.")]
  85. public Texture2D LightningGlowTexture;
  86. /// <summary>Particle system to play at the point of emission (start). 'Emission rate' particles will be emitted all at once.</summary>
  87. [Tooltip("Particle system to play at the point of emission (start). 'Emission rate' particles will be emitted all at once.")]
  88. public ParticleSystem LightningOriginParticleSystem;
  89. /// <summary>Particle system to play at the point of impact (end). 'Emission rate' particles will be emitted all at once.</summary>
  90. [Tooltip("Particle system to play at the point of impact (end). 'Emission rate' particles will be emitted all at once.")]
  91. public ParticleSystem LightningDestinationParticleSystem;
  92. /// <summary>Tint color for the lightning</summary>
  93. [Tooltip("Tint color for the lightning")]
  94. public Color LightningTintColor = Color.white;
  95. /// <summary>Tint color for the lightning glow</summary>
  96. [Tooltip("Tint color for the lightning glow")]
  97. public Color GlowTintColor = new Color(0.1f, 0.2f, 1.0f, 1.0f);
  98. /// <summary>Allow tinting the main trunk differently than forks.</summary>
  99. [Tooltip("Allow tintint the main trunk differently than forks.")]
  100. public Color MainTrunkTintColor = new Color(1.0f, 1.0f, 1.0f, 1.0f);
  101. /// <summary>Source blend mode. Default is SrcAlpha.</summary>
  102. [Tooltip("Source blend mode. Default is SrcAlpha.")]
  103. public UnityEngine.Rendering.BlendMode SourceBlendMode = UnityEngine.Rendering.BlendMode.SrcAlpha;
  104. /// <summary>Destination blend mode. Default is One. For additive blend use One. For alpha blend use OneMinusSrcAlpha.</summary>
  105. [Tooltip("Destination blend mode. Default is One. For additive blend use One. For alpha blend use OneMinusSrcAlpha.")]
  106. public UnityEngine.Rendering.BlendMode DestinationBlendMode = UnityEngine.Rendering.BlendMode.One;
  107. /// <summary>Source blend mode glow. Default is SrcAlpha.</summary>
  108. [Tooltip("Source blend mode. Default is SrcAlpha.")]
  109. public UnityEngine.Rendering.BlendMode SourceBlendModeGlow = UnityEngine.Rendering.BlendMode.SrcAlpha;
  110. /// <summary>Destination blend mode glow. Default is One. For additive blend use One. For alpha blend use OneMinusSrcAlpha.</summary>
  111. [Tooltip("Destination blend mode. Default is One. For additive blend use One. For alpha blend use OneMinusSrcAlpha.")]
  112. public UnityEngine.Rendering.BlendMode DestinationBlendModeGlow = UnityEngine.Rendering.BlendMode.One;
  113. /// <summary>Jitter multiplier to randomize lightning size. Jitter depends on trunk width and will make the lightning move rapidly and jaggedly, giving a more lively and sometimes cartoony feel. Jitter may be shared with other bolts depending on materials. If you need different jitters for the same material, create a second script object.</summary>
  114. [Header("Lightning Movement Properties")]
  115. [Tooltip("Jitter multiplier to randomize lightning size. Jitter depends on trunk width and will make the lightning move rapidly and jaggedly, " +
  116. "giving a more lively and sometimes cartoony feel. Jitter may be shared with other bolts depending on materials. If you need different " +
  117. "jitters for the same material, create a second script object.")]
  118. public float JitterMultiplier = 0.0f;
  119. /// <summary>Built in turbulance based on the direction of each segment. Small values usually work better, like 0.2.</summary>
  120. [Tooltip("Built in turbulance based on the direction of each segment. Small values usually work better, like 0.2.")]
  121. public float Turbulence = 0.0f;
  122. /// <summary>Global turbulence velocity for this script</summary>
  123. [Tooltip("Global turbulence velocity for this script")]
  124. public Vector3 TurbulenceVelocity = Vector3.zero;
  125. /// <summary>Flicker intensity, causes lightning to pop in and out rapidly. X = intensity, Y = speed.</summary>
  126. [Tooltip("Flicker intensity, causes lightning to pop in and out rapidly. X = intensity, Y = speed.")]
  127. public Vector2 IntensityFlicker = new Vector2(0.0f, 64.0f);
  128. /// <summary>
  129. /// Fires when lightning bolt is created (trunk width, start, end)
  130. /// </summary>
  131. public Action<LightningBoltParameters, Vector3, Vector3> LightningStartedCallback { get; set; }
  132. /// <summary>
  133. /// Fires when lightning bolt is ended (trunk width, start, end)
  134. /// </summary>
  135. public Action<LightningBoltParameters, Vector3, Vector3> LightningEndedCallback { get; set; }
  136. /// <summary>
  137. /// Fires when a light is added
  138. /// </summary>
  139. public Action<Light> LightAddedCallback { get; set; }
  140. /// <summary>
  141. /// Fires when a light is removed
  142. /// </summary>
  143. public Action<Light> LightRemovedCallback { get; set; }
  144. /// <summary>
  145. /// Whether the script has active lightning bolts
  146. /// </summary>
  147. public bool HasActiveBolts
  148. {
  149. get { return (activeBolts.Count > 0); }
  150. }
  151. /// <summary>
  152. /// The last time value (see unity built in shader variables _Time)
  153. /// </summary>
  154. public static Vector4 TimeVectorSinceStart { get; private set; }
  155. /// <summary>
  156. /// Lightning time since script start
  157. /// </summary>
  158. public static float TimeSinceStart { get; private set; }
  159. /// <summary>
  160. /// Lightning delta time
  161. /// </summary>
  162. public static float DeltaTime { get; private set; }
  163. /// <summary>
  164. /// Lightning time scale - as this approaches 0 time slows down
  165. /// </summary>
  166. public static float TimeScale = 1.0f;
  167. private static bool needsTimeUpdate = true;
  168. #endregion Public variables
  169. #region Public methods
  170. /// <summary>
  171. /// Create a lightning bolt
  172. /// </summary>
  173. /// <param name="p">Lightning bolt creation parameters</param>
  174. public virtual void CreateLightningBolt(LightningBoltParameters p)
  175. {
  176. #if UNITY_EDITOR
  177. if (Camera == null)
  178. {
  179. UnityEngine.Debug.LogError("Camera not assigned to lightning script. Either set the camera or tag your camera as main camera.");
  180. }
  181. #endif
  182. if (p != null && Camera != null)
  183. {
  184. UpdateTexture();
  185. oneParameterArray[0] = p;
  186. LightningBoltDependencies dependencies = CreateLightningBoltDependencies(oneParameterArray);
  187. if (dependencies != null)
  188. {
  189. LightningBolt bolt = GetOrCreateLightningBolt();
  190. bolt.SetupLightningBolt(dependencies);
  191. }
  192. }
  193. }
  194. /// <summary>
  195. /// Create multiple lightning bolts, attempting to batch them into as few draw calls as possible
  196. /// </summary>
  197. /// <param name="parameters">Lightning bolt creation parameters</param>
  198. public void CreateLightningBolts(ICollection<LightningBoltParameters> parameters)
  199. {
  200. #if UNITY_EDITOR
  201. if (Camera == null)
  202. {
  203. UnityEngine.Debug.LogError("Camera not assigned to lightning script. Either set the camera or tag your camera as main camera.");
  204. }
  205. #endif
  206. if (parameters != null && parameters.Count > 0 && Camera != null)
  207. {
  208. UpdateTexture();
  209. LightningBoltDependencies dependencies = CreateLightningBoltDependencies(parameters);
  210. if (dependencies != null)
  211. {
  212. LightningBolt bolt = GetOrCreateLightningBolt();
  213. bolt.SetupLightningBolt(dependencies);
  214. }
  215. }
  216. }
  217. #endregion Public methods
  218. #region Protected methods
  219. /// <summary>
  220. /// AWake
  221. /// </summary>
  222. protected virtual void Awake()
  223. {
  224. UpdateShaderIds();
  225. #if UNITY_EDITOR
  226. if (GetComponents<LightningBoltScript>().Length > 1)
  227. {
  228. UnityEngine.Debug.LogError("Having more than one lightning script attached to one game object is not supported.");
  229. }
  230. #endif
  231. }
  232. /// <summary>
  233. /// Start
  234. /// </summary>
  235. protected virtual void Start()
  236. {
  237. UpdateCamera();
  238. UpdateMaterialsForLastTexture();
  239. UpdateShaderParameters();
  240. CheckCompensateForParentTransform();
  241. UnityEngine.SceneManagement.SceneManager.sceneLoaded += OnSceneLoaded;
  242. #if UNITY_WEBGL
  243. MultiThreaded = false;
  244. #endif
  245. threadState = new LightningThreadState(MultiThreaded);
  246. }
  247. /// <summary>
  248. /// Update
  249. /// </summary>
  250. protected virtual void Update()
  251. {
  252. if (Time.timeScale <= 0.0f)
  253. {
  254. return;
  255. }
  256. if (needsTimeUpdate)
  257. {
  258. needsTimeUpdate = false;
  259. DeltaTime = (UseGameTime ? Time.deltaTime : Time.unscaledDeltaTime) * TimeScale;
  260. TimeSinceStart += DeltaTime;
  261. if (TimeSinceStart >= 16384.0f)
  262. {
  263. TimeSinceStart -= 16384.0f;
  264. }
  265. }
  266. #if DEBUG
  267. if (LightningMaterialMesh == null || LightningMaterialMeshNoGlow == null)
  268. {
  269. UnityEngine.Debug.LogError("Must assign all lightning materials");
  270. }
  271. #endif
  272. if (HasActiveBolts)
  273. {
  274. UpdateCamera();
  275. UpdateShaderParameters();
  276. CheckCompensateForParentTransform();
  277. UpdateActiveBolts();
  278. Shader.SetGlobalVector(shaderId_LightningTime, TimeVectorSinceStart = new Vector4(TimeSinceStart * 0.05f, TimeSinceStart, TimeSinceStart * 2.0f, TimeSinceStart * 3.0f));
  279. }
  280. threadState.UpdateMainThreadActions();
  281. }
  282. /// <summary>
  283. /// LateUpdate
  284. /// </summary>
  285. protected virtual void LateUpdate()
  286. {
  287. needsTimeUpdate = true;
  288. }
  289. /// <summary>
  290. /// Get or create lightning bolt parameters from cache
  291. /// </summary>
  292. /// <returns>LightningBoltParameters</returns>
  293. protected virtual LightningBoltParameters OnCreateParameters()
  294. {
  295. return LightningBoltParameters.GetOrCreateParameters();
  296. }
  297. /// <summary>
  298. /// Get or create lightning bolt parameters from cache, and set quality setting
  299. /// </summary>
  300. /// <returns>LightningBoltParameters</returns>
  301. protected LightningBoltParameters CreateParameters()
  302. {
  303. LightningBoltParameters p = OnCreateParameters();
  304. p.quality = QualitySetting;
  305. PopulateParameters(p);
  306. return p;
  307. }
  308. /// <summary>
  309. /// Derived class can override to fill in lightning bolt parameters
  310. /// </summary>
  311. /// <param name="parameters">Parameters</param>
  312. protected virtual void PopulateParameters(LightningBoltParameters parameters)
  313. {
  314. parameters.MainTrunkTintColor = MainTrunkTintColor;
  315. }
  316. #endregion Protected methods
  317. #region Private variables
  318. internal Material lightningMaterialMeshInternal { get; private set; }
  319. internal Material lightningMaterialMeshNoGlowInternal { get; private set; }
  320. private Texture2D lastLightningTexture;
  321. private Texture2D lastLightningGlowTexture;
  322. private readonly List<LightningBolt> activeBolts = new List<LightningBolt>();
  323. private readonly LightningBoltParameters[] oneParameterArray = new LightningBoltParameters[1];
  324. private readonly List<LightningBolt> lightningBoltCache = new List<LightningBolt>();
  325. private readonly List<LightningBoltDependencies> dependenciesCache = new List<LightningBoltDependencies>();
  326. private LightningThreadState threadState;
  327. // shader ids
  328. private static int shaderId_MainTex = int.MinValue;
  329. private static int shaderId_TintColor;
  330. private static int shaderId_JitterMultiplier;
  331. private static int shaderId_Turbulence;
  332. private static int shaderId_TurbulenceVelocity;
  333. private static int shaderId_SrcBlendMode;
  334. private static int shaderId_DstBlendMode;
  335. private static int shaderId_InvFade;
  336. private static int shaderId_LightningTime;
  337. private static int shaderId_IntensityFlicker;
  338. private static int shaderId_RenderMode;
  339. #endregion Private variables
  340. #region Private methods
  341. private Coroutine StartCoroutineWrapper(IEnumerator routine)
  342. {
  343. if (isActiveAndEnabled)
  344. {
  345. return StartCoroutine(routine);
  346. }
  347. return null;
  348. }
  349. private void OnSceneLoaded(UnityEngine.SceneManagement.Scene arg0, UnityEngine.SceneManagement.LoadSceneMode arg1)
  350. {
  351. LightningBolt.ClearCache();
  352. }
  353. private LightningBoltDependencies CreateLightningBoltDependencies(ICollection<LightningBoltParameters> parameters)
  354. {
  355. if (threadState == null)
  356. {
  357. return null;
  358. }
  359. LightningBoltDependencies d;
  360. if (dependenciesCache.Count == 0)
  361. {
  362. d = new LightningBoltDependencies();
  363. d.AddActiveBolt = AddActiveBolt;
  364. d.LightAdded = OnLightAdded;
  365. d.LightRemoved = OnLightRemoved;
  366. d.ReturnToCache = ReturnLightningDependenciesToCache;
  367. d.StartCoroutine = StartCoroutineWrapper;
  368. d.Parent = gameObject;
  369. }
  370. else
  371. {
  372. int i = dependenciesCache.Count - 1;
  373. d = dependenciesCache[i];
  374. dependenciesCache.RemoveAt(i);
  375. }
  376. d.CameraPos = Camera.transform.position;
  377. d.CameraIsOrthographic = Camera.orthographic;
  378. d.CameraMode = calculatedCameraMode;
  379. d.LevelOfDetailDistance = LevelOfDetailDistance;
  380. d.DestParticleSystem = LightningDestinationParticleSystem;
  381. d.LightningMaterialMesh = lightningMaterialMeshInternal;
  382. d.LightningMaterialMeshNoGlow = lightningMaterialMeshNoGlowInternal;
  383. d.OriginParticleSystem = LightningOriginParticleSystem;
  384. d.SortLayerName = SortLayerName;
  385. d.SortOrderInLayer = SortOrderInLayer;
  386. d.UseWorldSpace = UseWorldSpace;
  387. d.ThreadState = threadState;
  388. // clone parameters list if threading, otherwise just set it
  389. if (threadState.multiThreaded)
  390. {
  391. d.Parameters = new List<LightningBoltParameters>(parameters);
  392. }
  393. else
  394. {
  395. d.Parameters = parameters;
  396. }
  397. d.LightningBoltStarted = LightningStartedCallback;
  398. d.LightningBoltEnded = LightningEndedCallback;
  399. return d;
  400. }
  401. private void ReturnLightningDependenciesToCache(LightningBoltDependencies d)
  402. {
  403. d.Parameters = null;
  404. d.OriginParticleSystem = null;
  405. d.DestParticleSystem = null;
  406. d.LightningMaterialMesh = null;
  407. d.LightningMaterialMeshNoGlow = null;
  408. dependenciesCache.Add(d);
  409. }
  410. internal void OnLightAdded(Light l)
  411. {
  412. if (LightAddedCallback != null)
  413. {
  414. LightAddedCallback(l);
  415. }
  416. }
  417. internal void OnLightRemoved(Light l)
  418. {
  419. if (LightRemovedCallback != null)
  420. {
  421. LightRemovedCallback(l);
  422. }
  423. }
  424. internal void AddActiveBolt(LightningBolt bolt)
  425. {
  426. #if DEBUG
  427. if (bolt == null || activeBolts.Contains(bolt))
  428. {
  429. UnityEngine.Debug.LogError("Attempted to add null or duplicate active lightning bolt");
  430. return;
  431. }
  432. #endif
  433. // only called from the main thread
  434. activeBolts.Add(bolt);
  435. }
  436. private void UpdateShaderIds()
  437. {
  438. if (shaderId_MainTex != int.MinValue)
  439. {
  440. return;
  441. }
  442. shaderId_MainTex = Shader.PropertyToID("_MainTex");
  443. shaderId_TintColor = Shader.PropertyToID("_TintColor");
  444. shaderId_JitterMultiplier = Shader.PropertyToID("_JitterMultiplier");
  445. shaderId_Turbulence = Shader.PropertyToID("_Turbulence");
  446. shaderId_TurbulenceVelocity = Shader.PropertyToID("_TurbulenceVelocity");
  447. shaderId_SrcBlendMode = Shader.PropertyToID("_SrcBlendMode");
  448. shaderId_DstBlendMode = Shader.PropertyToID("_DstBlendMode");
  449. shaderId_InvFade = Shader.PropertyToID("_InvFade");
  450. shaderId_LightningTime = Shader.PropertyToID("_LightningTime");
  451. shaderId_IntensityFlicker = Shader.PropertyToID("_IntensityFlicker");
  452. shaderId_RenderMode = Shader.PropertyToID("_RenderMode");
  453. }
  454. private void UpdateMaterialsForLastTexture()
  455. {
  456. if (!Application.isPlaying)
  457. {
  458. return;
  459. }
  460. calculatedCameraMode = CameraMode.Unknown;
  461. lightningMaterialMeshInternal = new Material(LightningMaterialMesh);
  462. lightningMaterialMeshNoGlowInternal = new Material(LightningMaterialMeshNoGlow);
  463. if (LightningTexture != null)
  464. {
  465. lightningMaterialMeshNoGlowInternal.SetTexture(shaderId_MainTex, LightningTexture);
  466. }
  467. if (LightningGlowTexture != null)
  468. {
  469. lightningMaterialMeshInternal.SetTexture(shaderId_MainTex, LightningGlowTexture);
  470. }
  471. SetupMaterialCamera();
  472. }
  473. private void UpdateTexture()
  474. {
  475. if (LightningTexture != null && LightningTexture != lastLightningTexture)
  476. {
  477. lastLightningTexture = LightningTexture;
  478. UpdateMaterialsForLastTexture();
  479. }
  480. if (LightningGlowTexture != null && LightningGlowTexture != lastLightningGlowTexture)
  481. {
  482. lastLightningGlowTexture = LightningGlowTexture;
  483. UpdateMaterialsForLastTexture();
  484. }
  485. }
  486. private void SetMaterialPerspective()
  487. {
  488. if (calculatedCameraMode != CameraMode.Perspective)
  489. {
  490. calculatedCameraMode = CameraMode.Perspective;
  491. lightningMaterialMeshInternal.SetInt(shaderId_RenderMode, 0);
  492. lightningMaterialMeshNoGlowInternal.SetInt(shaderId_RenderMode, 0);
  493. }
  494. }
  495. private void SetMaterialOrthographicXY()
  496. {
  497. if (calculatedCameraMode != CameraMode.OrthographicXY)
  498. {
  499. calculatedCameraMode = CameraMode.OrthographicXY;
  500. lightningMaterialMeshInternal.SetInt(shaderId_RenderMode, 1);
  501. lightningMaterialMeshNoGlowInternal.SetInt(shaderId_RenderMode, 1);
  502. }
  503. }
  504. private void SetMaterialOrthographicXZ()
  505. {
  506. if (calculatedCameraMode != CameraMode.OrthographicXZ)
  507. {
  508. calculatedCameraMode = CameraMode.OrthographicXZ;
  509. lightningMaterialMeshInternal.SetInt(shaderId_RenderMode, 2);
  510. lightningMaterialMeshNoGlowInternal.SetInt(shaderId_RenderMode, 2);
  511. }
  512. }
  513. private void SetupMaterialCamera()
  514. {
  515. if (Camera == null && CameraMode == CameraMode.Auto)
  516. {
  517. SetMaterialPerspective();
  518. return;
  519. }
  520. if (CameraMode == CameraMode.Auto)
  521. {
  522. if (Camera.orthographic)
  523. {
  524. SetMaterialOrthographicXY();
  525. }
  526. else
  527. {
  528. SetMaterialPerspective();
  529. }
  530. }
  531. else if (CameraMode == CameraMode.Perspective)
  532. {
  533. SetMaterialPerspective();
  534. }
  535. else if (CameraMode == CameraMode.OrthographicXY)
  536. {
  537. SetMaterialOrthographicXY();
  538. }
  539. else
  540. {
  541. SetMaterialOrthographicXZ();
  542. }
  543. }
  544. private void UpdateShaderParameters()
  545. {
  546. lightningMaterialMeshInternal.SetColor(shaderId_TintColor, GlowTintColor);
  547. lightningMaterialMeshInternal.SetFloat(shaderId_JitterMultiplier, JitterMultiplier);
  548. lightningMaterialMeshInternal.SetFloat(shaderId_Turbulence, Turbulence * LightningBoltParameters.Scale);
  549. lightningMaterialMeshInternal.SetVector(shaderId_TurbulenceVelocity, TurbulenceVelocity * LightningBoltParameters.Scale);
  550. lightningMaterialMeshInternal.SetInt(shaderId_SrcBlendMode, (int)SourceBlendModeGlow);
  551. lightningMaterialMeshInternal.SetInt(shaderId_DstBlendMode, (int)DestinationBlendModeGlow);
  552. lightningMaterialMeshInternal.renderQueue = RenderQueue;
  553. lightningMaterialMeshInternal.SetFloat(shaderId_InvFade, SoftParticlesFactor);
  554. lightningMaterialMeshNoGlowInternal.SetColor(shaderId_TintColor, LightningTintColor);
  555. lightningMaterialMeshNoGlowInternal.SetFloat(shaderId_JitterMultiplier, JitterMultiplier);
  556. lightningMaterialMeshNoGlowInternal.SetFloat(shaderId_Turbulence, Turbulence * LightningBoltParameters.Scale);
  557. lightningMaterialMeshNoGlowInternal.SetVector(shaderId_TurbulenceVelocity, TurbulenceVelocity * LightningBoltParameters.Scale);
  558. lightningMaterialMeshNoGlowInternal.SetInt(shaderId_SrcBlendMode, (int)SourceBlendMode);
  559. lightningMaterialMeshNoGlowInternal.SetInt(shaderId_DstBlendMode, (int)DestinationBlendMode);
  560. lightningMaterialMeshNoGlowInternal.renderQueue = RenderQueue;
  561. lightningMaterialMeshNoGlowInternal.SetFloat(shaderId_InvFade, SoftParticlesFactor);
  562. lightningMaterialMeshInternal.SetVector(shaderId_IntensityFlicker, IntensityFlicker);
  563. lightningMaterialMeshNoGlowInternal.SetVector(shaderId_IntensityFlicker, IntensityFlicker);
  564. SetupMaterialCamera();
  565. }
  566. private void CheckCompensateForParentTransform()
  567. {
  568. if (CompensateForParentTransform)
  569. {
  570. Transform p = transform.parent;
  571. if (p != null)
  572. {
  573. transform.position = p.position;
  574. transform.localScale = new Vector3(1.0f / p.localScale.x, 1.0f / p.localScale.y, 1.0f / p.localScale.z);
  575. transform.rotation = p.rotation;
  576. }
  577. }
  578. }
  579. private void UpdateCamera()
  580. {
  581. Camera = (Camera == null ? (Camera.current == null ? Camera.main : Camera.current) : Camera);
  582. }
  583. private LightningBolt GetOrCreateLightningBolt()
  584. {
  585. if (lightningBoltCache.Count == 0)
  586. {
  587. #if ENABLE_PROFILING
  588. Debug.Log("Lightning cache miss");
  589. #endif
  590. return new LightningBolt();
  591. }
  592. LightningBolt b = lightningBoltCache[lightningBoltCache.Count - 1];
  593. lightningBoltCache.RemoveAt(lightningBoltCache.Count - 1);
  594. return b;
  595. }
  596. private void UpdateActiveBolts()
  597. {
  598. for (int i = activeBolts.Count - 1; i >= 0; i--)
  599. {
  600. LightningBolt bolt = activeBolts[i];
  601. if (!bolt.Update())
  602. {
  603. // bolt is done, remove it and put back in cache
  604. activeBolts.RemoveAt(i);
  605. bolt.Cleanup();
  606. lightningBoltCache.Add(bolt);
  607. }
  608. }
  609. }
  610. private void OnApplicationQuit()
  611. {
  612. if (threadState != null && threadState.multiThreaded)
  613. {
  614. threadState.Running = false;
  615. }
  616. }
  617. private void Cleanup()
  618. {
  619. // make sure active bolts are destroyed properly and cleaned up
  620. foreach (LightningBolt bolt in activeBolts)
  621. {
  622. bolt.Cleanup();
  623. }
  624. activeBolts.Clear();
  625. }
  626. private void OnDestroy()
  627. {
  628. if (threadState.multiThreaded)
  629. {
  630. threadState.TerminateAndWaitForEnd(true);
  631. }
  632. if (lightningMaterialMeshInternal != null)
  633. {
  634. GameObject.Destroy(lightningMaterialMeshInternal);
  635. }
  636. if (lightningMaterialMeshNoGlowInternal != null)
  637. {
  638. GameObject.Destroy(lightningMaterialMeshNoGlowInternal);
  639. }
  640. Cleanup();
  641. }
  642. private void OnDisable()
  643. {
  644. Cleanup();
  645. }
  646. #endregion Private methods
  647. }
  648. /// <summary>
  649. /// Fast coroutine for delays
  650. /// </summary>
  651. public class WaitForSecondsLightning : CustomYieldInstruction
  652. {
  653. private static readonly List<WaitForSecondsLightning> pool = new List<WaitForSecondsLightning>();
  654. private float remaining;
  655. /// <summary>
  656. /// Constructor
  657. /// </summary>
  658. /// <param name="time">Time in seconds to wait</param>
  659. public WaitForSecondsLightning(float time)
  660. {
  661. remaining = time;
  662. }
  663. public static WaitForSecondsLightning WaitForSecondsLightningPooled(float time)
  664. {
  665. if (pool.Count == 0)
  666. {
  667. return new WaitForSecondsLightning(time);
  668. }
  669. var idx = pool.Count - 1;
  670. WaitForSecondsLightning pooledObject = pool[idx];
  671. pooledObject.remaining = time;
  672. pooledObject.Reset();
  673. pool.RemoveAt(idx);
  674. return pooledObject;
  675. }
  676. /// <summary>
  677. /// Whether to keep waiting
  678. /// </summary>
  679. public override bool keepWaiting
  680. {
  681. get
  682. {
  683. if (remaining <= 0.0f)
  684. {
  685. pool.Add(this);
  686. return false;
  687. }
  688. remaining -= LightningBoltScript.DeltaTime;
  689. return true;
  690. }
  691. }
  692. }
  693. }