SpriteOutlineRenderer.cs 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  1. using System.Collections.Generic;
  2. using UnityEditor.U2D.Sprites;
  3. using UnityEngine;
  4. namespace UnityEditor.U2D.Animation
  5. {
  6. internal class SpriteOutlineRenderer
  7. {
  8. class OutlineRenderTexture
  9. {
  10. public Texture outlineTexture;
  11. public bool dirty;
  12. }
  13. Material m_OutlineMaterial;
  14. Material m_BitMaskMaterial;
  15. Dictionary<string, OutlineRenderTexture> m_OutlineTextureCache = new Dictionary<string, OutlineRenderTexture>();
  16. ISpriteEditorDataProvider m_CurrentDataProvider;
  17. SkinningEvents m_EventSystem;
  18. ISpriteEditor m_SpriteEditor;
  19. public SpriteOutlineRenderer(ISpriteEditor spriteEditor, SkinningEvents eventSystem)
  20. {
  21. m_BitMaskMaterial = new Material(Shader.Find("com.unity3d.animation/SpriteBitmask"));
  22. m_BitMaskMaterial.hideFlags = HideFlags.HideAndDontSave;
  23. m_OutlineMaterial = new Material(Shader.Find("com.unity3d.animation/SpriteOutline"));
  24. m_OutlineMaterial.hideFlags = HideFlags.HideAndDontSave;
  25. m_SpriteEditor = spriteEditor;
  26. m_EventSystem = eventSystem;
  27. m_EventSystem.meshPreviewChanged.AddListener(OnMeshPreviewChanged);
  28. m_EventSystem.selectedSpriteChanged.AddListener(OnSelectionChanged);
  29. CheckDataProviderChanged();
  30. }
  31. public void Dispose()
  32. {
  33. if (m_BitMaskMaterial != null)
  34. Object.DestroyImmediate(m_BitMaskMaterial);
  35. if (m_OutlineMaterial != null)
  36. Object.DestroyImmediate(m_OutlineMaterial);
  37. m_EventSystem.meshPreviewChanged.RemoveListener(OnMeshPreviewChanged);
  38. m_EventSystem.selectedSpriteChanged.RemoveListener(OnSelectionChanged);
  39. DestoryTextures();
  40. }
  41. private void OnMeshPreviewChanged(MeshPreviewCache mesh)
  42. {
  43. AddOrUpdateMaskTexture(mesh.sprite, true);
  44. }
  45. private void OnSelectionChanged(SpriteCache spriteCache)
  46. {
  47. CheckDataProviderChanged();
  48. AddOrUpdateMaskTexture(spriteCache, false);
  49. }
  50. private void DestoryTextures()
  51. {
  52. if (m_OutlineTextureCache != null)
  53. {
  54. foreach (var value in m_OutlineTextureCache.Values)
  55. {
  56. if (value != null && value.outlineTexture != null)
  57. Texture.DestroyImmediate(value.outlineTexture);
  58. }
  59. m_OutlineTextureCache.Clear();
  60. }
  61. }
  62. private void AddOrUpdateMaskTexture(SpriteCache sprite, bool regenerate)
  63. {
  64. SpriteCache selectedSprite = null;
  65. if (sprite != null)
  66. selectedSprite = sprite.skinningCache.selectedSprite;
  67. if (m_OutlineTextureCache != null && sprite != null)
  68. {
  69. if (!m_OutlineTextureCache.ContainsKey(sprite.id))
  70. m_OutlineTextureCache.Add(sprite.id, new OutlineRenderTexture() {dirty = true});
  71. var outlineTextureCache = m_OutlineTextureCache[sprite.id];
  72. outlineTextureCache.dirty |= regenerate;
  73. if (sprite == selectedSprite)
  74. {
  75. if (outlineTextureCache.dirty || outlineTextureCache.outlineTexture == null)
  76. {
  77. outlineTextureCache.outlineTexture = GenerateOutlineTexture(m_SpriteEditor, sprite, (RenderTexture)outlineTextureCache.outlineTexture);
  78. if (outlineTextureCache.outlineTexture != null)
  79. {
  80. outlineTextureCache.outlineTexture.hideFlags = HideFlags.HideAndDontSave;
  81. outlineTextureCache.dirty = false;
  82. }
  83. }
  84. m_OutlineMaterial.mainTexture = outlineTextureCache.outlineTexture;
  85. }
  86. }
  87. }
  88. private void CheckDataProviderChanged()
  89. {
  90. var dp = m_SpriteEditor.GetDataProvider<ISpriteEditorDataProvider>();
  91. if (dp != m_CurrentDataProvider)
  92. {
  93. DestoryTextures();
  94. m_OutlineTextureCache.Clear();
  95. m_CurrentDataProvider = dp;
  96. }
  97. }
  98. internal void RenderSpriteOutline(ISpriteEditor spriteEditor, SpriteCache sprite)
  99. {
  100. if (sprite == null)
  101. return;
  102. if (Event.current.type == EventType.Repaint)
  103. {
  104. UnityEngine.Profiling.Profiler.BeginSample("SpriteOutlineRenderer::RenderSpriteOutline");
  105. m_OutlineMaterial.SetColor("_OutlineColor", SelectionOutlineSettings.outlineColor);
  106. m_OutlineMaterial.SetFloat("_AdjustLinearForGamma", PlayerSettings.colorSpace == ColorSpace.Linear ? 1.0f : 0.0f);
  107. var texture = spriteEditor.GetDataProvider<ITextureDataProvider>().texture;
  108. float outlineSize = Mathf.Max(texture.width, texture.height) * SelectionOutlineSettings.selectedSpriteOutlineSize / 1024.0f;
  109. m_OutlineMaterial.SetFloat("_OutlineSize", outlineSize);
  110. var mesh = GetMesh(sprite);
  111. m_OutlineMaterial.SetPass(0);
  112. GL.PushMatrix();
  113. GL.MultMatrix(Handles.matrix * sprite.GetLocalToWorldMatrixFromMode());
  114. Rect r = new Rect(mesh.bounds.min.x, mesh.bounds.min.y, mesh.bounds.size.x, mesh.bounds.size.y);
  115. GL.Begin(GL.QUADS);
  116. GL.Color(Color.white);
  117. GL.TexCoord(new Vector3(0, 0, 0));
  118. GL.Vertex3(r.xMin, r.yMin, 0);
  119. GL.TexCoord(new Vector3(1, 0, 0));
  120. GL.Vertex3(r.xMax, r.yMin, 0);
  121. GL.TexCoord(new Vector3(1, 1, 0));
  122. GL.Vertex3(r.xMax, r.yMax, 0);
  123. GL.TexCoord(new Vector3(0, 1, 0));
  124. GL.Vertex3(r.xMin, r.yMax, 0);
  125. GL.End();
  126. GL.PopMatrix();
  127. UnityEngine.Profiling.Profiler.EndSample();
  128. }
  129. }
  130. private Texture GenerateOutlineTexture(ISpriteEditor spriteEditor, SpriteCache spriteCache, RenderTexture reuseRT)
  131. {
  132. if (spriteCache != null && spriteCache.textureRect.width != 0 && spriteCache.textureRect.height != 0)
  133. {
  134. UnityEngine.Profiling.Profiler.BeginSample("SpriteOutlineRenderer::GenerateOutlineTexture");
  135. var mesh = GetMesh(spriteCache);
  136. var b = mesh.bounds;
  137. if (reuseRT == null)
  138. {
  139. UnityEngine.Profiling.Profiler.BeginSample("SpriteOutlineRenderer::CreateRTNew");
  140. reuseRT = new RenderTexture((int)b.size.x, (int)b.size.y, 24, RenderTextureFormat.ARGBHalf);
  141. UnityEngine.Profiling.Profiler.EndSample();
  142. }
  143. else if (reuseRT.width != (int)b.size.x || reuseRT.height != (int)b.size.y)
  144. {
  145. UnityEngine.Profiling.Profiler.BeginSample("SpriteOutlineRenderer::CreateRTReuse");
  146. Object.DestroyImmediate(reuseRT);
  147. reuseRT = new RenderTexture((int)b.size.x, (int)b.size.y, 24, RenderTextureFormat.ARGBHalf);
  148. UnityEngine.Profiling.Profiler.EndSample();
  149. }
  150. m_BitMaskMaterial.mainTexture = spriteEditor.GetDataProvider<ITextureDataProvider>().texture;
  151. var oldRT = RenderTexture.active;
  152. Graphics.SetRenderTarget(reuseRT);
  153. m_BitMaskMaterial.SetPass(0);
  154. UnityEngine.Profiling.Profiler.BeginSample("SpriteOutlineRenderer::DrawMesh");
  155. GL.Clear(false, true, new Color(0, 0, 0, 0));
  156. GL.PushMatrix();
  157. GL.LoadOrtho();
  158. var h = b.size.y * 0.5f;
  159. var w = h * (b.size.x / b.size.y);
  160. GL.LoadProjectionMatrix(Matrix4x4.Ortho(-w, w, -h, h, -1, 1));
  161. GL.Begin(GL.QUADS);
  162. GL.Color(Color.white);
  163. Graphics.DrawMeshNow(mesh, Matrix4x4.Translate(-b.center));
  164. GL.End();
  165. GL.PopMatrix();
  166. Graphics.SetRenderTarget(oldRT);
  167. UnityEngine.Profiling.Profiler.EndSample();
  168. UnityEngine.Profiling.Profiler.EndSample();
  169. return reuseRT;
  170. }
  171. return null;
  172. }
  173. private Mesh GetMesh(SpriteCache sprite)
  174. {
  175. var meshPreview = sprite.GetMeshPreview();
  176. var skeleton = sprite.skinningCache.GetEffectiveSkeleton(sprite);
  177. Debug.Assert(meshPreview != null);
  178. Debug.Assert(skeleton != null);
  179. if (meshPreview.canSkin && skeleton.isPosePreview)
  180. return meshPreview.mesh;
  181. return meshPreview.defaultMesh;
  182. }
  183. }
  184. }