2025-09-08 17:37:12 +08:00

130 lines
4.4 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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<bool> drawFull;
public Texture2D brushTexture;
public Transform mq;
/// <summary>
/// 主摄像机
/// </summary>
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<SkinnedMeshRenderer>().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;
}
}
}