130 lines
4.4 KiB
C#
130 lines
4.4 KiB
C#
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;
|
||
}
|
||
}
|
||
} |