Без опису
Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.

SpriteShapeController.cs 31KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884
  1. using System.Collections.Generic;
  2. using Unity.Jobs;
  3. using Unity.Collections;
  4. using Unity.Mathematics;
  5. using Unity.Collections.LowLevel.Unsafe;
  6. using Unity.Profiling;
  7. #if UNITY_EDITOR
  8. using UnityEditor.U2D;
  9. #endif
  10. namespace UnityEngine.U2D
  11. {
  12. /// <summary>
  13. /// SpriteShapeController component contains Spline and SpriteShape Profile information that is used when generating SpriteShape geometry.
  14. /// </summary>
  15. [ExecuteInEditMode]
  16. [RequireComponent(typeof(SpriteShapeRenderer))]
  17. [DisallowMultipleComponent]
  18. [HelpURLAttribute("https://docs.unity3d.com/Packages/com.unity.2d.spriteshape@latest/index.html?subfolder=/manual/SSController.html")]
  19. public class SpriteShapeController : MonoBehaviour
  20. {
  21. // Internal Dataset.
  22. const float s_DistanceTolerance = 0.001f;
  23. // Cached Objects.
  24. SpriteShape m_ActiveSpriteShape;
  25. EdgeCollider2D m_EdgeCollider2D;
  26. PolygonCollider2D m_PolygonCollider2D;
  27. SpriteShapeRenderer m_SpriteShapeRenderer;
  28. SpriteShapeGeometryCache m_SpriteShapeGeometryCache;
  29. Sprite[] m_SpriteArray = new Sprite[0];
  30. Sprite[] m_EdgeSpriteArray = new Sprite[0];
  31. Sprite[] m_CornerSpriteArray = new Sprite[0];
  32. AngleRangeInfo[] m_AngleRangeInfoArray = new AngleRangeInfo[0];
  33. // Required for Generation.
  34. NativeArray<float2> m_ColliderData;
  35. NativeArray<Vector4> m_TangentData;
  36. // Renderer Stuff.
  37. bool m_DynamicOcclusionLocal;
  38. bool m_DynamicOcclusionOverriden;
  39. // Hash Check.
  40. int m_ActiveSplineHash = 0;
  41. int m_ActiveSpriteShapeHash = 0;
  42. int m_MaxArrayCount = 0;
  43. JobHandle m_JobHandle;
  44. SpriteShapeParameters m_ActiveShapeParameters;
  45. // Serialized Data.
  46. [SerializeField]
  47. Spline m_Spline = new Spline();
  48. [SerializeField]
  49. SpriteShape m_SpriteShape;
  50. [SerializeField]
  51. float m_FillPixelPerUnit = 100.0f;
  52. [SerializeField]
  53. float m_StretchTiling = 1.0f;
  54. [SerializeField]
  55. int m_SplineDetail;
  56. [SerializeField]
  57. bool m_AdaptiveUV;
  58. [SerializeField]
  59. bool m_StretchUV;
  60. [SerializeField]
  61. bool m_WorldSpaceUV;
  62. [SerializeField]
  63. float m_CornerAngleThreshold = 30.0f;
  64. [SerializeField]
  65. int m_ColliderDetail;
  66. [SerializeField, Range(-0.5f, 0.5f)]
  67. float m_ColliderOffset;
  68. [SerializeField]
  69. bool m_UpdateCollider = true;
  70. [SerializeField]
  71. bool m_OptimizeCollider = true;
  72. [SerializeField]
  73. bool m_OptimizeGeometry = true;
  74. [SerializeField]
  75. bool m_EnableTangents = false;
  76. [SerializeField]
  77. [HideInInspector]
  78. bool m_GeometryCached = false;
  79. [SerializeField]
  80. bool m_UTess2D = false;
  81. static readonly ProfilerMarker generateGeometry = new ProfilerMarker("SpriteShape.GenerateGeometry");
  82. static readonly ProfilerMarker generateCollider = new ProfilerMarker("SpriteShape.GenerateCollider");
  83. #region GetSet
  84. internal int maxArrayCount
  85. {
  86. get { return m_MaxArrayCount; }
  87. set { m_MaxArrayCount = value; }
  88. }
  89. internal bool geometryCached
  90. {
  91. get { return m_GeometryCached; }
  92. set { m_GeometryCached = value; }
  93. }
  94. internal int splineHashCode
  95. {
  96. get { return m_ActiveSplineHash; }
  97. }
  98. internal Sprite[] spriteArray
  99. {
  100. get { return m_SpriteArray; }
  101. }
  102. internal SpriteShapeParameters spriteShapeParameters
  103. {
  104. get { return m_ActiveShapeParameters; }
  105. }
  106. internal SpriteShapeGeometryCache spriteShapeGeometryCache
  107. {
  108. get
  109. {
  110. if (!m_SpriteShapeGeometryCache)
  111. {
  112. bool b = TryGetComponent(typeof(SpriteShapeGeometryCache), out Component comp);
  113. m_SpriteShapeGeometryCache = b ? (comp as SpriteShapeGeometryCache) : null;
  114. }
  115. return m_SpriteShapeGeometryCache;
  116. }
  117. }
  118. public int spriteShapeHashCode
  119. {
  120. get { return m_ActiveSpriteShapeHash; }
  121. }
  122. public bool worldSpaceUVs
  123. {
  124. get { return m_WorldSpaceUV; }
  125. set { m_WorldSpaceUV = value; }
  126. }
  127. public float fillPixelsPerUnit
  128. {
  129. get { return m_FillPixelPerUnit; }
  130. set { m_FillPixelPerUnit = value; }
  131. }
  132. public bool enableTangents
  133. {
  134. get { return m_EnableTangents; }
  135. set { m_EnableTangents = value; }
  136. }
  137. public float stretchTiling
  138. {
  139. get { return m_StretchTiling; }
  140. set { m_StretchTiling = value; }
  141. }
  142. public int splineDetail
  143. {
  144. get { return m_SplineDetail; }
  145. set { m_SplineDetail = Mathf.Max(0, value); }
  146. }
  147. public int colliderDetail
  148. {
  149. get { return m_ColliderDetail; }
  150. set { m_ColliderDetail = Mathf.Max(0, value); }
  151. }
  152. public float colliderOffset
  153. {
  154. get { return m_ColliderOffset; }
  155. set { m_ColliderOffset = value; }
  156. }
  157. public float cornerAngleThreshold
  158. {
  159. get { return m_CornerAngleThreshold; }
  160. set { m_CornerAngleThreshold = value; }
  161. }
  162. public bool autoUpdateCollider
  163. {
  164. get { return m_UpdateCollider; }
  165. set { m_UpdateCollider = value; }
  166. }
  167. public bool optimizeCollider
  168. {
  169. get { return m_OptimizeCollider; }
  170. }
  171. internal bool optimizeColliderInternal
  172. {
  173. set { m_OptimizeCollider = value; }
  174. }
  175. public bool optimizeGeometry
  176. {
  177. get { return m_OptimizeGeometry; }
  178. }
  179. public bool hasCollider
  180. {
  181. get { return (edgeCollider != null) || (polygonCollider != null); }
  182. }
  183. public Spline spline
  184. {
  185. get { return m_Spline; }
  186. }
  187. public SpriteShape spriteShape
  188. {
  189. get { return m_SpriteShape; }
  190. set { m_SpriteShape = value; }
  191. }
  192. public EdgeCollider2D edgeCollider
  193. {
  194. get
  195. {
  196. if (!m_EdgeCollider2D)
  197. {
  198. bool b = TryGetComponent(typeof(EdgeCollider2D), out Component comp);
  199. m_EdgeCollider2D = b ? (comp as EdgeCollider2D) : null;
  200. }
  201. return m_EdgeCollider2D;
  202. }
  203. }
  204. public PolygonCollider2D polygonCollider
  205. {
  206. get
  207. {
  208. if (!m_PolygonCollider2D)
  209. {
  210. bool b = TryGetComponent(typeof(PolygonCollider2D), out Component comp);
  211. m_PolygonCollider2D = b ? (comp as PolygonCollider2D) : null;
  212. }
  213. return m_PolygonCollider2D;
  214. }
  215. }
  216. public SpriteShapeRenderer spriteShapeRenderer
  217. {
  218. get
  219. {
  220. if (!m_SpriteShapeRenderer)
  221. m_SpriteShapeRenderer = GetComponent<SpriteShapeRenderer>();
  222. return m_SpriteShapeRenderer;
  223. }
  224. }
  225. #endregion
  226. #region EventHandles.
  227. void DisposeInternal()
  228. {
  229. if (m_ColliderData.IsCreated)
  230. m_ColliderData.Dispose();
  231. if (m_TangentData.IsCreated)
  232. m_TangentData.Dispose();
  233. }
  234. void OnApplicationQuit()
  235. {
  236. DisposeInternal();
  237. }
  238. void OnEnable()
  239. {
  240. m_DynamicOcclusionOverriden = true;
  241. m_DynamicOcclusionLocal = spriteShapeRenderer.allowOcclusionWhenDynamic;
  242. spriteShapeRenderer.allowOcclusionWhenDynamic = false;
  243. InitBounds();
  244. UpdateSpriteData();
  245. }
  246. void OnDisable()
  247. {
  248. DisposeInternal();
  249. }
  250. void OnDestroy()
  251. {
  252. }
  253. void Reset()
  254. {
  255. m_SplineDetail = (int)QualityDetail.High;
  256. m_AdaptiveUV = true;
  257. m_StretchUV = false;
  258. m_FillPixelPerUnit = 100f;
  259. m_ColliderDetail = (int)QualityDetail.High;
  260. m_StretchTiling = 1.0f;
  261. m_WorldSpaceUV = false;
  262. m_CornerAngleThreshold = 30.0f;
  263. m_ColliderOffset = 0;
  264. m_UpdateCollider = true;
  265. m_OptimizeCollider = true;
  266. m_OptimizeGeometry = true;
  267. m_EnableTangents = false;
  268. spline.Clear();
  269. spline.InsertPointAt(0, Vector2.left + Vector2.down);
  270. spline.InsertPointAt(1, Vector2.left + Vector2.up);
  271. spline.InsertPointAt(2, Vector2.right + Vector2.up);
  272. spline.InsertPointAt(3, Vector2.right + Vector2.down);
  273. }
  274. static void SmartDestroy(UnityEngine.Object o)
  275. {
  276. if (o == null)
  277. return;
  278. #if UNITY_EDITOR
  279. if (!Application.isPlaying)
  280. DestroyImmediate(o);
  281. else
  282. #endif
  283. Destroy(o);
  284. }
  285. #endregion
  286. #region HashAndDataCheck
  287. internal Bounds InitBounds()
  288. {
  289. var pointCount = spline.GetPointCount();
  290. if (pointCount > 1)
  291. {
  292. Bounds bounds = new Bounds(spline.GetPosition(0), Vector3.zero);
  293. for (int i = 1; i < pointCount; ++i)
  294. bounds.Encapsulate(spline.GetPosition(i));
  295. bounds.Encapsulate(spriteShapeRenderer.localBounds);
  296. spriteShapeRenderer.SetLocalAABB(bounds);
  297. return bounds;
  298. }
  299. return new Bounds();
  300. }
  301. /// <summary>
  302. /// Refresh SpriteShape Hash so its force generated again on the next frame if its visible.
  303. /// </summary>
  304. public void RefreshSpriteShape()
  305. {
  306. m_ActiveSplineHash = 0;
  307. }
  308. // Ensure Neighbor points are not too close to each other.
  309. bool ValidateSpline()
  310. {
  311. int pointCount = spline.GetPointCount();
  312. if (pointCount < 2)
  313. return false;
  314. for (int i = 0; i < pointCount - 1; ++i)
  315. {
  316. var vec = spline.GetPosition(i) - spline.GetPosition(i + 1);
  317. if (vec.sqrMagnitude < s_DistanceTolerance)
  318. {
  319. Debug.LogWarningFormat(gameObject, "[SpriteShape] Control points {0} & {1} are too close. SpriteShape will not be generated for < {2} >.", i, i + 1, gameObject.name);
  320. return false;
  321. }
  322. }
  323. return true;
  324. }
  325. // Ensure SpriteShape is valid if not
  326. bool ValidateSpriteShapeTexture()
  327. {
  328. bool valid = false;
  329. // Check if SpriteShape Profile is valid.
  330. if (spriteShape != null)
  331. {
  332. // Open ended and no valid Sprites set. Check if it has a valid fill texture.
  333. if (!spline.isOpenEnded)
  334. {
  335. valid = (spriteShape.fillTexture != null);
  336. }
  337. }
  338. else
  339. {
  340. // Warn that no SpriteShape is set.
  341. Debug.LogWarningFormat(gameObject, "[SpriteShape] A valid SpriteShape profile has not been set for gameObject < {0} >.", gameObject.name);
  342. #if UNITY_EDITOR
  343. // We allow null SpriteShape for rapid prototyping in Editor.
  344. valid = true;
  345. #endif
  346. }
  347. return valid;
  348. }
  349. internal bool ValidateUTess2D()
  350. {
  351. bool uTess2D = m_UTess2D;
  352. // Check for all properties that can create overlaps/intersections.
  353. if (m_UTess2D && null != spriteShape)
  354. {
  355. uTess2D = (spriteShape.fillOffset == 0);
  356. }
  357. return uTess2D;
  358. }
  359. bool HasSpriteShapeChanged()
  360. {
  361. bool changed = (m_ActiveSpriteShape != spriteShape);
  362. if (changed)
  363. m_ActiveSpriteShape = spriteShape;
  364. return changed;
  365. }
  366. bool HasSpriteShapeDataChanged()
  367. {
  368. bool updateSprites = HasSpriteShapeChanged();
  369. if (spriteShape)
  370. {
  371. var hashCode = SpriteShape.GetSpriteShapeHashCode(spriteShape);
  372. if (spriteShapeHashCode != hashCode)
  373. {
  374. m_ActiveSpriteShapeHash = hashCode;
  375. updateSprites = true;
  376. }
  377. }
  378. return updateSprites;
  379. }
  380. bool HasSplineDataChanged()
  381. {
  382. unchecked
  383. {
  384. // Spline.
  385. int hashCode = (int)2166136261 ^ spline.GetHashCode();
  386. // Local Stuff.
  387. hashCode = hashCode * 16777619 ^ (m_UTess2D ? 1 : 0);
  388. hashCode = hashCode * 16777619 ^ (m_WorldSpaceUV ? 1 : 0);
  389. hashCode = hashCode * 16777619 ^ (m_EnableTangents ? 1 : 0);
  390. hashCode = hashCode * 16777619 ^ (m_GeometryCached ? 1 : 0);
  391. hashCode = hashCode * 16777619 ^ (m_OptimizeGeometry ? 1 : 0);
  392. hashCode = hashCode * 16777619 ^ (m_StretchTiling.GetHashCode());
  393. hashCode = hashCode * 16777619 ^ (m_ColliderOffset.GetHashCode());
  394. hashCode = hashCode * 16777619 ^ (m_ColliderDetail.GetHashCode());
  395. if (splineHashCode != hashCode)
  396. {
  397. m_ActiveSplineHash = hashCode;
  398. return true;
  399. }
  400. }
  401. return false;
  402. }
  403. void LateUpdate()
  404. {
  405. BakeCollider();
  406. }
  407. void OnWillRenderObject()
  408. {
  409. BakeMesh();
  410. }
  411. /// <summary>
  412. /// Generate geometry on a Job.
  413. /// </summary>
  414. /// <returns>JobHandle for the SpriteShape geometry generation job.</returns>
  415. public JobHandle BakeMesh()
  416. {
  417. JobHandle jobHandle = default;
  418. #if !UNITY_EDITOR
  419. if (spriteShapeGeometryCache)
  420. {
  421. // If SpriteShapeGeometry has already been uploaded, don't bother checking further.
  422. if (0 != m_ActiveSplineHash && 0 != spriteShapeGeometryCache.maxArrayCount)
  423. return jobHandle;
  424. }
  425. #endif
  426. bool valid = ValidateSpline();
  427. if (valid)
  428. {
  429. bool splineChanged = HasSplineDataChanged();
  430. bool spriteShapeChanged = HasSpriteShapeDataChanged();
  431. bool spriteShapeParametersChanged = UpdateSpriteShapeParameters();
  432. if (splineChanged || spriteShapeChanged || spriteShapeParametersChanged)
  433. {
  434. if (spriteShapeChanged)
  435. {
  436. UpdateSpriteData();
  437. }
  438. jobHandle = ScheduleBake();
  439. #if UNITY_EDITOR
  440. UpdateGeometryCache();
  441. #endif
  442. }
  443. }
  444. return jobHandle;
  445. }
  446. #endregion
  447. #region UpdateData
  448. /// <summary>
  449. /// Update Cache.
  450. /// </summary>
  451. internal void UpdateGeometryCache()
  452. {
  453. if (spriteShapeGeometryCache && geometryCached)
  454. {
  455. m_JobHandle.Complete();
  456. spriteShapeGeometryCache.UpdateGeometryCache();
  457. }
  458. }
  459. /// <summary>
  460. /// Force update SpriteShape parameters.
  461. /// </summary>
  462. /// <returns>Returns true if there are changes</returns>
  463. public bool UpdateSpriteShapeParameters()
  464. {
  465. bool carpet = !spline.isOpenEnded;
  466. bool smartSprite = true;
  467. bool adaptiveUV = m_AdaptiveUV;
  468. bool stretchUV = m_StretchUV;
  469. bool spriteBorders = false;
  470. uint fillScale = 0;
  471. uint splineDetail = (uint)m_SplineDetail;
  472. float borderPivot = 0f;
  473. float angleThreshold = (m_CornerAngleThreshold >= 0 && m_CornerAngleThreshold < 90) ? m_CornerAngleThreshold : 89.9999f;
  474. Texture2D fillTexture = null;
  475. Matrix4x4 transformMatrix = Matrix4x4.identity;
  476. if (spriteShape)
  477. {
  478. if (worldSpaceUVs)
  479. transformMatrix = transform.localToWorldMatrix;
  480. fillTexture = spriteShape.fillTexture;
  481. fillScale = stretchUV ? (uint)stretchTiling : (uint)fillPixelsPerUnit;
  482. borderPivot = spriteShape.fillOffset;
  483. spriteBorders = spriteShape.useSpriteBorders;
  484. // If Corners are enabled, set smart-sprite to false.
  485. if (spriteShape.cornerSprites.Count > 0)
  486. smartSprite = false;
  487. }
  488. else
  489. {
  490. #if UNITY_EDITOR
  491. fillTexture = UnityEditor.EditorGUIUtility.whiteTexture;
  492. fillScale = 100;
  493. #endif
  494. }
  495. bool changed = m_ActiveShapeParameters.adaptiveUV != adaptiveUV ||
  496. m_ActiveShapeParameters.angleThreshold != angleThreshold ||
  497. m_ActiveShapeParameters.borderPivot != borderPivot ||
  498. m_ActiveShapeParameters.carpet != carpet ||
  499. m_ActiveShapeParameters.fillScale != fillScale ||
  500. m_ActiveShapeParameters.fillTexture != fillTexture ||
  501. m_ActiveShapeParameters.smartSprite != smartSprite ||
  502. m_ActiveShapeParameters.splineDetail != splineDetail ||
  503. m_ActiveShapeParameters.spriteBorders != spriteBorders ||
  504. m_ActiveShapeParameters.transform != transformMatrix ||
  505. m_ActiveShapeParameters.stretchUV != stretchUV;
  506. m_ActiveShapeParameters.adaptiveUV = adaptiveUV;
  507. m_ActiveShapeParameters.stretchUV = stretchUV;
  508. m_ActiveShapeParameters.angleThreshold = angleThreshold;
  509. m_ActiveShapeParameters.borderPivot = borderPivot;
  510. m_ActiveShapeParameters.carpet = carpet;
  511. m_ActiveShapeParameters.fillScale = fillScale;
  512. m_ActiveShapeParameters.fillTexture = fillTexture;
  513. m_ActiveShapeParameters.smartSprite = smartSprite;
  514. m_ActiveShapeParameters.splineDetail = splineDetail;
  515. m_ActiveShapeParameters.spriteBorders = spriteBorders;
  516. m_ActiveShapeParameters.transform = transformMatrix;
  517. return changed;
  518. }
  519. void UpdateSpriteData()
  520. {
  521. if (spriteShape)
  522. {
  523. List<Sprite> edgeSpriteList = new List<Sprite>();
  524. List<Sprite> cornerSpriteList = new List<Sprite>();
  525. List<AngleRangeInfo> angleRangeInfoList = new List<AngleRangeInfo>();
  526. List<AngleRange> sortedAngleRanges = new List<AngleRange>(spriteShape.angleRanges);
  527. sortedAngleRanges.Sort((a, b) => a.order.CompareTo(b.order));
  528. for (int i = 0; i < sortedAngleRanges.Count; i++)
  529. {
  530. bool validSpritesFound = false;
  531. AngleRange angleRange = sortedAngleRanges[i];
  532. foreach (Sprite edgeSprite in angleRange.sprites)
  533. {
  534. if (edgeSprite != null)
  535. {
  536. validSpritesFound = true;
  537. break;
  538. }
  539. }
  540. if (validSpritesFound)
  541. {
  542. AngleRangeInfo angleRangeInfo = new AngleRangeInfo();
  543. angleRangeInfo.start = angleRange.start;
  544. angleRangeInfo.end = angleRange.end;
  545. angleRangeInfo.order = (uint)angleRange.order;
  546. List<int> spriteIndices = new List<int>();
  547. foreach (Sprite edgeSprite in angleRange.sprites)
  548. {
  549. edgeSpriteList.Add(edgeSprite);
  550. spriteIndices.Add(edgeSpriteList.Count - 1);
  551. }
  552. angleRangeInfo.sprites = spriteIndices.ToArray();
  553. angleRangeInfoList.Add(angleRangeInfo);
  554. }
  555. }
  556. bool validCornerSpritesFound = false;
  557. foreach (CornerSprite cornerSprite in spriteShape.cornerSprites)
  558. {
  559. if (cornerSprite.sprites[0] != null)
  560. {
  561. validCornerSpritesFound = true;
  562. break;
  563. }
  564. }
  565. if (validCornerSpritesFound)
  566. {
  567. for (int i = 0; i < spriteShape.cornerSprites.Count; i++)
  568. {
  569. CornerSprite cornerSprite = spriteShape.cornerSprites[i];
  570. cornerSpriteList.Add(cornerSprite.sprites[0]);
  571. }
  572. }
  573. m_EdgeSpriteArray = edgeSpriteList.ToArray();
  574. m_CornerSpriteArray = cornerSpriteList.ToArray();
  575. m_AngleRangeInfoArray = angleRangeInfoList.ToArray();
  576. List<Sprite> spriteList = new List<Sprite>();
  577. spriteList.AddRange(m_EdgeSpriteArray);
  578. spriteList.AddRange(m_CornerSpriteArray);
  579. m_SpriteArray = spriteList.ToArray();
  580. }
  581. else
  582. {
  583. m_SpriteArray = new Sprite[0];
  584. m_EdgeSpriteArray = new Sprite[0];
  585. m_CornerSpriteArray = new Sprite[0];
  586. m_AngleRangeInfoArray = new AngleRangeInfo[0];
  587. }
  588. }
  589. NativeArray<ShapeControlPoint> GetShapeControlPoints()
  590. {
  591. int pointCount = spline.GetPointCount();
  592. NativeArray<ShapeControlPoint> shapePoints = new NativeArray<ShapeControlPoint>(pointCount, Allocator.Temp);
  593. for (int i = 0; i < pointCount; ++i)
  594. {
  595. ShapeControlPoint shapeControlPoint;
  596. shapeControlPoint.position = spline.GetPosition(i);
  597. shapeControlPoint.leftTangent = spline.GetLeftTangent(i);
  598. shapeControlPoint.rightTangent = spline.GetRightTangent(i);
  599. shapeControlPoint.mode = (int)spline.GetTangentMode(i);
  600. shapePoints[i] = shapeControlPoint;
  601. }
  602. return shapePoints;
  603. }
  604. NativeArray<SplinePointMetaData> GetSplinePointMetaData()
  605. {
  606. int pointCount = spline.GetPointCount();
  607. NativeArray<SplinePointMetaData> shapeMetaData = new NativeArray<SplinePointMetaData>(pointCount, Allocator.Temp);
  608. for (int i = 0; i < pointCount; ++i)
  609. {
  610. SplinePointMetaData metaData;
  611. metaData.height = m_Spline.GetHeight(i);
  612. metaData.spriteIndex = (uint)m_Spline.GetSpriteIndex(i);
  613. metaData.cornerMode = (int)m_Spline.GetCornerMode(i);
  614. shapeMetaData[i] = metaData;
  615. }
  616. return shapeMetaData;
  617. }
  618. int CalculateMaxArrayCount(NativeArray<ShapeControlPoint> shapePoints)
  619. {
  620. int maxVertexCount = 1024 * 64;
  621. bool hasSprites = false;
  622. float smallestWidth = 99999.0f;
  623. if (null != spriteArray)
  624. {
  625. foreach (var sprite in m_SpriteArray)
  626. {
  627. if (sprite != null)
  628. {
  629. hasSprites = true;
  630. float pixelWidth = BezierUtility.GetSpritePixelWidth(sprite);
  631. smallestWidth = (smallestWidth > pixelWidth) ? pixelWidth : smallestWidth;
  632. }
  633. }
  634. }
  635. // Approximate vertex Array Count. Include Corners and Wide Sprites into account.
  636. float smallestSegment = smallestWidth;
  637. float shapeLength = BezierUtility.BezierLength(shapePoints, splineDetail, ref smallestSegment) * 4.0f;
  638. int adjustShape = shapePoints.Length * 4 * splineDetail;
  639. int adjustWidth = hasSprites ? ((int)(shapeLength / smallestSegment) * splineDetail) + adjustShape : 0;
  640. adjustShape = optimizeGeometry ? (adjustShape) : (adjustShape * 2);
  641. adjustShape = ValidateSpriteShapeTexture() ? adjustShape : 0;
  642. maxArrayCount = adjustShape + adjustWidth;
  643. maxArrayCount = math.min(maxArrayCount, maxVertexCount);
  644. return maxArrayCount;
  645. }
  646. #endregion
  647. unsafe JobHandle ScheduleBake()
  648. {
  649. JobHandle jobHandle = default;
  650. bool staticUpload = Application.isPlaying;
  651. #if !UNITY_EDITOR
  652. staticUpload = true;
  653. #endif
  654. if (staticUpload && geometryCached)
  655. {
  656. if (spriteShapeGeometryCache)
  657. if (spriteShapeGeometryCache.maxArrayCount != 0)
  658. return spriteShapeGeometryCache.Upload(spriteShapeRenderer, this);
  659. }
  660. int pointCount = spline.GetPointCount();
  661. NativeArray<ShapeControlPoint> shapePoints = GetShapeControlPoints();
  662. NativeArray<SplinePointMetaData> shapeMetaData = GetSplinePointMetaData();
  663. maxArrayCount = CalculateMaxArrayCount(shapePoints);
  664. if (maxArrayCount > 0 && enabled)
  665. {
  666. // Complate previos
  667. m_JobHandle.Complete();
  668. // Collider Data
  669. if (m_ColliderData.IsCreated)
  670. m_ColliderData.Dispose();
  671. m_ColliderData = new NativeArray<float2>(maxArrayCount, Allocator.Persistent);
  672. // Tangent Data
  673. if (!m_TangentData.IsCreated)
  674. m_TangentData = new NativeArray<Vector4>(1, Allocator.Persistent);
  675. NativeArray<ushort> indexArray;
  676. NativeSlice<Vector3> posArray;
  677. NativeSlice<Vector2> uv0Array;
  678. NativeArray<Bounds> bounds = spriteShapeRenderer.GetBounds();
  679. NativeArray<SpriteShapeSegment> geomArray = spriteShapeRenderer.GetSegments(shapePoints.Length * 8);
  680. NativeSlice<Vector4> tanArray = new NativeSlice<Vector4>(m_TangentData);
  681. if (m_EnableTangents)
  682. {
  683. spriteShapeRenderer.GetChannels(maxArrayCount, out indexArray, out posArray, out uv0Array, out tanArray);
  684. }
  685. else
  686. {
  687. spriteShapeRenderer.GetChannels(maxArrayCount, out indexArray, out posArray, out uv0Array);
  688. }
  689. var uTess2D = ValidateUTess2D();
  690. var spriteShapeJob = new SpriteShapeGenerator() { m_Bounds = bounds, m_PosArray = posArray, m_Uv0Array = uv0Array, m_TanArray = tanArray, m_GeomArray = geomArray, m_IndexArray = indexArray, m_ColliderPoints = m_ColliderData };
  691. spriteShapeJob.generateCollider = generateCollider;
  692. spriteShapeJob.generateGeometry = generateGeometry;
  693. spriteShapeJob.Prepare(this, m_ActiveShapeParameters, maxArrayCount, shapePoints, shapeMetaData, m_AngleRangeInfoArray, m_EdgeSpriteArray, m_CornerSpriteArray, uTess2D);
  694. // Only update Handle for an actual Job is scheduled.
  695. m_JobHandle = spriteShapeJob.Schedule();
  696. spriteShapeRenderer.Prepare(m_JobHandle, m_ActiveShapeParameters, m_SpriteArray);
  697. jobHandle = m_JobHandle;
  698. #if UNITY_EDITOR
  699. if (spriteShapeGeometryCache && geometryCached)
  700. spriteShapeGeometryCache.SetGeometryCache(maxArrayCount, posArray, uv0Array, tanArray, indexArray, geomArray);
  701. #endif
  702. JobHandle.ScheduleBatchedJobs();
  703. }
  704. if (m_DynamicOcclusionOverriden)
  705. {
  706. spriteShapeRenderer.allowOcclusionWhenDynamic = m_DynamicOcclusionLocal;
  707. m_DynamicOcclusionOverriden = false;
  708. }
  709. shapePoints.Dispose();
  710. shapeMetaData.Dispose();
  711. return jobHandle;
  712. }
  713. public void BakeCollider()
  714. {
  715. // Previously this must be explicitly called if using BakeMesh.
  716. // But now we do it internally. BakeCollider_CanBeCalledMultipleTimesWithoutJobComplete
  717. m_JobHandle.Complete();
  718. if (m_ColliderData.IsCreated)
  719. {
  720. if (autoUpdateCollider)
  721. {
  722. if (hasCollider)
  723. {
  724. int maxCount = short.MaxValue - 1;
  725. float2 last = (float2)0;
  726. List<Vector2> colliderSegment = new List<Vector2>();
  727. for (int i = 0; i < maxCount; ++i)
  728. {
  729. float2 now = m_ColliderData[i];
  730. if (!math.any(last) && !math.any(now))
  731. {
  732. if ((i+1) < maxCount)
  733. {
  734. float2 next = m_ColliderData[i+1];
  735. if (!math.any(next) && !math.any(next))
  736. break;
  737. }
  738. else
  739. break;
  740. }
  741. colliderSegment.Add(new Vector2(now.x, now.y));
  742. }
  743. if (edgeCollider != null)
  744. edgeCollider.points = colliderSegment.ToArray();
  745. if (polygonCollider != null)
  746. polygonCollider.points = colliderSegment.ToArray();
  747. #if UNITY_EDITOR
  748. UnityEditor.SceneView.RepaintAll();
  749. #endif
  750. }
  751. }
  752. // Dispose Collider as its no longer needed.
  753. m_ColliderData.Dispose();
  754. }
  755. }
  756. internal void BakeMeshForced()
  757. {
  758. if (spriteShapeRenderer != null)
  759. {
  760. var hasSplineChanged = HasSplineDataChanged();
  761. if (hasSplineChanged)
  762. {
  763. BakeMesh();
  764. Rendering.CommandBuffer rc = new Rendering.CommandBuffer();
  765. rc.GetTemporaryRT(0, 256, 256, 0);
  766. rc.SetRenderTarget(0);
  767. rc.DrawRenderer(spriteShapeRenderer, spriteShapeRenderer.sharedMaterial);
  768. rc.ReleaseTemporaryRT(0);
  769. Graphics.ExecuteCommandBuffer(rc);
  770. }
  771. }
  772. }
  773. }
  774. }