RenderExistingMeshGraphic.cs 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. /******************************************************************************
  2. * Spine Runtimes License Agreement
  3. * Last updated July 28, 2023. Replaces all prior versions.
  4. *
  5. * Copyright (c) 2013-2025, Esoteric Software LLC
  6. *
  7. * Integration of the Spine Runtimes into software or otherwise creating
  8. * derivative works of the Spine Runtimes is permitted under the terms and
  9. * conditions of Section 2 of the Spine Editor License Agreement:
  10. * http://esotericsoftware.com/spine-editor-license
  11. *
  12. * Otherwise, it is permitted to integrate the Spine Runtimes into software or
  13. * otherwise create derivative works of the Spine Runtimes (collectively,
  14. * "Products"), provided that each user of the Products must obtain their own
  15. * Spine Editor license and redistribution of the Products in any form must
  16. * include this license and copyright notice.
  17. *
  18. * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
  19. * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  20. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  21. * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
  22. * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  23. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
  24. * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
  25. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  26. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE
  27. * SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  28. *****************************************************************************/
  29. #if UNITY_2018_3 || UNITY_2019 || UNITY_2018_3_OR_NEWER
  30. #define NEW_PREFAB_SYSTEM
  31. #endif
  32. using System;
  33. using System.Collections.Generic;
  34. using UnityEngine;
  35. using UnityEngine.UI;
  36. namespace Spine.Unity.Examples {
  37. using MaterialReplacement = RenderExistingMesh.MaterialReplacement;
  38. #if NEW_PREFAB_SYSTEM
  39. [ExecuteAlways]
  40. #else
  41. [ExecuteInEditMode]
  42. #endif
  43. public class RenderExistingMeshGraphic : MonoBehaviour {
  44. public SkeletonGraphic referenceSkeletonGraphic;
  45. public Material replacementMaterial;
  46. public MaterialReplacement[] replacementMaterials = new MaterialReplacement[0];
  47. SkeletonSubmeshGraphic ownGraphic;
  48. public List<SkeletonSubmeshGraphic> ownSubmeshGraphics;
  49. #if UNITY_EDITOR
  50. private void Reset () {
  51. Awake();
  52. LateUpdate();
  53. }
  54. #endif
  55. void Awake () {
  56. // subscribe to OnMeshAndMaterialsUpdated
  57. if (referenceSkeletonGraphic) {
  58. referenceSkeletonGraphic.OnMeshAndMaterialsUpdated -= UpdateOnCallback;
  59. referenceSkeletonGraphic.OnMeshAndMaterialsUpdated += UpdateOnCallback;
  60. }
  61. ownGraphic = this.GetComponent<SkeletonSubmeshGraphic>();
  62. if (referenceSkeletonGraphic) {
  63. if (referenceSkeletonGraphic.allowMultipleCanvasRenderers)
  64. EnsureCanvasRendererCount(referenceSkeletonGraphic.canvasRenderers.Count);
  65. else
  66. SetupSubmeshGraphic();
  67. }
  68. }
  69. protected void OnDisable () {
  70. if (referenceSkeletonGraphic) {
  71. referenceSkeletonGraphic.OnMeshAndMaterialsUpdated -= UpdateOnCallback;
  72. }
  73. }
  74. protected void OnEnable () {
  75. #if UNITY_EDITOR
  76. // handle disabled scene reload
  77. if (Application.isPlaying) {
  78. Awake();
  79. return;
  80. }
  81. #endif
  82. if (referenceSkeletonGraphic) {
  83. referenceSkeletonGraphic.OnMeshAndMaterialsUpdated -= UpdateOnCallback;
  84. referenceSkeletonGraphic.OnMeshAndMaterialsUpdated += UpdateOnCallback;
  85. }
  86. }
  87. void SetupSubmeshGraphic () {
  88. if (ownGraphic == null)
  89. ownGraphic = this.gameObject.AddComponent<SkeletonSubmeshGraphic>();
  90. ownGraphic.maskable = referenceSkeletonGraphic.maskable;
  91. ownGraphic.canvasRenderer.cullTransparentMesh = referenceSkeletonGraphic.canvasRenderer.cullTransparentMesh;
  92. ownGraphic.canvasRenderer.SetMaterial(replacementMaterial, referenceSkeletonGraphic.mainTexture);
  93. }
  94. protected void EnsureCanvasRendererCount (int targetCount) {
  95. if (ownSubmeshGraphics == null)
  96. ownSubmeshGraphics = new List<SkeletonSubmeshGraphic>();
  97. bool cullTransparentMesh = referenceSkeletonGraphic.canvasRenderer.cullTransparentMesh;
  98. Vector2 pivot = referenceSkeletonGraphic.rectTransform.pivot;
  99. int currentCount = ownSubmeshGraphics.Count;
  100. for (int i = currentCount; i < targetCount; ++i) {
  101. GameObject go = new GameObject(string.Format("Renderer{0}", i), typeof(RectTransform));
  102. go.transform.SetParent(this.transform, false);
  103. go.transform.localPosition = Vector3.zero;
  104. CanvasRenderer canvasRenderer = go.AddComponent<CanvasRenderer>();
  105. canvasRenderer.cullTransparentMesh = cullTransparentMesh;
  106. SkeletonSubmeshGraphic submeshGraphic = go.AddComponent<SkeletonSubmeshGraphic>();
  107. ownSubmeshGraphics.Add(submeshGraphic);
  108. submeshGraphic.maskable = referenceSkeletonGraphic.maskable;
  109. submeshGraphic.raycastTarget = false;
  110. submeshGraphic.rectTransform.pivot = pivot;
  111. submeshGraphic.rectTransform.anchorMin = Vector2.zero;
  112. submeshGraphic.rectTransform.anchorMax = Vector2.one;
  113. submeshGraphic.rectTransform.sizeDelta = Vector2.zero;
  114. }
  115. }
  116. protected void UpdateCanvasRenderers () {
  117. Mesh[] referenceMeshes = referenceSkeletonGraphic.MeshesMultipleCanvasRenderers.Items;
  118. Material[] referenceMaterials = referenceSkeletonGraphic.MaterialsMultipleCanvasRenderers.Items;
  119. Texture[] referenceTextures = referenceSkeletonGraphic.TexturesMultipleCanvasRenderers.Items;
  120. int end = Math.Min(ownSubmeshGraphics.Count, referenceSkeletonGraphic.TexturesMultipleCanvasRenderers.Count);
  121. for (int i = 0; i < end; i++) {
  122. SkeletonSubmeshGraphic submeshGraphic = ownSubmeshGraphics[i];
  123. CanvasRenderer reference = referenceSkeletonGraphic.canvasRenderers[i];
  124. if (reference.gameObject.activeInHierarchy) {
  125. Material usedMaterial = replacementMaterial != null ?
  126. replacementMaterial : GetReplacementMaterialFor(referenceMaterials[i]);
  127. if (usedMaterial == null)
  128. usedMaterial = referenceMaterials[i];
  129. usedMaterial = referenceSkeletonGraphic.GetModifiedMaterial(usedMaterial);
  130. submeshGraphic.canvasRenderer.SetMaterial(usedMaterial, referenceTextures[i]);
  131. submeshGraphic.canvasRenderer.SetMesh(referenceMeshes[i]);
  132. submeshGraphic.gameObject.SetActive(true);
  133. } else {
  134. submeshGraphic.canvasRenderer.Clear();
  135. submeshGraphic.gameObject.SetActive(false);
  136. }
  137. }
  138. }
  139. protected void DisableCanvasRenderers () {
  140. for (int i = 0; i < ownSubmeshGraphics.Count; i++) {
  141. SkeletonSubmeshGraphic submeshGraphic = ownSubmeshGraphics[i];
  142. submeshGraphic.canvasRenderer.Clear();
  143. submeshGraphic.gameObject.SetActive(false);
  144. }
  145. }
  146. protected Material GetReplacementMaterialFor (Material originalMaterial) {
  147. for (int i = 0; i < replacementMaterials.Length; ++i) {
  148. MaterialReplacement entry = replacementMaterials[i];
  149. if (entry.originalMaterial != null && entry.originalMaterial.shader == originalMaterial.shader)
  150. return entry.replacementMaterial;
  151. }
  152. return null;
  153. }
  154. #if UNITY_EDITOR
  155. void LateUpdate () {
  156. if (!Application.isPlaying) {
  157. UpdateMesh();
  158. }
  159. }
  160. #endif
  161. void UpdateOnCallback (SkeletonGraphic g) {
  162. UpdateMesh();
  163. }
  164. void UpdateMesh () {
  165. if (!referenceSkeletonGraphic) return;
  166. if (referenceSkeletonGraphic.allowMultipleCanvasRenderers) {
  167. EnsureCanvasRendererCount(referenceSkeletonGraphic.canvasRenderers.Count);
  168. UpdateCanvasRenderers();
  169. if (ownGraphic)
  170. ownGraphic.canvasRenderer.Clear();
  171. } else {
  172. if (ownGraphic == null)
  173. ownGraphic = this.gameObject.AddComponent<SkeletonSubmeshGraphic>();
  174. DisableCanvasRenderers();
  175. Material referenceMaterial = referenceSkeletonGraphic.materialForRendering;
  176. Material usedMaterial = replacementMaterial != null ? replacementMaterial : GetReplacementMaterialFor(referenceMaterial);
  177. if (usedMaterial == null)
  178. usedMaterial = referenceMaterial;
  179. usedMaterial = referenceSkeletonGraphic.GetModifiedMaterial(usedMaterial);
  180. ownGraphic.canvasRenderer.SetMaterial(usedMaterial, referenceSkeletonGraphic.mainTexture);
  181. Mesh mesh = referenceSkeletonGraphic.GetLastMesh();
  182. ownGraphic.canvasRenderer.SetMesh(mesh);
  183. }
  184. }
  185. }
  186. }