using System; using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.Events; namespace DongWuYiXue.DaoNiaoShu { public class DrawOn3D : MonoBehaviour { public Color paintColor = Vector4.one; [Range(10, 200)] public int paintSize = 60; [Range(0.2f, 10)] public float paintHardness = 1; [Range(0, 1.0f)] public float fullRatio = 1f; public UnityAction drawFull; public Texture2D brushTexture; public Transform mq; /// /// 主摄像机 /// private Camera cam; [SerializeField] private ComputeShader computer; [SerializeField] private ComputeShader clearDraw; [SerializeField] private Shader drawShader; [SerializeField] private Shader blitShader; private ComputeBuffer value; private int[] full = new int[1]; private int[] full2 = new int[1]; private RenderTexture rt2; private Material mat; private Material matblit; private bool isFull = false; private Mesh mesh; int limit; //public GameObject hand1; //public GameObject hand2; void Start() { cam = Camera.main; //ComputeBufferType.IndirectArguments认定此buffer大小必须为12字节 value = new ComputeBuffer(1, 4, ComputeBufferType.IndirectArguments); rt2 = new RenderTexture(512, 512, 8); rt2.enableRandomWrite = true; rt2.Create(); mat = new Material(drawShader); matblit = new Material(blitShader); mesh = GetComponent().sharedMesh; limit = rt2.width * rt2.height; } // 在RenderTexture的(x,y)坐标处画笔刷图案 private void Draw(int x, int y) { //绘制rendertexture RenderTexture.active = rt2; GL.PushMatrix(); GL.LoadPixelMatrix(0, rt2.width, rt2.height, 0); // 绘制贴图 x -= (int)(paintSize * 0.5f); y -= (int)(paintSize * 0.5f); Rect rect = new Rect(x, y, paintSize, paintSize);//brushTexture.width, brushTexture.height); mat.SetColor("_BaseColor", paintColor); mat.SetFloat("_PaintHardness", paintHardness); Graphics.DrawTexture(rect, brushTexture, mat, 0); // 弹出改变 GL.PopMatrix(); RenderTexture.active = null; //检测是否绘制满不用每帧执行,这里隔一帧执行一次 //if (run) //{ full[0] = 0; value.SetData(full); computer.SetTexture(0, "Result", rt2); computer.SetBuffer(0, "Full", value); computer.Dispatch(0, rt2.width / 8, rt2.height / 8, 1); value.GetData(full2); //} //run = !run; //full2等于1表示绘制满,等于0表示没有绘制满 if (full2[0] > limit * fullRatio) { drawFull?.Invoke(true); isFull = true; Debug.Log("已经画满"); } } private void Update() { if (Physics.Raycast(mq.localPosition, mq.forward, out RaycastHit hit)) { // hit.textureCoord是碰撞点的uv值,uv值是从0到1的,所以要乘以宽高才能得到具体坐标点 var x = (int)(hit.textureCoord.x * rt2.width) % rt2.width; // 注意,uv坐标系和Graphics坐标系的y轴方向相反 var y = (int)(rt2.height - hit.textureCoord.y * rt2.height) % rt2.height; Draw(x, y); } //渲染绘制的画面 matblit.SetTexture("_MainTex", rt2); matblit.SetColor("_BaseColor", paintColor); Graphics.DrawMesh(mesh, transform.localToWorldMatrix, matblit, 0); } public void ClearDraw() { clearDraw.SetTexture(0, "Result", rt2); clearDraw.Dispatch(0, rt2.width / 8, rt2.height / 8, 1); //清除画板后,画满回调可再次触发 isFull = false; } private void OnDestroy() { rt2.Release(); value.Release(); rt2 = null; value = null; } } }