UGUI利用RawImage实现涂鸦效果

using UnityEngine;
using System.Collections;
using UnityEngine.UI;
using YMFrame;
using System;
using System.Collections.Generic;
using Random = UnityEngine.Random;

namespace YMFrame
{
public class Painting : MonoBehaviour
{
private RenderTexture texRender; //画布
public Material _mPaintMaterial = null; //给定的shader新建材质
public Texture brushTypeTexture; //画笔纹理,半透明
public Shader paintShader;

    private float brushScale = 0.5f;
    public Color brushColor = Color.white; //new Color(219, 174, 68, 255) / 255;
    public RawImage raw_paint;                   //使用UGUI的RawImage显示,方便进行添加UI
    public RawImage totalShowRaw;
    private float lastDistance;
    private Vector3[] PositionArray = new Vector3[3];
    private int a = 0;
    private Vector3[] PositionArray1 = new Vector3[4];
    private int b = 0;
    private float[] speedArray = new float[4];
    private int s = 0;
    public int num = 50;

    public bool isPaintMagic;
    private int paintTimes;

    private float paint_x;

    private float raw_height;
    private float raw_width;

    private float raw_max_y;

    private float scale_x;
    private float scale_y;

    Vector3 startPosition = Vector3.zero;
    Vector3 endPosition = Vector3.zero;

    private Vector2 canvasSizeDelta;

    public void Init(RawImage _raw, Texture _brushType, RawImage _totalShowRaw, bool _isMagic, int _scale)
    {
        //canvasSizeDelta = GufengxGameSystem.Instance.gameContext.UIList.GetComponent<RectTransform>().sizeDelta;
        isPaintMagic = _isMagic;
        totalShowRaw = _totalShowRaw;
        brushTypeTexture = _brushType;
        raw_paint = _raw;

        //if (_scale != 1)
        //{
        //    Vector2 _size = raw_paint.GetComponent<RectTransform>().sizeDelta;
        //    _size.x = canvasSizeDelta.x * _scale;
        //    raw_paint.GetComponent<RectTransform>().sizeDelta = _size;
        //    Vector3 recordPos = raw_paint.transform.localPosition;
        //    recordPos.x = (_size.x - canvasSizeDelta.x) / 2.0f;
        //    raw_paint.transform.localPosition = recordPos;
        //}

        //IAssetService assetService = Services.GetService<IAssetService>();
        //LoadedAsset loadedAsset = assetService.LoadAssetSync<Shader>("shaders/based_shaders", "Painting");
        //paintShader = loadedAsset.GetAsset<Shader>();

        texRender = new RenderTexture(Screen.width, Screen.height, 24, RenderTextureFormat.ARGB32);
        Clear(texRender);
        raw_width = raw_paint.GetComponent<RectTransform>().sizeDelta.x * 1.0f;
        raw_height = raw_paint.GetComponent<RectTransform>().sizeDelta.y * 1.0f;

        scale_x = Screen.width / raw_width;
        scale_y = Screen.height / raw_height;
        raw_max_y = (canvasSizeDelta.y + raw_height) / 2 + raw_paint.transform.localPosition.y;
    }

    protected Material PaintMaterial
    {
        get
        {
            if (_mPaintMaterial == null)
            {
                _mPaintMaterial = new Material(paintShader);
            }
            return _mPaintMaterial;
        }
    }

    void Update()
    {
        if ((isPaintMagic == false || paintTimes < 1))
        {
            if (Input.GetMouseButton(0))
            {
                if (!raw_paint.color.Equals(Color.black))
                {
                    raw_paint.color = Color.black;
                }
                OnMouseMove(new Vector3(Input.mousePosition.x, Input.mousePosition.y, 0));
            }
            if (Input.GetMouseButtonUp(0))
            {
                OnMouseUp();
                paintTimes++;
            }
            DrawImage();
            if (totalShowRaw != null)
            {
                totalShowRaw.texture = raw_paint.texture;
            }
        }
    }

    void OnMouseUp()
    {
        startPosition = Vector3.zero;
        //brushScale = 0.5f;
        a = 0;
        b = 0;
        s = 0;
    }

    //设置画笔宽度
    float SetScale(float distance)
    {
        float Scale = 0;
        if (distance < 100)
        {
            Scale = 0.8f - 0.005f * distance;
        }
        else
        {
            Scale = 0.425f - 0.00125f * distance;
        }
        if (Scale <= 0.05f)
        {
            Scale = 0.05f;
        }
        return Scale;
    }

    void OnMouseMove(Vector3 pos)
    {
        pos = SwitchPos(pos);
        if (startPosition == Vector3.zero)
        {
            //startPosition = new Vector3(Input.mousePosition.x, Input.mousePosition.y, 0);
            startPosition = pos;
        }

        endPosition = pos;
        float distance = Vector3.Distance(startPosition, endPosition);
        brushScale = SetScale(distance);
        ThreeOrderBézierCurse(pos, distance, 4.5f);

        startPosition = endPosition;
        lastDistance = distance;
    }

    private Vector3 SwitchPos(Vector3 pos)
    {
        pos.y = pos.y / (Screen.height / canvasSizeDelta.y);
        Vector3 _pos = pos;
        float ratio_y = 1 - (raw_max_y - _pos.y) / raw_height;
        _pos.y = Screen.height * ratio_y;
        return _pos;
    }

    public void Clear(RenderTexture destTexture)
    {
        Graphics.SetRenderTarget(destTexture);
        GL.PushMatrix();
        GL.Clear(true, true, new Color(0, 0, 0, 0));
        //GL.Clear(true, true, Color.white);
        GL.PopMatrix();
    }

