SpriteShapeController.cs 29 KB

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