Unity 实现橡皮擦效果

我所实现的橡皮擦效果是设置图片某点的像素的透明度为0,来简单实现擦除效果的;

下面是效果

首先需要注意两点:1:设置 Main Camera 的 projection 属性为Orthographic

2:设置Canvas 的Render Mode 为 Screen Space - Camera

然后找一张图片,导入Unity 中并修改它的读写权限,创建Raw Imager

这样启动之后就可以测试效果了。

附上代码:(代码中有解释)

  1 using AYUI.UIFrame;
  2 using DG.Tweening;
  3 using System;
  4 using System.Collections;
  5 using System.Collections.Generic;
  6 using UnityEngine;
  7 using UnityEngine.EventSystems;
  8 using UnityEngine.UI;
  9
 10 public class EraseMask : MonoBehaviour, IPointerDownHandler, IDragHandler, IPointerUpHandler
 11 {
 12
 13     //是否擦除了
 14     public bool isStartEraser;
 15
 16     //是否擦除结束了
 17     public bool isEndEraser;
 18
 19     //开始事件
 20     public Action eraserStartEvent;
 21
 22     //结束事件
 23     public Action eraserEndEvent;
 24
 25     public RawImage uiTex;
 26     Texture2D tex;
 27     Texture2D MyTex;
 28     int mWidth;
 29     int mHeight;
 30
 31     [Header("Brush Size")]
 32     public int brushSize = 50;
 33
 34     [Header("Rate")]
 35     public int rate = 90;
 36
 37     float maxColorA;
 38     float colorA;
 39
 40     void Awake()
 41     {
 42         tex = (Texture2D)uiTex.mainTexture;
 43         MyTex = new Texture2D(tex.width, tex.height, TextureFormat.ARGB32, false);
 44         mWidth = MyTex.width;
 45         mHeight = MyTex.height;
 46
 47         MyTex.SetPixels(tex.GetPixels());
 48         MyTex.Apply();
 49         uiTex.texture = MyTex;
 50         maxColorA = MyTex.GetPixels().Length;
 51         colorA = 0;
 52         isEndEraser = false;
 53         isStartEraser = false;
 54
 55     }
 56
 57
 58     /// <summary>
 59     /// 贝塞尔平滑
 60     /// </summary>
 61     /// <param name="start">起点</param>
 62     /// <param name="mid">中点</param>
 63     /// <param name="end">终点</param>
 64     /// <param name="segments">段数</param>
 65     /// <returns></returns>
 66     public Vector2[] Beizier(Vector2 start, Vector2 mid, Vector2 end, int segments)
 67     {
 68         float d = 1f / segments;
 69         Vector2[] points = new Vector2[segments - 1];
 70         for (int i = 0; i < points.Length; i++)
 71         {
 72             float t = d * (i + 1);
 73             points[i] = (1 - t) * (1 - t) * mid + 2 * t * (1 - t) * start + t * t * end;
 74         }
 75         List<Vector2> rps = new List<Vector2>();
 76         rps.Add(mid);
 77         rps.AddRange(points);
 78         rps.Add(end);
 79         return rps.ToArray();
 80     }
 81
 82
 83
 84     bool startDraw = false;
 85     bool twoPoints = false;
 86     Vector2 lastPos;//最后一个点
 87     Vector2 penultPos;//倒数第二个点
 88     float radius = 12f;
 89     float distance = 1f;
 90
 91
 92
 93     #region 事件
 94     public void OnPointerDown(PointerEventData eventData)
 95     {
 96         if (isEndEraser) { return; }
 97         startDraw = true;
 98         penultPos = eventData.position;
 99         CheckPoint(penultPos);
100     }
101
102     public void OnDrag(PointerEventData eventData)
103     {
104         if (isEndEraser) { return; }
105         if (twoPoints && Vector2.Distance(eventData.position, lastPos) > distance)//如果两次记录的鼠标坐标距离大于一定的距离,开始记录鼠标的点
106         {
107             Vector2 pos = eventData.position;
108             float dis = Vector2.Distance(lastPos, pos);
109
110             CheckPoint(eventData.position);
111             int segments = (int)(dis / radius);//计算出平滑的段数
112             segments = segments < 1 ? 1 : segments;
113             if (segments >= 10) { segments = 10; }
114             Vector2[] points = Beizier(penultPos, lastPos, pos, segments);//进行贝塞尔平滑
115             for (int i = 0; i < points.Length; i++)
116             {
117                 CheckPoint(points[i]);
118             }
119             lastPos = pos;
120             if (points.Length > 2)
121                 penultPos = points[points.Length - 2];
122         }
123         else
124         {
125             twoPoints = true;
126             lastPos = eventData.position;
127         }
128     }
129
130     public void OnPointerUp(PointerEventData eventData)
131     {
132         if (isEndEraser) { return; }
133         //CheckPoint(eventData.position);
134         startDraw = false;
135         twoPoints = false;
136     }
137
138
139     #endregion
140
141
142
143     void CheckPoint(Vector3 pScreenPos)
144     {
145         Vector3 worldPos = Camera.main.ScreenToWorldPoint(pScreenPos);
146         Vector3 localPos = uiTex.gameObject.transform.InverseTransformPoint(worldPos);
147
148         if (localPos.x > -mWidth / 2 && localPos.x < mWidth / 2 && localPos.y > -mHeight / 2 && localPos.y < mHeight / 2)
149         {
150             for (int i = (int)localPos.x - brushSize; i < (int)localPos.x + brushSize; i++)
151             {
152                 for (int j = (int)localPos.y - brushSize; j < (int)localPos.y + brushSize; j++)
153                 {
154                     if (Mathf.Pow(i - localPos.x, 2) + Mathf.Pow(j - localPos.y, 2) > Mathf.Pow(brushSize, 2))
155                         continue;
156                     if (i < 0) { if (i < -mWidth / 2) { continue; } }
157                     if (i > 0) { if (i > mWidth / 2) { continue; } }
158                     if (j < 0) { if (j < -mHeight / 2) { continue; } }
159                     if (j > 0) { if (j > mHeight / 2) { continue; } }
160
161                     Color col = MyTex.GetPixel(i + (int)mWidth / 2, j + (int)mHeight / 2);
162                     if (col.a != 0f)
163                     {
164                         col.a = 0.0f;
165                         colorA++;
166                         MyTex.SetPixel(i + (int)mWidth / 2, j + (int)mHeight / 2, col);
167                     }
168                 }
169             }
170
171
172             //开始刮的时候 去判断进度
173             if (!isStartEraser)
174             {
175                 isStartEraser = true;
176                 InvokeRepeating("getTransparentPercent", 0f, 0.2f);
177                 if (eraserStartEvent != null)
178                     eraserStartEvent.Invoke();
179             }
180
181             MyTex.Apply();
182         }
183     }
184
185
186
187     double fate;
188
189
190     /// <summary>
191     /// 检测当前刮刮卡 进度
192     /// </summary>
193     /// <returns></returns>
194     public void getTransparentPercent()
195     {
196         if (isEndEraser) { return; }
197
198
199         fate = colorA / maxColorA * 100;
200
201         fate = (float)Math.Round(fate, 2);
202
203         // Debug.LogError("当前百分比: " + fate);
204
205         if (fate >= rate)
206         {
207             isEndEraser = true;
208             CancelInvoke("getTransparentPercent");
209             gameObject.SetActive(false);
210
211             //触发结束事件
212             if (eraserEndEvent != null)
213                 eraserEndEvent.Invoke();
214
215         }
216     }
217
218 }