    void DrawBrush(RenderTexture destTexture, int x, int y, Texture sourceTexture, Color color, float scale)
    {
        float _x = x;
        paint_x = raw_paint.transform.localPosition.x;
        _x = (canvasSizeDelta.x / raw_width) * x + ((raw_width - canvasSizeDelta.x) / 2 - paint_x) / (raw_width / Screen.width);

        DrawBrush(destTexture, new Rect(_x, y, sourceTexture.width * scale_x * 0.8f, sourceTexture.height * scale_y * 0.8f), sourceTexture, color, scale);
    }

    void DrawBrush(RenderTexture destTexture, Rect destRect, Texture sourceTexture, Color color, float scale)
    {
        float left = destRect.xMin - destRect.width * scale / 2.0f;
        float right = destRect.xMin + destRect.width * scale / 2.0f;
        float top = destRect.yMin - destRect.height * scale / 2.0f;
        float bottom = destRect.yMin + destRect.height * scale / 2.0f;

        Graphics.SetRenderTarget(destTexture);

        GL.PushMatrix();
        GL.LoadOrtho();

        PaintMaterial.SetTexture("_MainTex", brushTypeTexture);
        PaintMaterial.SetColor("_Color", color);
        PaintMaterial.SetPass(0);

        GL.Begin(GL.QUADS);

        GL.TexCoord2(0.0f, 0.0f); GL.Vertex3(left / Screen.width, top / Screen.height, 0);
        GL.TexCoord2(1.0f, 0.0f); GL.Vertex3(right / Screen.width, top / Screen.height, 0);
        GL.TexCoord2(1.0f, 1.0f); GL.Vertex3(right / Screen.width, bottom / Screen.height, 0);
        GL.TexCoord2(0.0f, 1.0f); GL.Vertex3(left / Screen.width, bottom / Screen.height, 0);

        GL.End();
        GL.PopMatrix();
    }

    void DrawImage()
    {
        raw_paint.texture = texRender;
    }

    public void OnClickClear()
    {
        Clear(texRender);
    }

    //二阶贝塞尔曲线
    public void TwoOrderBézierCurse(Vector3 pos, float distance)
    {
        PositionArray[a] = pos;
        a++;
        if (a == 3)
        {
            for (int index = 0; index < num; index++)
            {
                Vector3 middle = (PositionArray[0] + PositionArray[2]) / 2;
                PositionArray[1] = (PositionArray[1] - middle) / 2 + middle;

                float t = (1.0f / num) * index / 2;
                Vector3 target = Mathf.Pow(1 - t, 2) * PositionArray[0] + 2 * (1 - t) * t * PositionArray[1] +
                                 Mathf.Pow(t, 2) * PositionArray[2];
                float deltaSpeed = (float)(distance - lastDistance) / num;
                DrawBrush(texRender, (int)target.x, (int)target.y, brushTypeTexture, brushColor, SetScale(lastDistance + (deltaSpeed * index)));
            }
            PositionArray[0] = PositionArray[1];
            PositionArray[1] = PositionArray[2];
            a = 2;
        }
        else
        {
            DrawBrush(texRender, (int)endPosition.x, (int)endPosition.y, brushTypeTexture,
                brushColor, brushScale);
        }
    }

    //三阶贝塞尔曲线,获取连续4个点坐标,通过调整中间2点坐标,画出部分(我使用了num/1.5实现画出部分曲线)来使曲线平滑;通过速度控制曲线宽度。
    private void ThreeOrderBézierCurse(Vector3 pos, float distance, float targetPosOffset)
    {
        //记录坐标
        PositionArray1[b] = pos;
        b++;
        //记录速度
        speedArray[s] = distance;
        s++;
        if (b == 4)
        {
            Vector3 temp1 = PositionArray1[1];
            Vector3 temp2 = PositionArray1[2];

            //修改中间两点坐标
            Vector3 middle = (PositionArray1[0] + PositionArray1[2]) / 2;
            PositionArray1[1] = (PositionArray1[1] - middle) * 1.5f + middle;
            middle = (temp1 + PositionArray1[3]) / 2;
            PositionArray1[2] = (PositionArray1[2] - middle) * 2.1f + middle;

            for (int index1 = 0; index1 < num / 1.5f; index1++)
            {
                float t1 = (1.0f / num) * index1;
                Vector3 target = Mathf.Pow(1 - t1, 3) * PositionArray1[0] +
                                 3 * PositionArray1[1] * t1 * Mathf.Pow(1 - t1, 2) +
                                 3 * PositionArray1[2] * t1 * t1 * (1 - t1) + PositionArray1[3] * Mathf.Pow(t1, 3);
                //float deltaspeed = (float)(distance - lastDistance) / num;
                //获取速度差值(存在问题,参考)
                float deltaspeed = (float)(speedArray[3] - speedArray[0]) / num;
                //float randomOffset = Random.Range(-1/(speedArray[0] + (deltaspeed * index1)), 1 / (speedArray[0] + (deltaspeed * index1)));
                //模拟毛刺效果
                float randomOffset = Random.Range(-targetPosOffset, targetPosOffset);
                DrawBrush(texRender, (int)(target.x + randomOffset), (int)(target.y + randomOffset), brushTypeTexture, brushColor, SetScale(speedArray[0] + (deltaspeed * index1)));
            }

            PositionArray1[0] = temp1;
            PositionArray1[1] = temp2;
            PositionArray1[2] = PositionArray1[3];

            speedArray[0] = speedArray[1];
            speedArray[1] = speedArray[2];
            speedArray[2] = speedArray[3];
            b = 3;
            s = 3;
        }
        else
        {
            DrawBrush(texRender, (int)endPosition.x, (int)endPosition.y, brushTypeTexture,
                brushColor, brushScale);
        }
    }
}

}

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值