using System.Collections; using System.Collections.Generic; using System.Diagnostics; using UnityEngine; using Debug = UnityEngine.Debug; #if UNITY_EDITOR public class DecalMaster : MonoBehaviour { [Header("General")] [SerializeField] private DecalObject[] _decalObjects; [Header("Single Paper Mode Settings")] [SerializeField] private MeshRenderer decalRenderer; [SerializeField] private MeshRenderer targetObjectRenderer; [SerializeField] private Transform papersParent; [SerializeField] private Texture2D[] coloredPapers; private Texture2D newTargetObjectTexture; private bool projectingActive; private Coroutine currentProjectingCoroutine = null; private int imageIndex = 1; public bool ProjectingActive => projectingActive; [SerializeField] private MeshRenderer targetObjectRendererTemp; private Material originalTargetMaterial; // 用于保存原始材质信息 private void Start() { // 深度拷贝targetObjectRenderer给targetObjectRendererTemp originalTargetMaterial = targetObjectRenderer.material; // Material newMaterial = new Material(originalTargetMaterial); // // // 设置新的纹理到材质中 // Texture2D newDecalTexture2 = Resources.Load("jackImageResBg/" + imageIndex%7); // newMaterial.mainTexture = newDecalTexture2; // // // 将新材质应用到目标对象 // targetObjectRenderer.material = newMaterial; } private IEnumerator ProjectPapersCoroutine() { if (_decalObjects == null || _decalObjects.Length < 0) { Debug.LogWarning("Not found decal objects!"); yield break; } for(int i = 0; i < _decalObjects.Length; i++) { if (_decalObjects[i].gameObject.activeInHierarchy) _decalObjects[i].gameObject.SetActive(false); } projectingActive = true; for (int i = 0; i < _decalObjects.Length; i++) { _decalObjects[i].gameObject.SetActive(true); yield return currentProjectingCoroutine = StartCoroutine(_decalObjects[i].Project()); _decalObjects[i].gameObject.SetActive(false); Debug.LogWarning($"Finished Printing"); yield return null; } projectingActive = false; yield break; } private IEnumerator ProjectSinglePaperCoroutine() { projectingActive = true; yield return currentProjectingCoroutine = StartCoroutine(Project()); projectingActive = false; } private IEnumerator Project() { // Texture2D decalTexture = decalRenderer.sprite.texture; rndRandomColoredPape(); Texture2D decalTexture = (Texture2D)decalRenderer.sharedMaterial.mainTexture; newTargetObjectTexture = new Texture2D(targetObjectRenderer.material.mainTexture.width, targetObjectRenderer.material.mainTexture.height, TextureFormat.RGBA32, false); Graphics.CopyTexture(targetObjectRenderer.material.mainTexture, newTargetObjectTexture); targetObjectRenderer.material.mainTexture = newTargetObjectTexture; int width = decalTexture.width; int height = decalTexture.height; for (int x = 0; x < width; x++) { for (int y = 0; y < height; y++) { if (decalTexture.GetPixel(x, y).a <= 0.1f) { continue; } ProjectPixel(x, y, decalTexture); } Debug.Log("Pixel printed"); yield return null; } newTargetObjectTexture.Apply(); SaveTexture(); yield return new WaitForSeconds(3f); yield return null; imageIndex++; // 清空当前纹理 Debug.Log("清空纹理"); // targetObjectRenderer = targetObjectRendererTemp; // 加载要替换的新纹理,投射目标 if (updatePrintImage()) { } else { ProjectSinglePaper(); } yield break; } private void rndRandomColoredPape() { targetObjectRenderer.sharedMaterial.mainTexture = GetRandomColoredPaper(); } private void ProjectPixel(int x, int y, Texture2D decalTexture) { RaycastHit hit; Vector3 rayOrigin = GetRayOrigin(x, y, decalTexture); Vector3 rayDirection = decalRenderer.transform.forward; Ray ray = new Ray(rayOrigin, rayDirection); if (!Physics.Raycast(ray, out hit)) return; Renderer rend = hit.transform.GetComponent(); MeshCollider meshCollider = hit.collider as MeshCollider; if (rend == null || rend.sharedMaterial == null || rend.sharedMaterial.mainTexture == null || meshCollider == null) return; if (rend != targetObjectRenderer) return; Texture2D tex = rend.material.mainTexture as Texture2D; Vector2 pixelUV = hit.textureCoord; pixelUV.x *= tex.width; pixelUV.y *= tex.height; tex.SetPixel((int)pixelUV.x, (int)pixelUV.y, decalTexture.GetPixel(x, y)); tex.Apply(); } private Vector3 GetRayOrigin(int x, int y, Texture2D decalTexture) { float rightPercent = (float)x / decalTexture.width; float upPercent = (float)y / decalTexture.height; Vector3 startPosition = decalRenderer.transform.position; startPosition += decalRenderer.transform.right * (rightPercent - 0.5f) * decalRenderer.transform.localScale.x; startPosition += decalRenderer.transform.up * (upPercent - 0.5f) * decalRenderer.transform.localScale.y; return startPosition; } private bool updatePrintImage() { // 加载要替换的新纹理 Texture2D newDecalTexture = Resources.Load("jackImageRes/" + imageIndex); // 新纹理需要放在 Resources 文件夹下 // 如果新纹理加载失败,可以在这里进行处理 if (newDecalTexture == null) { Debug.LogError("找不到文件,打印结束, 输出错误ID: "+ imageIndex); return true; } // 直接替换decalRenderer中的纹理为新纹理 decalRenderer.material.mainTexture = newDecalTexture; return false; } private void SaveTexture() { JTSystems.Utils.SaveTexture(newTargetObjectTexture, "/DecalToTexture/Fish/"); } private void ConfigureChild(int paperIndex) { Paper currentPaper = papersParent.GetChild(paperIndex).GetComponent(); targetObjectRenderer = currentPaper.GetFrontRenderer(); currentPaper.GetFrontRenderer().sharedMaterial.mainTexture = GetRandomColoredPaper(); } private Texture2D GetRandomColoredPaper() { return coloredPapers[Random.Range(0, coloredPapers.Length)]; } public void EnableNextPaper() { int currentActivePaperIndex = 0; for (int i = 0; i < papersParent.childCount; i++) { if (papersParent.GetChild(i).gameObject.activeSelf) { currentActivePaperIndex = i; break; } } currentActivePaperIndex++; if (currentActivePaperIndex >= papersParent.childCount) currentActivePaperIndex = 0; for (int i = 0; i < papersParent.childCount; i++) { if (i == currentActivePaperIndex) papersParent.GetChild(i).gameObject.SetActive(true); else papersParent.GetChild(i).gameObject.SetActive(false); } ConfigureChild(currentActivePaperIndex); } public void ProjectSinglePaper() { currentProjectingCoroutine = StartCoroutine(ProjectSinglePaperCoroutine()); } public void ProjectAllPapers() { currentProjectingCoroutine = StartCoroutine(ProjectPapersCoroutine()); } public void StopCurrentProjecting() { StopAllCoroutines(); currentProjectingCoroutine = null; projectingActive = false; } } #endif