另附一张好用的图片 :https://pan.baidu.com/s/1Z_GTuwPouFtiSgVcFfrAcg

提取码:da7t

原文地址:https://www.cnblogs.com/lzzhentou/p/11634696.html

时间: 2024-08-24 23:32:10

Unity 实现橡皮擦效果的相关文章

2015.4.25-2015.5.1 字符串去重,比例圆设计,中奖机和canvas橡皮擦效果等

1.字符串去重,html模板取值 2.javascript正则表达式之$1...$9 3.jquery插件 4.返回上一页并刷新 解决方法: <a href ="javascript:location.href=document.referrer;"> 5.用webstorm写的手机网站 怎样能用手机预览呢? 解决方法:布署到wamp,xamp,iis上,然后用浏览器生成二维码,扫一扫就可以打开.假如是javaweb项目,挂上tomcat手机直接访问你机子的ip. 6.比例

Cocos2dx 实现擦除即橡皮擦效果的实现

Cocos2dx实现橡皮擦效果的实现 DionysosLai([email protected])  2014/8/25 之前项目在做一个绘本游戏,要求实现擦除效果,具体效果可以参考绘本<我是一只暴龙>,当时由于项目比较紧,是直接拿网上代码来用(感谢仁兄Zrong的入门之引,具体博文,详见地址,http://zengrong.net/post/2067.htm).当时,没有对其做一些具体优化工作,一些原理,也是似懂非懂.今天,在工作之余,重写了代码,并从始至末将知识点理清楚,务必要求自己能够搞

关于Unity中粒子效果的使用

粒子效果1: 游戏中会有很炫酷的特效,比如爆炸,水花,火焰等;2: unity提供粒子编辑器,方便特效人员来开发很炫酷的特效;3.粒子效果一般有专门的粒子特效师来做,我们只需要拿来用就好了,很多参数没必要掌握. Particle System组件面板 1: 粒子系统主体;2: 喷射(Emission);3: 形态(shape);4: 生命周期内的速度偏移(velocity over lifetime);5: 生命周期内的限制速度(limit velocity over lifetime);6:

unity传送门类似效果实现

简述 在传送门中,核心的玩法是在地上或者墙上打开2个可以联通的洞来实现传送的效果.以此扩展加入解谜要素构成游戏的核心. 这里尝试使用unity来实现传送门的核心功能,具体功能分析如下: 1.传送门的模型 2.传送门的贴图 3.传送门的传送功能 这里我们需要以下软件:3dmax 2014,unity3d 5.4.0,visual studio 2015 一.传送门的模型和uv        打开3dmax,确认系统单位和显示单位都为米,如果不为米,改成米         建立一个圆柱体,高度段数1

unity,荧光效果(bloom)实现过程

两个月前,刚接触unity的时候费了半天劲儿做了个荧光效果(见:http://www.cnblogs.com/wantnon/p/4430749.html),今天终于抽空整理了一下,把过程写下来. 荧光效果如图:   一,接口: 整理完以后得到三个东西:AE_GroupBloom.cs,Camera_renderBloomRT.prefab,bloomEmitter.shader. 使用方法: 1,将AE_GroupBloom.cs添加到Main Camera上. 2,将Camera_rende

Unity 摄像机抖动效果

以下是摄像机抖动效果源码: using UnityEngine; using System.Collections; public class SC_shakeCamera : MonoBehaviour{         private float shakeTime = 0.0f;         private float fps = 20.0f;         private float frameTime = 0.0f;         private float shakeDelt

canvas 橡皮擦效果制作

擦除一定数量后全部消失的有用 imageData 方法的 我把代码贴在最下面 <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title></title> <style type="text/css"> body{ overflow: hidden; } #canvas{ display: block; margin: 0

Unity Shader 广告牌效果

广告牌效果指的是,一个二维平面的法线方向始终与视线(摄像机的观察方向)相同.广泛运用于渲染烟雾,云朵,闪光等. 它的本质在于构建旋转矩阵,此时我们可以选择三个基向量来构建此矩阵. 指向→的方向(X轴) 指向↑的方向(Y轴) 平面的法线方向(Z轴) 计算方法通常是: 1.根据当前摄像机的方向确定法线方向(广告牌效果的本质),并归一化 normal=normalize(viewDir); 2.根据得到的法线方向和初始的向上方向(在本地空间中即为float3(0,1,0))计算向右的方向,并归一化 r

Canvas 橡皮擦效果

引子 解决了第一个问题图像灰度处理之后,接着就是做擦除的效果. Origin My GitHub 思路 一开始想到 Canvas 的画布可以相互覆盖的特性,彩色原图作为背景,灰度图渲染到 Canvas 画布上,然后手指滑动的时候,把接触的部分清除掉,就显示出了背景图.关键的部分是怎么清除画布上已有图像,查询资料发现有两种方式: 使用 clearRect 方法,会把指定范围所有像素变成透明,并擦除之前绘制的所有内容. 使用 globalCompositeOperation 属性,该属性设置在绘制新