UIParticleRenderer.cs 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724
  1. #if UNITY_2022_3_0 || UNITY_2022_3_1 || UNITY_2022_3_2 || UNITY_2022_3_3 || UNITY_2022_3_4 || UNITY_2022_3_5 || UNITY_2022_3_6 || UNITY_2022_3_7 || UNITY_2022_3_8 || UNITY_2022_3_9 || UNITY_2022_3_10
  2. #elif UNITY_2023_1_0 || UNITY_2023_1_1 || UNITY_2023_1_2 || UNITY_2023_1_3 || UNITY_2023_1_4 || UNITY_2023_1_5 || UNITY_2023_1_6 || UNITY_2023_1_7 || UNITY_2023_1_8 || UNITY_2023_1_9
  3. #elif UNITY_2023_1_10 || UNITY_2023_1_11 || UNITY_2023_1_12 || UNITY_2023_1_13 || UNITY_2023_1_14 || UNITY_2023_1_15 || UNITY_2023_1_16
  4. #elif UNITY_2022_3_OR_NEWER
  5. #define PS_BAKE_API_V2
  6. #endif
  7. using System;
  8. using System.Collections.Generic;
  9. using Coffee.UIParticleInternal;
  10. using UnityEditor;
  11. using UnityEngine;
  12. using UnityEngine.Profiling;
  13. using UnityEngine.Rendering;
  14. using UnityEngine.UI;
  15. namespace Coffee.UIExtensions
  16. {
  17. [Icon("Packages/cn.etetet.yiuieffect/Editor/UIParticleEditor/UIParticleIcon.png")]
  18. [ExecuteAlways]
  19. [RequireComponent(typeof(RectTransform))]
  20. [RequireComponent(typeof(CanvasRenderer))]
  21. [AddComponentMenu("")]
  22. internal class UIParticleRenderer : MaskableGraphic
  23. {
  24. private static readonly CombineInstance[] s_CombineInstances = { new CombineInstance() };
  25. private static readonly List<Material> s_Materials = new List<Material>(2);
  26. private static MaterialPropertyBlock s_Mpb;
  27. private static readonly Vector3[] s_Corners = new Vector3[4];
  28. private bool _delay;
  29. private int _index;
  30. private bool _isPrevStored;
  31. private bool _isTrail;
  32. private Bounds _lastBounds;
  33. private Material _materialForRendering;
  34. private Material _modifiedMaterial;
  35. private UIParticle _parent;
  36. private ParticleSystem _particleSystem;
  37. private float _prevCanvasScale;
  38. private Vector3 _prevPsPos;
  39. private Vector3 _prevScale;
  40. private Vector2Int _prevScreenSize;
  41. private bool _preWarm;
  42. private ParticleSystemRenderer _renderer;
  43. private ParticleSystem _mainEmitter;
  44. public override Texture mainTexture => _isTrail ? null : _particleSystem.GetTextureForSprite();
  45. public override bool raycastTarget => false;
  46. private Rect rootCanvasRect
  47. {
  48. get
  49. {
  50. s_Corners[0] = transform.TransformPoint(_lastBounds.min.x, _lastBounds.min.y, 0);
  51. s_Corners[1] = transform.TransformPoint(_lastBounds.min.x, _lastBounds.max.y, 0);
  52. s_Corners[2] = transform.TransformPoint(_lastBounds.max.x, _lastBounds.max.y, 0);
  53. s_Corners[3] = transform.TransformPoint(_lastBounds.max.x, _lastBounds.min.y, 0);
  54. if (canvas)
  55. {
  56. var worldToLocalMatrix = canvas.rootCanvas.transform.worldToLocalMatrix;
  57. for (var i = 0; i < 4; ++i)
  58. {
  59. s_Corners[i] = worldToLocalMatrix.MultiplyPoint(s_Corners[i]);
  60. }
  61. }
  62. var corner1 = (Vector2)s_Corners[0];
  63. var corner2 = (Vector2)s_Corners[0];
  64. for (var i = 1; i < 4; ++i)
  65. {
  66. if (s_Corners[i].x < corner1.x)
  67. {
  68. corner1.x = s_Corners[i].x;
  69. }
  70. else if (s_Corners[i].x > corner2.x)
  71. {
  72. corner2.x = s_Corners[i].x;
  73. }
  74. if (s_Corners[i].y < corner1.y)
  75. {
  76. corner1.y = s_Corners[i].y;
  77. }
  78. else if (s_Corners[i].y > corner2.y)
  79. {
  80. corner2.y = s_Corners[i].y;
  81. }
  82. }
  83. return new Rect(corner1, corner2 - corner1);
  84. }
  85. }
  86. public override Material materialForRendering
  87. {
  88. get
  89. {
  90. if (!_materialForRendering)
  91. {
  92. _materialForRendering = base.materialForRendering;
  93. }
  94. return _materialForRendering;
  95. }
  96. }
  97. public void Reset(int index = -1)
  98. {
  99. if (_renderer)
  100. {
  101. _renderer.enabled = true;
  102. }
  103. _parent = null;
  104. _particleSystem = null;
  105. _renderer = null;
  106. _mainEmitter = null;
  107. if (0 <= index)
  108. {
  109. _index = index;
  110. }
  111. //_emitter = null;
  112. if (this && isActiveAndEnabled)
  113. {
  114. material = null;
  115. canvasRenderer.Clear();
  116. _lastBounds = new Bounds();
  117. enabled = false;
  118. }
  119. else
  120. {
  121. MaterialRepository.Release(ref _modifiedMaterial);
  122. _materialForRendering = null;
  123. }
  124. }
  125. protected override void OnEnable()
  126. {
  127. base.OnEnable();
  128. hideFlags = UIParticleProjectSettings.globalHideFlags;
  129. if (!s_CombineInstances[0].mesh)
  130. {
  131. s_CombineInstances[0].mesh = new Mesh
  132. {
  133. name = "[UIParticleRenderer] Combine Instance Mesh",
  134. hideFlags = HideFlags.HideAndDontSave
  135. };
  136. }
  137. }
  138. protected override void OnDisable()
  139. {
  140. base.OnDisable();
  141. MaterialRepository.Release(ref _modifiedMaterial);
  142. _materialForRendering = null;
  143. _isPrevStored = false;
  144. }
  145. public static UIParticleRenderer AddRenderer(UIParticle parent, int index)
  146. {
  147. // Create renderer object.
  148. var go = new GameObject("[generated] UIParticleRenderer", typeof(UIParticleRenderer))
  149. {
  150. hideFlags = UIParticleProjectSettings.globalHideFlags,
  151. layer = parent.gameObject.layer
  152. };
  153. // Set parent.
  154. var transform = go.transform;
  155. transform.SetParent(parent.transform, false);
  156. transform.localPosition = Vector3.zero;
  157. transform.localRotation = Quaternion.identity;
  158. transform.localScale = Vector3.one;
  159. // Add renderer component.
  160. var renderer = go.GetComponent<UIParticleRenderer>();
  161. renderer._parent = parent;
  162. renderer._index = index;
  163. return renderer;
  164. }
  165. /// <summary>
  166. /// Perform material modification in this function.
  167. /// </summary>
  168. public override Material GetModifiedMaterial(Material baseMaterial)
  169. {
  170. if (!IsActive() || !_parent)
  171. {
  172. MaterialRepository.Release(ref _modifiedMaterial);
  173. return baseMaterial;
  174. }
  175. var modifiedMaterial = base.GetModifiedMaterial(baseMaterial);
  176. //
  177. var texture = mainTexture;
  178. if (texture == null && _parent.m_AnimatableProperties.Length == 0)
  179. {
  180. MaterialRepository.Release(ref _modifiedMaterial);
  181. return modifiedMaterial;
  182. }
  183. var hash = new Hash128(
  184. modifiedMaterial ? (uint)modifiedMaterial.GetInstanceID() : 0,
  185. texture ? (uint)texture.GetInstanceID() : 0,
  186. 0 < _parent.m_AnimatableProperties.Length ? (uint)GetInstanceID() : 0,
  187. #if UNITY_EDITOR
  188. (uint)EditorJsonUtility.ToJson(modifiedMaterial).GetHashCode()
  189. #else
  190. 0
  191. #endif
  192. );
  193. if (!MaterialRepository.Valid(hash, _modifiedMaterial))
  194. {
  195. MaterialRepository.Get(hash, ref _modifiedMaterial, x => new Material(x.mat)
  196. {
  197. hideFlags = HideFlags.HideAndDontSave,
  198. mainTexture = x.texture ? x.texture : x.mat.mainTexture
  199. }, (mat: modifiedMaterial, texture));
  200. }
  201. return _modifiedMaterial;
  202. }
  203. public void Set(UIParticle parent, ParticleSystem ps, bool isTrail, ParticleSystem mainEmitter)
  204. {
  205. _parent = parent;
  206. maskable = parent.maskable;
  207. gameObject.layer = parent.gameObject.layer;
  208. _particleSystem = ps;
  209. _preWarm = _particleSystem.main.prewarm;
  210. #if UNITY_EDITOR
  211. if (Application.isPlaying)
  212. #endif
  213. {
  214. if (_particleSystem.isPlaying || _preWarm)
  215. {
  216. _particleSystem.Clear();
  217. _particleSystem.Pause();
  218. }
  219. }
  220. ps.TryGetComponent(out _renderer);
  221. _renderer.enabled = false;
  222. _isTrail = isTrail;
  223. _renderer.GetSharedMaterials(s_Materials);
  224. material = s_Materials[isTrail ? 1 : 0];
  225. s_Materials.Clear();
  226. // Support sprite.
  227. var tsa = ps.textureSheetAnimation;
  228. if (tsa.mode == ParticleSystemAnimationMode.Sprites && tsa.uvChannelMask == 0)
  229. {
  230. tsa.uvChannelMask = UVChannelFlags.UV0;
  231. }
  232. _prevScale = GetWorldScale();
  233. _prevPsPos = _particleSystem.transform.position;
  234. _prevScreenSize = new Vector2Int(Screen.width, Screen.height);
  235. _prevCanvasScale = canvas ? canvas.scaleFactor : 1f;
  236. _delay = true;
  237. _mainEmitter = mainEmitter;
  238. canvasRenderer.SetTexture(null);
  239. enabled = true;
  240. }
  241. public void UpdateMesh(Camera bakeCamera)
  242. {
  243. // No particle to render: Clear mesh.
  244. if (
  245. !isActiveAndEnabled || !_particleSystem || !_parent
  246. || !canvasRenderer || !canvas || !bakeCamera
  247. || _parent.meshSharing == UIParticle.MeshSharing.Replica
  248. || !transform.lossyScale.GetScaled(_parent.scale3DForCalc).IsVisible() // Scale is not visible.
  249. || (!_particleSystem.IsAlive() && !_particleSystem.isPlaying) // No particle.
  250. || (_isTrail && !_particleSystem.trails.enabled) // Trail, but it is not enabled.
  251. #if UNITY_2018_3_OR_NEWER
  252. || canvasRenderer.GetInheritedAlpha() <
  253. 0.01f // #102: Do not bake particle system to mesh when the alpha is zero.
  254. #endif
  255. )
  256. {
  257. Profiler.BeginSample("[UIParticleRenderer] Clear Mesh");
  258. workerMesh.Clear();
  259. canvasRenderer.SetMesh(workerMesh);
  260. _lastBounds = new Bounds();
  261. Profiler.EndSample();
  262. return;
  263. }
  264. var main = _particleSystem.main;
  265. var scale = GetWorldScale();
  266. var psPos = _particleSystem.transform.position;
  267. // Simulate particles.
  268. Profiler.BeginSample("[UIParticle] Bake Mesh > Simulate Particles");
  269. if (!_isTrail && _parent.canSimulate && !_mainEmitter)
  270. {
  271. #if UNITY_EDITOR
  272. if (!Application.isPlaying)
  273. {
  274. SimulateForEditor(psPos - _prevPsPos, scale);
  275. }
  276. else
  277. #endif
  278. {
  279. ResolveResolutionChange(psPos, scale);
  280. Simulate(scale, _parent.isPaused || _delay);
  281. if (_delay && !_parent.isPaused)
  282. {
  283. Simulate(scale, _parent.isPaused);
  284. }
  285. // When the ParticleSystem simulation is complete, stop it.
  286. if (!main.loop
  287. && main.duration <= _particleSystem.time
  288. && (_particleSystem.IsAlive() || _particleSystem.particleCount == 0)
  289. )
  290. {
  291. _particleSystem.Stop(false);
  292. }
  293. }
  294. _prevScale = scale;
  295. _prevPsPos = psPos;
  296. _delay = false;
  297. }
  298. Profiler.EndSample();
  299. // Bake mesh.
  300. Profiler.BeginSample("[UIParticleRenderer] Bake Mesh");
  301. s_CombineInstances[0].mesh.Clear(false);
  302. // Assertion failed on expression: 'ps->array_size()' #278
  303. var extends = s_CombineInstances[0].mesh.bounds.extents.x;
  304. if (!float.IsNaN(extends) && !float.IsInfinity(extends) && 0 < extends)
  305. {
  306. s_CombineInstances[0].mesh.RecalculateBounds();
  307. }
  308. if (_isTrail && _parent.canSimulate && 0 < _particleSystem.particleCount)
  309. {
  310. #if PS_BAKE_API_V2
  311. _renderer.BakeTrailsMesh(s_CombineInstances[0].mesh, bakeCamera,
  312. ParticleSystemBakeMeshOptions.BakeRotationAndScale);
  313. #else
  314. _renderer.BakeTrailsMesh(s_CombineInstances[0].mesh, bakeCamera, true);
  315. #endif
  316. }
  317. else if (!_isTrail && _renderer.CanBakeMesh())
  318. {
  319. _particleSystem.ValidateShape();
  320. #if PS_BAKE_API_V2
  321. _renderer.BakeMesh(s_CombineInstances[0].mesh, bakeCamera,
  322. ParticleSystemBakeMeshOptions.BakeRotationAndScale);
  323. #else
  324. _renderer.BakeMesh(s_CombineInstances[0].mesh, bakeCamera, true);
  325. #endif
  326. }
  327. // Too many vertices to render.
  328. if (65535 <= s_CombineInstances[0].mesh.vertexCount)
  329. {
  330. Debug.LogErrorFormat(this,
  331. "Too many vertices to render. index={0}, isTrail={1}, vertexCount={2}(>=65535)",
  332. _index,
  333. _isTrail,
  334. s_CombineInstances[0].mesh.vertexCount
  335. );
  336. s_CombineInstances[0].mesh.Clear(false);
  337. }
  338. Profiler.EndSample();
  339. // Combine mesh to transform. ([ParticleSystem local ->] world -> renderer local)
  340. Profiler.BeginSample("[UIParticleRenderer] Combine Mesh");
  341. if (_parent.canSimulate)
  342. {
  343. if (_parent.positionMode == UIParticle.PositionMode.Absolute)
  344. {
  345. s_CombineInstances[0].transform =
  346. canvasRenderer.transform.worldToLocalMatrix
  347. * GetWorldMatrix(psPos, scale);
  348. }
  349. else
  350. {
  351. var diff = _particleSystem.transform.position - _parent.transform.position;
  352. s_CombineInstances[0].transform =
  353. canvasRenderer.transform.worldToLocalMatrix
  354. * Matrix4x4.Translate(diff.GetScaled(scale - Vector3.one))
  355. * GetWorldMatrix(psPos, scale);
  356. }
  357. workerMesh.CombineMeshes(s_CombineInstances, true, true);
  358. workerMesh.RecalculateBounds();
  359. var bounds = workerMesh.bounds;
  360. var center = bounds.center;
  361. center.z = 0;
  362. bounds.center = center;
  363. var extents = bounds.extents;
  364. extents.z = 0;
  365. bounds.extents = extents;
  366. workerMesh.bounds = bounds;
  367. _lastBounds = bounds;
  368. // Convert linear color to gamma color.
  369. if (UIParticleProjectSettings.enableLinearToGamma && canvas.ShouldGammaToLinearInMesh())
  370. {
  371. workerMesh.LinearToGamma();
  372. }
  373. var components = InternalListPool<Component>.Rent();
  374. GetComponents(typeof(IMeshModifier), components);
  375. for (var i = 0; i < components.Count; i++)
  376. {
  377. #pragma warning disable CS0618 // Type or member is obsolete
  378. ((IMeshModifier)components[i]).ModifyMesh(workerMesh);
  379. #pragma warning restore CS0618 // Type or member is obsolete
  380. }
  381. InternalListPool<Component>.Return(ref components);
  382. }
  383. Profiler.EndSample();
  384. // Update animatable material properties.
  385. Profiler.BeginSample("[UIParticleRenderer] Update Animatable Material Properties");
  386. UpdateMaterialProperties();
  387. Profiler.EndSample();
  388. // Get grouped renderers.
  389. Profiler.BeginSample("[UIParticleRenderer] Set Mesh");
  390. var renderers = InternalListPool<UIParticleRenderer>.Rent();
  391. if (_parent.useMeshSharing)
  392. {
  393. UIParticleUpdater.GetGroupedRenderers(_parent.groupId, _index, renderers);
  394. }
  395. for (var i = 0; i < renderers.Count; i++)
  396. {
  397. var r = renderers[i];
  398. if (r == this) continue;
  399. r.canvasRenderer.SetMesh(workerMesh);
  400. r._lastBounds = _lastBounds;
  401. r.canvasRenderer.materialCount = 1;
  402. r.canvasRenderer.SetMaterial(materialForRendering, 0);
  403. }
  404. InternalListPool<UIParticleRenderer>.Return(ref renderers);
  405. if (_parent.canRender)
  406. {
  407. canvasRenderer.SetMesh(workerMesh);
  408. }
  409. else
  410. {
  411. workerMesh.Clear();
  412. }
  413. Profiler.EndSample();
  414. }
  415. public override void SetMaterialDirty()
  416. {
  417. _materialForRendering = null;
  418. base.SetMaterialDirty();
  419. }
  420. /// <summary>
  421. /// Call to update the geometry of the Graphic onto the CanvasRenderer.
  422. /// </summary>
  423. protected override void UpdateGeometry()
  424. {
  425. }
  426. public override void Cull(Rect clipRect, bool validRect)
  427. {
  428. var cull = _lastBounds.extents == Vector3.zero
  429. || !validRect
  430. || !clipRect.Overlaps(rootCanvasRect, true);
  431. if (canvasRenderer.cull == cull) return;
  432. canvasRenderer.cull = cull;
  433. UISystemProfilerApi.AddMarker("MaskableGraphic.cullingChanged", this);
  434. onCullStateChanged.Invoke(cull);
  435. OnCullingChanged();
  436. }
  437. private Vector3 GetWorldScale()
  438. {
  439. Profiler.BeginSample("[UIParticleRenderer] GetWorldScale");
  440. var scale = _parent.scale3DForCalc.GetScaled(_parent.parentScale);
  441. if (_parent.autoScalingMode == UIParticle.AutoScalingMode.UIParticle
  442. && _particleSystem.main.scalingMode == ParticleSystemScalingMode.Local
  443. && _parent.canvas)
  444. {
  445. scale = scale.GetScaled(_parent.canvas.rootCanvas.transform.localScale);
  446. }
  447. Profiler.EndSample();
  448. return scale;
  449. }
  450. private Matrix4x4 GetWorldMatrix(Vector3 psPos, Vector3 scale)
  451. {
  452. var space = _particleSystem.GetActualSimulationSpace();
  453. if (_isTrail && _particleSystem.trails.worldSpace)
  454. {
  455. space = ParticleSystemSimulationSpace.World;
  456. }
  457. #if UNITY_EDITOR
  458. if (!Application.isPlaying)
  459. {
  460. switch (space)
  461. {
  462. case ParticleSystemSimulationSpace.World:
  463. return Matrix4x4.Translate(psPos)
  464. * Matrix4x4.Scale(scale)
  465. * Matrix4x4.Translate(-psPos);
  466. }
  467. }
  468. #endif
  469. switch (space)
  470. {
  471. case ParticleSystemSimulationSpace.Local:
  472. return Matrix4x4.Translate(psPos)
  473. * Matrix4x4.Scale(scale);
  474. case ParticleSystemSimulationSpace.World:
  475. if (_isTrail)
  476. {
  477. return Matrix4x4.Translate(psPos)
  478. * Matrix4x4.Scale(scale)
  479. * Matrix4x4.Translate(-psPos);
  480. }
  481. if (_mainEmitter)
  482. {
  483. if (_mainEmitter.IsLocalSpace())
  484. {
  485. return Matrix4x4.Translate(psPos)
  486. * Matrix4x4.Scale(scale)
  487. * Matrix4x4.Translate(-psPos);
  488. }
  489. else
  490. {
  491. psPos = _particleSystem.transform.position - _mainEmitter.transform.position;
  492. return Matrix4x4.Translate(psPos)
  493. * Matrix4x4.Scale(scale)
  494. * Matrix4x4.Translate(-psPos);
  495. }
  496. }
  497. return Matrix4x4.Scale(scale);
  498. case ParticleSystemSimulationSpace.Custom:
  499. return Matrix4x4.Translate(_particleSystem.main.customSimulationSpace.position.GetScaled(scale))
  500. * Matrix4x4.Scale(scale);
  501. default:
  502. throw new NotSupportedException();
  503. }
  504. }
  505. /// <summary>
  506. /// For world simulation, interpolate particle positions when the screen size is changed.
  507. /// </summary>
  508. /// <param name="psPos"></param>
  509. /// <param name="scale"></param>
  510. private void ResolveResolutionChange(Vector3 psPos, Vector3 scale)
  511. {
  512. var screenSize = new Vector2Int(Screen.width, Screen.height);
  513. var isWorldSpace = _particleSystem.IsWorldSpace();
  514. var canvasScale = _parent.canvas ? _parent.canvas.scaleFactor : 1f;
  515. var resolutionChanged = _prevScreenSize != screenSize
  516. || !Mathf.Approximately(_prevCanvasScale, canvasScale);
  517. if (resolutionChanged && isWorldSpace && _isPrevStored)
  518. {
  519. // Update particle array size and get particles.
  520. var size = _particleSystem.particleCount;
  521. var particles = ParticleSystemExtensions.GetParticleArray(size);
  522. _particleSystem.GetParticles(particles, size);
  523. // Resolution resolver:
  524. // (psPos / scale) / (prevPsPos / prevScale) -> psPos * scale.inv * prevPsPos.inv * prevScale
  525. var modifier = psPos.GetScaled(
  526. scale.Inverse(),
  527. _prevPsPos.Inverse(),
  528. _prevScale);
  529. for (var i = 0; i < size; i++)
  530. {
  531. var particle = particles[i];
  532. particle.position = particle.position.GetScaled(modifier);
  533. particles[i] = particle;
  534. }
  535. _particleSystem.SetParticles(particles, size);
  536. // Delay: Do not progress in the frame where the resolution has been changed.
  537. _delay = true;
  538. _prevScale = scale;
  539. _prevPsPos = psPos;
  540. _isPrevStored = true;
  541. }
  542. _prevCanvasScale = canvas ? canvas.scaleFactor : 1f;
  543. _prevScreenSize = screenSize;
  544. }
  545. private void Simulate(Vector3 scale, bool paused)
  546. {
  547. var main = _particleSystem.main;
  548. var deltaTime = paused
  549. ? 0
  550. : main.useUnscaledTime
  551. ? Time.unscaledDeltaTime
  552. : Time.deltaTime;
  553. deltaTime *= _parent.timeScaleMultiplier;
  554. // Pre-warm:
  555. if (0 < deltaTime && _preWarm)
  556. {
  557. deltaTime += main.duration;
  558. _preWarm = false;
  559. }
  560. // get world position.
  561. var isLocalSpace = _particleSystem.IsLocalSpace();
  562. var psTransform = _particleSystem.transform;
  563. var originLocalPosition = psTransform.localPosition;
  564. var originLocalRotation = psTransform.localRotation;
  565. var originWorldPosition = psTransform.position;
  566. var originWorldRotation = psTransform.rotation;
  567. var emission = _particleSystem.emission;
  568. var rateOverDistance = emission.enabled
  569. && 0 < emission.rateOverDistance.constant
  570. && 0 < emission.rateOverDistanceMultiplier;
  571. if (rateOverDistance && !paused && _isPrevStored)
  572. {
  573. // (For rate-over-distance emission,) Move to previous scaled position, simulate (delta = 0).
  574. var prevScaledPos = isLocalSpace
  575. ? _prevPsPos
  576. : _prevPsPos.GetScaled(_prevScale.Inverse());
  577. psTransform.SetPositionAndRotation(prevScaledPos, originWorldRotation);
  578. _particleSystem.Simulate(0, false, false, false);
  579. }
  580. // Move to scaled position, simulate, revert to origin position.
  581. var scaledPos = isLocalSpace
  582. ? originWorldPosition
  583. : originWorldPosition.GetScaled(scale.Inverse());
  584. psTransform.SetPositionAndRotation(scaledPos, originWorldRotation);
  585. _particleSystem.Simulate(deltaTime, false, false, false);
  586. psTransform.localPosition = originLocalPosition;
  587. psTransform.localRotation = originLocalRotation;
  588. }
  589. #if UNITY_EDITOR
  590. private void SimulateForEditor(Vector3 diffPos, Vector3 scale)
  591. {
  592. // Extra world simulation.
  593. var isWorldSpace = _particleSystem.IsWorldSpace();
  594. if (isWorldSpace && 0 < Vector3.SqrMagnitude(diffPos))
  595. {
  596. Profiler.BeginSample("[UIParticle] Bake Mesh > Extra world simulation");
  597. diffPos.x *= 1f - 1f / Mathf.Max(0.001f, scale.x);
  598. diffPos.y *= 1f - 1f / Mathf.Max(0.001f, scale.y);
  599. diffPos.z *= 1f - 1f / Mathf.Max(0.001f, scale.z);
  600. var size = _particleSystem.particleCount;
  601. var particles = ParticleSystemExtensions.GetParticleArray(size);
  602. _particleSystem.GetParticles(particles, size);
  603. for (var i = 0; i < size; i++)
  604. {
  605. var p = particles[i];
  606. p.position += diffPos;
  607. particles[i] = p;
  608. }
  609. _particleSystem.SetParticles(particles, size);
  610. Profiler.EndSample();
  611. }
  612. }
  613. #endif
  614. private void UpdateMaterialProperties()
  615. {
  616. if (_parent.m_AnimatableProperties.Length == 0) return;
  617. if (s_Mpb == null)
  618. {
  619. s_Mpb = new MaterialPropertyBlock();
  620. }
  621. _renderer.GetPropertyBlock(s_Mpb);
  622. if (s_Mpb.isEmpty) return;
  623. // #41: Copy the value from MaterialPropertyBlock to CanvasRenderer
  624. if (!materialForRendering) return;
  625. for (var i = 0; i < _parent.m_AnimatableProperties.Length; i++)
  626. {
  627. var ap = _parent.m_AnimatableProperties[i];
  628. ap.UpdateMaterialProperties(materialForRendering, s_Mpb);
  629. }
  630. s_Mpb.Clear();
  631. }
  632. }
  633. }