DecalMaster.cs 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261
  1. using System.Collections;
  2. using System.Collections.Generic;
  3. using System.Diagnostics;
  4. using UnityEngine;
  5. using Debug = UnityEngine.Debug;
  6. #if UNITY_EDITOR
  7. public class DecalMaster : MonoBehaviour
  8. {
  9. [Header("General")]
  10. [SerializeField] private DecalObject[] _decalObjects;
  11. [Header("Single Paper Mode Settings")]
  12. [SerializeField] private MeshRenderer decalRenderer;
  13. [SerializeField] private MeshRenderer targetObjectRenderer;
  14. [SerializeField] private Transform papersParent;
  15. [SerializeField] private Texture2D[] coloredPapers;
  16. private Texture2D newTargetObjectTexture;
  17. private bool projectingActive;
  18. private Coroutine currentProjectingCoroutine = null;
  19. private int imageIndex = 1;
  20. public bool ProjectingActive => projectingActive;
  21. [SerializeField] private MeshRenderer targetObjectRendererTemp;
  22. private Material originalTargetMaterial; // 用于保存原始材质信息
  23. private void Start()
  24. {
  25. // 深度拷贝targetObjectRenderer给targetObjectRendererTemp
  26. originalTargetMaterial = targetObjectRenderer.material;
  27. // Material newMaterial = new Material(originalTargetMaterial);
  28. //
  29. // // 设置新的纹理到材质中
  30. // Texture2D newDecalTexture2 = Resources.Load<Texture2D>("jackImageResBg/" + imageIndex%7);
  31. // newMaterial.mainTexture = newDecalTexture2;
  32. //
  33. // // 将新材质应用到目标对象
  34. // targetObjectRenderer.material = newMaterial;
  35. }
  36. private IEnumerator ProjectPapersCoroutine()
  37. {
  38. if (_decalObjects == null || _decalObjects.Length < 0)
  39. {
  40. Debug.LogWarning("Not found decal objects!");
  41. yield break;
  42. }
  43. for(int i = 0; i < _decalObjects.Length; i++)
  44. {
  45. if (_decalObjects[i].gameObject.activeInHierarchy)
  46. _decalObjects[i].gameObject.SetActive(false);
  47. }
  48. projectingActive = true;
  49. for (int i = 0; i < _decalObjects.Length; i++)
  50. {
  51. _decalObjects[i].gameObject.SetActive(true);
  52. yield return currentProjectingCoroutine = StartCoroutine(_decalObjects[i].Project());
  53. _decalObjects[i].gameObject.SetActive(false);
  54. Debug.LogWarning($"Finished Printing");
  55. yield return null;
  56. }
  57. projectingActive = false;
  58. yield break;
  59. }
  60. private IEnumerator ProjectSinglePaperCoroutine()
  61. {
  62. projectingActive = true;
  63. yield return currentProjectingCoroutine = StartCoroutine(Project());
  64. projectingActive = false;
  65. }
  66. private IEnumerator Project()
  67. {
  68. // Texture2D decalTexture = decalRenderer.sprite.texture;
  69. rndRandomColoredPape();
  70. Texture2D decalTexture = (Texture2D)decalRenderer.sharedMaterial.mainTexture;
  71. newTargetObjectTexture = new Texture2D(targetObjectRenderer.material.mainTexture.width, targetObjectRenderer.material.mainTexture.height, TextureFormat.RGBA32, false);
  72. Graphics.CopyTexture(targetObjectRenderer.material.mainTexture, newTargetObjectTexture);
  73. targetObjectRenderer.material.mainTexture = newTargetObjectTexture;
  74. int width = decalTexture.width;
  75. int height = decalTexture.height;
  76. for (int x = 0; x < width; x++)
  77. {
  78. for (int y = 0; y < height; y++)
  79. {
  80. if (decalTexture.GetPixel(x, y).a <= 0.1f)
  81. {
  82. continue;
  83. }
  84. ProjectPixel(x, y, decalTexture);
  85. }
  86. Debug.Log("Pixel printed");
  87. yield return null;
  88. }
  89. newTargetObjectTexture.Apply();
  90. SaveTexture();
  91. yield return new WaitForSeconds(3f);
  92. yield return null;
  93. imageIndex++;
  94. // 清空当前纹理
  95. Debug.Log("清空纹理");
  96. // targetObjectRenderer = targetObjectRendererTemp;
  97. // 加载要替换的新纹理,投射目标
  98. if (updatePrintImage())
  99. {
  100. }
  101. else
  102. {
  103. ProjectSinglePaper();
  104. }
  105. yield break;
  106. }
  107. private void rndRandomColoredPape()
  108. {
  109. targetObjectRenderer.sharedMaterial.mainTexture = GetRandomColoredPaper();
  110. }
  111. private void ProjectPixel(int x, int y, Texture2D decalTexture)
  112. {
  113. RaycastHit hit;
  114. Vector3 rayOrigin = GetRayOrigin(x, y, decalTexture);
  115. Vector3 rayDirection = decalRenderer.transform.forward;
  116. Ray ray = new Ray(rayOrigin, rayDirection);
  117. if (!Physics.Raycast(ray, out hit))
  118. return;
  119. Renderer rend = hit.transform.GetComponent<Renderer>();
  120. MeshCollider meshCollider = hit.collider as MeshCollider;
  121. if (rend == null || rend.sharedMaterial == null || rend.sharedMaterial.mainTexture == null || meshCollider == null)
  122. return;
  123. if (rend != targetObjectRenderer)
  124. return;
  125. Texture2D tex = rend.material.mainTexture as Texture2D;
  126. Vector2 pixelUV = hit.textureCoord;
  127. pixelUV.x *= tex.width;
  128. pixelUV.y *= tex.height;
  129. tex.SetPixel((int)pixelUV.x, (int)pixelUV.y, decalTexture.GetPixel(x, y));
  130. tex.Apply();
  131. }
  132. private Vector3 GetRayOrigin(int x, int y, Texture2D decalTexture)
  133. {
  134. float rightPercent = (float)x / decalTexture.width;
  135. float upPercent = (float)y / decalTexture.height;
  136. Vector3 startPosition = decalRenderer.transform.position;
  137. startPosition += decalRenderer.transform.right * (rightPercent - 0.5f) * decalRenderer.transform.localScale.x;
  138. startPosition += decalRenderer.transform.up * (upPercent - 0.5f) * decalRenderer.transform.localScale.y;
  139. return startPosition;
  140. }
  141. private bool updatePrintImage()
  142. {
  143. // 加载要替换的新纹理
  144. Texture2D newDecalTexture = Resources.Load<Texture2D>("jackImageRes/" + imageIndex); // 新纹理需要放在 Resources 文件夹下
  145. // 如果新纹理加载失败,可以在这里进行处理
  146. if (newDecalTexture == null)
  147. {
  148. Debug.LogError("找不到文件,打印结束, 输出错误ID: "+ imageIndex);
  149. return true;
  150. }
  151. // 直接替换decalRenderer中的纹理为新纹理
  152. decalRenderer.material.mainTexture = newDecalTexture;
  153. return false;
  154. }
  155. private void SaveTexture()
  156. {
  157. JTSystems.Utils.SaveTexture(newTargetObjectTexture, "/DecalToTexture/Fish/");
  158. }
  159. private void ConfigureChild(int paperIndex)
  160. {
  161. Paper currentPaper = papersParent.GetChild(paperIndex).GetComponent<Paper>();
  162. targetObjectRenderer = currentPaper.GetFrontRenderer();
  163. currentPaper.GetFrontRenderer().sharedMaterial.mainTexture = GetRandomColoredPaper();
  164. }
  165. private Texture2D GetRandomColoredPaper()
  166. {
  167. return coloredPapers[Random.Range(0, coloredPapers.Length)];
  168. }
  169. public void EnableNextPaper()
  170. {
  171. int currentActivePaperIndex = 0;
  172. for (int i = 0; i < papersParent.childCount; i++)
  173. {
  174. if (papersParent.GetChild(i).gameObject.activeSelf)
  175. {
  176. currentActivePaperIndex = i;
  177. break;
  178. }
  179. }
  180. currentActivePaperIndex++;
  181. if (currentActivePaperIndex >= papersParent.childCount)
  182. currentActivePaperIndex = 0;
  183. for (int i = 0; i < papersParent.childCount; i++)
  184. {
  185. if (i == currentActivePaperIndex)
  186. papersParent.GetChild(i).gameObject.SetActive(true);
  187. else
  188. papersParent.GetChild(i).gameObject.SetActive(false);
  189. }
  190. ConfigureChild(currentActivePaperIndex);
  191. }
  192. public void ProjectSinglePaper()
  193. {
  194. currentProjectingCoroutine = StartCoroutine(ProjectSinglePaperCoroutine());
  195. }
  196. public void ProjectAllPapers()
  197. {
  198. currentProjectingCoroutine = StartCoroutine(ProjectPapersCoroutine());
  199. }
  200. public void StopCurrentProjecting()
  201. {
  202. StopAllCoroutines();
  203. currentProjectingCoroutine = null;
  204. projectingActive = false;
  205. }
  206. }
  207. #endif