2025-09-08 14:51:28 +08:00
|
|
|
|
using System;
|
|
|
|
|
|
using System.Collections;
|
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
|
using UnityEngine;
|
|
|
|
|
|
using UnityEngine.Events;
|
2025-09-08 17:37:12 +08:00
|
|
|
|
namespace DongWuYiXue.DaoNiaoShu
|
2025-09-08 14:51:28 +08:00
|
|
|
|
{
|
|
|
|
|
|
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;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|