UGUI—画笔
作者:追风剑情 发布于:2020-10-14 14:10 分类:Unity3d
示例:在Texture2D上的画笔功能
1、准备一张画笔图片
2、合成图片shader (可选功能)
Shader "Custom/ComposeShader" { Properties { _MainTex("Texture", 2D) = "white" {} _SecondTex("Texture", 2D) = "white" {} } SubShader { Tags { "Queue" = "Transparent" "RenderType" = "Transparent" } LOD 100 Pass { Blend SrcAlpha OneMinusSrcAlpha CGPROGRAM #pragma vertex vert #pragma fragment frag #include "UnityCG.cginc" struct appdata { float4 vertex : POSITION; float2 uv : TEXCOORD0; }; struct v2f { float2 uv : TEXCOORD0; float4 vertex : SV_POSITION; }; sampler2D _MainTex; float4 _MainTex_ST; sampler2D _SecondTex; float4 _SecondTex_ST; v2f vert(appdata v) { v2f o; o.vertex = UnityObjectToClipPos(v.vertex); o.uv = TRANSFORM_TEX(v.uv, _MainTex); return o; } fixed4 frag(v2f i) : SV_Target { fixed4 col = tex2D(_MainTex, i.uv); fixed4 col2 = tex2D(_SecondTex, i.uv); //step(a, x) 如果x<a,返回0;否则,返回1 //col2.a = step(0.95, col2.a); col.rgb = col.rgba * (1 - col2.a) + col2.rgba * col2.a; return col; } ENDCG } } }
3、画笔脚本
using System; using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; using UnityEngine.EventSystems; /// <summary> /// 画笔层 /// </summary> public class UIBrushLayer : MonoBehaviour, IPointerClickHandler { //画布的RectTransform [SerializeField] private RectTransform m_RectTransform; //显示画布 [SerializeField] private RawImage m_RawImage; //处理图片合成 [SerializeField] private Material m_ComposeMat; //画笔 //作为画笔的Texture需要在Inspector面板进行下面两项设置 //Texture Type: Default //Wrap Mode: Repeat //Read/Write Enabled: true [SerializeField] private Texture2D m_BrushPoint; //画布 private Texture2D m_CanvasTexture; private Vector2 m_LastPosition = new Vector2(-1, -1); private bool m_Pressed = false; [Tooltip("画笔颜色")] public Color BrushColor = Color.red; //[Tooltip("抗锯齿级别")] //[Range(1, 5)] //public int AnisoLevel = 3; //是否存在绘制 public bool IsBrushed { get; private set; } //是否启用 [SerializeField] private bool m_EnabledBrush = true; public bool EnabledBrush { get { return m_EnabledBrush; } set { m_EnabledBrush = value; m_LastPosition.x = m_LastPosition.y = -1; } } //是否点击清除 public bool ClickClear = false; //是否接收事件 public bool RaycastTarget { set { m_RawImage.raycastTarget = value; } } //绘制点 public Action<Point> OnTouchPointEvent; //取消绘制 public Action OnTouchCanceledEvent; //重置 private void Reset() { if (m_RectTransform == null) return; int width = (int)m_RectTransform.rect.width; int height = (int)m_RectTransform.rect.height; m_CanvasTexture = Texture2D.blackTexture; //Resize()方法会将所有像素值设置为(0.804, 0.804, 0.804, 0.804) //new Texture2D()也会将所有像素值设置为(0.804, 0.804, 0.804, 0.804) m_CanvasTexture.Resize(width, height); //将所有像素值设置为(0,0,0,0) Color[] colors = new Color[width * height]; m_CanvasTexture.SetPixels(colors); m_CanvasTexture.Apply(); m_RawImage.texture = m_CanvasTexture; m_RawImage.color = Color.white; IsBrushed = false; m_LastPosition.x = m_LastPosition.y = -1; } private void Start() { Reset(); SetBrushColor(BrushColor); } private void Update() { if (!EnabledBrush) return; CheckPressed(); if (!m_Pressed) return; if (m_LastPosition.x < 0 || m_LastPosition.y < 0) return; TouchBrush(); CheckRelease(); } private void OnDisable() { m_LastPosition.x = -1; m_LastPosition.y = -1; } //判断是否点击在自身的GameObject上 private bool IsPointerOverGameObject() { PointerEventData eventDataCurrentPosition = new PointerEventData(EventSystem.current); eventDataCurrentPosition.position = TouchPosition; List<RaycastResult> results = new List<RaycastResult>(); EventSystem.current.RaycastAll(eventDataCurrentPosition, results); if (results.Count == 0) return false; RaycastResult result = results[0]; return result.gameObject == this.gameObject; } public void OnPointerClick(PointerEventData eventData) { if (ClickClear && IsBrushed) Clear(); } //清空 public void Clear() { Reset(); } //当前触摸的位置(屏幕坐标) public Vector2 TouchPosition { get { Vector2 position = Vector2.zero; if (Input.touchSupported) { if (Input.touchCount > 0) position = Input.touches[0].position; } else { position = Input.mousePosition; } return position; } } //检测鼠标或手指是否按下 private void CheckPressed() { if (Input.touchSupported) { if (Input.touchCount > 0 && Input.touches[0].phase == TouchPhase.Began) { if (IsPointerOverGameObject()) { m_LastPosition = Input.touches[0].position; m_Pressed = true; } } } else if (Input.GetMouseButtonDown(0)) { if (IsPointerOverGameObject()) { m_LastPosition = Input.mousePosition; m_Pressed = true; } } } //检测鼠标或手指是否释放 private void CheckRelease() { if (Input.touchSupported) { if (Input.touchCount == 0 || Input.touches[0].phase == TouchPhase.Ended) { m_Pressed = false; if (OnTouchCanceledEvent != null) OnTouchCanceledEvent(); } } else if (Input.GetMouseButtonUp(0)) { m_Pressed = false; if (OnTouchCanceledEvent != null) OnTouchCanceledEvent(); } } //在指定点绘制 public void TouchBrush(Vector2 localPosition) { if (localPosition.x < 0 || localPosition.y < 0) { m_LastPosition.x = m_LastPosition.y = -1; return; } if (gameObject.activeInHierarchy) StartCoroutine(DrawLocalPointCoroutine(localPosition)); } //通过手指绘制曲线 private void TouchBrush() { StartCoroutine(DrawPointCoroutine(TouchPosition)); } //以协程方式绘制连续点 private IEnumerator DrawLocalPointCoroutine(Vector2 localPosition) { //绘制第一个起始点 if (m_LastPosition.x < 0 || m_LastPosition.y < 0) { DrawLocalPoint(localPosition); m_LastPosition = localPosition; m_CanvasTexture.Apply(); yield break; } //以插值方式绘制连续的点,形成曲线 float maxDistanceDelta = m_BrushPoint.width / 3; float distance = 0.0f; int loopCount = 0; do { distance = Vector2.Distance(localPosition, m_LastPosition); Vector2 lerpPosition = Vector2.MoveTowards(m_LastPosition, localPosition, maxDistanceDelta); DrawLocalPoint(lerpPosition); m_LastPosition = lerpPosition; //控制每帧最多绘制几个点,避免卡主线程 loopCount++; if (loopCount > 10) yield return null; loopCount = 0; } while (distance > 1.0f); m_LastPosition = localPosition; m_CanvasTexture.Apply(); } //以协程方式绘制连续点 private IEnumerator DrawPointCoroutine(Vector2 screenPosition) { //判断坐标是否在可绘区 if (!RectTransformUtility.RectangleContainsScreenPoint(m_RectTransform, screenPosition)) yield break; if (OnTouchPointEvent != null) { Vector2 localPosition = UGUITool.ScreenPointToLocal(m_RectTransform, screenPosition); OnTouchPointEvent(new Point() { x=(int)localPosition.x, y=(int)localPosition.y}); } yield return null; //以插值方式绘制连续的点,形成曲线 float maxDistanceDelta = m_BrushPoint.width / 3; float distance = 0.0f; int loopCount = 0; do { distance = Vector2.Distance(screenPosition, m_LastPosition); Vector2 lerpPosition = Vector2.MoveTowards(m_LastPosition, screenPosition, maxDistanceDelta); DrawPoint(lerpPosition); m_LastPosition = lerpPosition; //控制每帧最多绘制几个点,避免卡主线程 loopCount++; if (loopCount > 10) yield return null; loopCount = 0; } while (distance > 1.0f); m_LastPosition = screenPosition; m_CanvasTexture.Apply(); } //绘制单个点 private void DrawLocalPoint(Vector2 localPosition) { //使绘制时m_BrushPoint的中心点与点击位置对齐 localPosition.x -= m_BrushPoint.width / 2; localPosition.y -= m_BrushPoint.height / 2; //绘制画笔圆点 int x = (int)(localPosition.x); int y = (int)localPosition.y; int w = m_BrushPoint.width; int h = m_BrushPoint.height; for (int i = 0; i < w; i++) { for (int j = 0; j < h; j++) { Color c = m_BrushPoint.GetPixel(i, j); if (c.a > 0.9f) m_CanvasTexture.SetPixel(x + i, y + j, c); } } IsBrushed = true; } //绘制单个点 private void DrawPoint(Vector2 screenPosition) { //画笔层本地坐标 Vector2 localPosition = UGUITool.ScreenPointToLocal(m_RectTransform, screenPosition); DrawLocalPoint(localPosition); } //RenderTexture转Texture2D private Texture2D ConvertTexture2D(RenderTexture renderTexture) { int width = renderTexture.width; int height = renderTexture.height; Texture2D texture2D = new Texture2D(width, height, TextureFormat.ARGB32, false); RenderTexture.active = renderTexture; texture2D.ReadPixels(new Rect(0, 0, width, height), 0, 0); texture2D.Apply(); return texture2D; } //将画布合成到给定Texture上 public Texture2D ComposeTexture(Texture2D texture) { m_ComposeMat.SetTexture("_SecondTex", m_CanvasTexture); RenderTexture destRT = RenderTexture.GetTemporary(texture.width, texture.height, 0, RenderTextureFormat.ARGB32); Graphics.Blit(texture, destRT, m_ComposeMat); Texture2D composeTex = ConvertTexture2D(destRT); destRT.Release(); return composeTex; } //设置画笔颜色 public void SetBrushColor(Color color) { BrushColor = color; Texture2D newBrush = new Texture2D(m_BrushPoint.width, m_BrushPoint.height, TextureFormat.RGBA32, false); Color[] colors = new Color[m_BrushPoint.width * m_BrushPoint.height]; newBrush.SetPixels(colors); newBrush.Apply(); for (int i = 0; i < m_BrushPoint.width; i++) { for (int j = 0; j < m_BrushPoint.height; j++) { Color c = m_BrushPoint.GetPixel(i, j); if (c.a > 0.0f) { c.r = color.r; c.g = color.g; c.b = color.b; newBrush.SetPixel(i, j, c); } } } newBrush.Apply(); m_BrushPoint = newBrush; } public BrushRect GetBrushRect() { BrushRect rect = new BrushRect(); rect.width = (int)m_RectTransform.rect.width; rect.height = (int)m_RectTransform.rect.height; return rect; } private void OnDestroy() { OnTouchPointEvent = null; OnTouchCanceledEvent = null; } [Serializable] public class Point { public int x; public int y; public override string ToString() { return string.Format("({0},{1})", x, y); } } [Serializable] public class BrushPointList { public UIBrushLayer.Point[] points; } [Serializable] public class BrushRect { public int width; public int height; public override string ToString() { return string.Format("width={0},height{1}", width, height); } } }
4、挂上画笔脚本
BrushImage.mat
运行效果
标签: Unity3d
« 影创AR眼镜
|
UGUI—合成Texture»
日历
最新文章
随机文章
热门文章
分类
存档
- 2024年11月(3)
- 2024年10月(5)
- 2024年9月(3)
- 2024年8月(3)
- 2024年7月(11)
- 2024年6月(3)
- 2024年5月(9)
- 2024年4月(10)
- 2024年3月(11)
- 2024年2月(24)
- 2024年1月(12)
- 2023年12月(3)
- 2023年11月(9)
- 2023年10月(7)
- 2023年9月(2)
- 2023年8月(7)
- 2023年7月(9)
- 2023年6月(6)
- 2023年5月(7)
- 2023年4月(11)
- 2023年3月(6)
- 2023年2月(11)
- 2023年1月(8)
- 2022年12月(2)
- 2022年11月(4)
- 2022年10月(10)
- 2022年9月(2)
- 2022年8月(13)
- 2022年7月(7)
- 2022年6月(11)
- 2022年5月(18)
- 2022年4月(29)
- 2022年3月(5)
- 2022年2月(6)
- 2022年1月(8)
- 2021年12月(5)
- 2021年11月(3)
- 2021年10月(4)
- 2021年9月(9)
- 2021年8月(14)
- 2021年7月(8)
- 2021年6月(5)
- 2021年5月(2)
- 2021年4月(3)
- 2021年3月(7)
- 2021年2月(2)
- 2021年1月(8)
- 2020年12月(7)
- 2020年11月(2)
- 2020年10月(6)
- 2020年9月(9)
- 2020年8月(10)
- 2020年7月(9)
- 2020年6月(18)
- 2020年5月(4)
- 2020年4月(25)
- 2020年3月(38)
- 2020年1月(21)
- 2019年12月(13)
- 2019年11月(29)
- 2019年10月(44)
- 2019年9月(17)
- 2019年8月(18)
- 2019年7月(25)
- 2019年6月(25)
- 2019年5月(17)
- 2019年4月(10)
- 2019年3月(36)
- 2019年2月(35)
- 2019年1月(28)
- 2018年12月(30)
- 2018年11月(22)
- 2018年10月(4)
- 2018年9月(7)
- 2018年8月(13)
- 2018年7月(13)
- 2018年6月(6)
- 2018年5月(5)
- 2018年4月(13)
- 2018年3月(5)
- 2018年2月(3)
- 2018年1月(8)
- 2017年12月(35)
- 2017年11月(17)
- 2017年10月(16)
- 2017年9月(17)
- 2017年8月(20)
- 2017年7月(34)
- 2017年6月(17)
- 2017年5月(15)
- 2017年4月(32)
- 2017年3月(8)
- 2017年2月(2)
- 2017年1月(5)
- 2016年12月(14)
- 2016年11月(26)
- 2016年10月(12)
- 2016年9月(25)
- 2016年8月(32)
- 2016年7月(14)
- 2016年6月(21)
- 2016年5月(17)
- 2016年4月(13)
- 2016年3月(8)
- 2016年2月(8)
- 2016年1月(18)
- 2015年12月(13)
- 2015年11月(15)
- 2015年10月(12)
- 2015年9月(18)
- 2015年8月(21)
- 2015年7月(35)
- 2015年6月(13)
- 2015年5月(9)
- 2015年4月(4)
- 2015年3月(5)
- 2015年2月(4)
- 2015年1月(13)
- 2014年12月(7)
- 2014年11月(5)
- 2014年10月(4)
- 2014年9月(8)
- 2014年8月(16)
- 2014年7月(26)
- 2014年6月(22)
- 2014年5月(28)
- 2014年4月(15)
友情链接
- Unity官网
- Unity圣典
- Unity在线手册
- Unity中文手册(圣典)
- Unity官方中文论坛
- Unity游戏蛮牛用户文档
- Unity下载存档
- Unity引擎源码下载
- Unity服务
- Unity Ads
- wiki.unity3d
- Visual Studio Code官网
- SenseAR开发文档
- MSDN
- C# 参考
- C# 编程指南
- .NET Framework类库
- .NET 文档
- .NET 开发
- WPF官方文档
- uLua
- xLua
- SharpZipLib
- Protobuf-net
- Protobuf.js
- OpenSSL
- OPEN CASCADE
- JSON
- MessagePack
- C在线工具
- 游戏蛮牛
- GreenVPN
- 聚合数据
- 热云
- 融云
- 腾讯云
- 腾讯开放平台
- 腾讯游戏服务
- 腾讯游戏开发者平台
- 腾讯课堂
- 微信开放平台
- 腾讯实时音视频
- 腾讯即时通信IM
- 微信公众平台技术文档
- 白鹭引擎官网
- 白鹭引擎开放平台
- 白鹭引擎开发文档
- FairyGUI编辑器
- PureMVC-TypeScript
- 讯飞开放平台
- 亲加通讯云
- Cygwin
- Mono开发者联盟
- Scut游戏服务器引擎
- KBEngine游戏服务器引擎
- Photon游戏服务器引擎
- 码云
- SharpSvn
- 腾讯bugly
- 4399原创平台
- 开源中国
- Firebase
- Firebase-Admob-Unity
- google-services-unity
- Firebase SDK for Unity
- Google-Firebase-SDK
- AppsFlyer SDK
- android-repository
- CQASO
- Facebook开发者平台
- gradle下载
- GradleBuildTool下载
- Android Developers
- Google中国开发者
- AndroidDevTools
- Android社区
- Android开发工具
- Google Play Games Services
- Google商店
- Google APIs for Android
- 金钱豹VPN
- TouchSense SDK
- MakeHuman
- Online RSA Key Converter
- Windows UWP应用
- Visual Studio For Unity
- Open CASCADE Technology
- 慕课网
- 阿里云服务器ECS
- 在线免费文字转语音系统
- AI Studio
- 网云穿
- 百度网盘开放平台
- 迅捷画图
- 菜鸟工具
- [CSDN] 程序员研修院
- 华为人脸识别
- 百度AR导航导览SDK
- 海康威视官网
- 海康开放平台
- 海康SDK下载
- git download
交流QQ群
-
Flash游戏设计: 86184192
Unity游戏设计: 171855449
游戏设计订阅号