当前位置: 首页 > news >正文

Unity刮刮乐效果实现教程

目录

二、原理

三、实操

1.安装环境

2. 渲染纹理RenderTexture

3.写脚本:ScratchUI.cs

4.ShaderGraph

5. UI制作

6.材质球

7.挂脚本

四、运行测试

五、不同素材实现相同的效果


我们先来看看视频效果

image

其实这个无疑就是一个刮刮乐的效果

本文我实现了两种效果,最终效果如下:

image

image

工程源码见文章末尾。

二、原理

其原理是通过Alpha通道实现透明效果——当Alpha值为0时呈现透明状态。具体实现时,我们采用一张RenderTexture作为Alpha通道图,将其与UI主贴图的Alpha通道进行相乘运算。

实际操作中,我们只需在RenderTexture上根据鼠标刮擦的位置绘制相应的笔刷印记即可。

三、实操

1.安装环境

新建项目,安装ShaderGraph和升级URP项目

image

image

2. 渲染纹理RenderTexture

首先,创建一个渲染纹理

image

设置一下Render Texture的尺寸和格式

image

用photoshop做两张图,一张纯黑色的方图(用于初始化填充Render Texture),一张笔刷图,简单起见,笔刷图案我就用一个白点。

如下:

image

3.写脚本:ScratchUI.cs

代码的注释我写得比较清晰了,大家应该能看懂

// ScratchUI.cs
using UnityEngine;
using UnityEngine.EventSystems;/// <summary>
/// 刮刮乐UI组件
/// </summary>
public class ScratchUI : MonoBehaviour, IPointerDownHandler, IPointerUpHandler
{[Header("渲染设置")]public RenderTexture renderTexture;  // 目标渲染纹理public Texture brushTexture;         // 笔刷纹理public Texture blankTexture;         // 初始空白纹理[Header("UI组件")]public RectTransform rectTransform; // 遮罩区域public Canvas canvas;                // 所属画布private bool m_isMove = false;private void Start(){InitializeTexture();}/// <summary>/// 初始化渲染纹理为空白状态/// </summary>private void InitializeTexture(){RenderTexture.active = renderTexture;GL.PushMatrix();GL.LoadPixelMatrix(0, renderTexture.width, renderTexture.height, 0);Graphics.DrawTexture(new Rect(0, 0, renderTexture.width, renderTexture.height), blankTexture);GL.PopMatrix();RenderTexture.active = null;}/// <summary>/// 在指定坐标绘制笔刷/// </summary>private void Draw(int x, int y){RenderTexture.active = renderTexture;GL.PushMatrix();GL.LoadPixelMatrix(0, renderTexture.width, renderTexture.height, 0);// 调整坐标使笔刷居中x -= (int)(brushTexture.width * 0.5f);y -= (int)(brushTexture.height * 0.5f);Graphics.DrawTexture(new Rect(x, y, brushTexture.width, brushTexture.height),brushTexture);GL.PopMatrix();RenderTexture.active = null;}public void OnPointerDown(PointerEventData eventData){m_isMove = true;}public void OnPointerUp(PointerEventData eventData){m_isMove = false;}private void Update(){if (m_isMove){HandleScratch(Input.mousePosition);}}/// <summary>/// 处理刮卡操作/// </summary>private void HandleScratch(Vector2 screenPosition){Vector2 localPos = ScreenToLocalPosition(screenPosition, rectTransform, canvas.worldCamera);// 转换为UV坐标float uvX = (rectTransform.sizeDelta.x * 0.5f + localPos.x) / rectTransform.sizeDelta.x;float uvY = (rectTransform.sizeDelta.y * 0.5f + localPos.y) / rectTransform.sizeDelta.y;// 转换为渲染纹理坐标int x = (int)(uvX * renderTexture.width);int y = renderTexture.height - (int)(uvY * renderTexture.height);Draw(x, y);}/// <summary>/// 屏幕坐标转换为UI局部坐标/// </summary>private Vector2 ScreenToLocalPosition(Vector3 screenPos, RectTransform target, Camera cam){if (RectTransformUtility.ScreenPointToLocalPointInRectangle(target, screenPos, cam, out Vector2 localPos)){return localPos;}return Vector2.zero;}
}

// ScratchUI.cs
using UnityEngine;
using UnityEngine.EventSystems;
/// <summary>
/// 刮刮乐UI
/// </summary>
public class ScratchUI : MonoBehaviour, IPointerDownHandler, IPointerUpHandler
{/// <summary>/// 绘制的目标图片/// </summary>public RenderTexture renderTexture;/// <summary>/// 笔刷/// </summary>public Texture brushTexture;/// <summary>/// 空白图/// </summary>public Texture blankTexture;/// <summary>/// mask的RectTransform/// </summary>public RectTransform rectTransform;/// <summary>/// 画布/// </summary>public Canvas canvas;private bool m_isMove = false;private void Start(){DrawBlank();}/// <summary>/// 初始化RenderTexture/// </summary>private void DrawBlank(){// 激活rtRenderTexture.active = renderTexture;// 保存当前状态GL.PushMatrix();// 设置矩阵GL.LoadPixelMatrix(0, renderTexture.width, renderTexture.height, 0);// 绘制贴图Rect rect = new Rect(0, 0, renderTexture.width, renderTexture.height);Graphics.DrawTexture(rect, blankTexture);// 弹出改变GL.PopMatrix();RenderTexture.active = null;}/// <summary>/// 在RenderTexture的(x,y)坐标处画笔刷图案/// </summary>/// <param name="x">Graphics坐标系下的x</param>/// <param name="y">Graphics坐标系下的y</param>private void Draw(int x, int y){// 激活rtRenderTexture.active = renderTexture;// 保存当前状态GL.PushMatrix();// 设置矩阵GL.LoadPixelMatrix(0, renderTexture.width, renderTexture.height, 0);// 绘制笔刷图案x -= (int)(brushTexture.width * 0.5f);y -= (int)(brushTexture.height * 0.5f);Rect rect = new Rect(x, y, brushTexture.width, brushTexture.height);Graphics.DrawTexture(rect, brushTexture);// 弹出改变GL.PopMatrix();RenderTexture.active = null;}/// <summary>/// 按下/// </summary>public void OnPointerDown(PointerEventData data){m_isMove = true;}/// <summary>/// 抬起/// </summary>public void OnPointerUp(PointerEventData data){m_isMove = false;}private void Update(){if (m_isMove){OnMouseMove(Input.mousePosition);}}/// <summary>/// 刮卡/// </summary>/// <param name="position">刮卡的屏幕坐标</param>private void OnMouseMove(Vector2 position){// 获取刮的位置的ui局部坐标var uiLocalPos = ScreenPosToUiLocalPos(position, rectTransform, canvas.worldCamera);// 将局部坐标转化为uv坐标var uvX = (rectTransform.sizeDelta.x / 2f + uiLocalPos.x) / rectTransform.sizeDelta.x;var uvY = (rectTransform.sizeDelta.y / 2f + uiLocalPos.y) / rectTransform.sizeDelta.y;// 将uv坐标转化为Graphics坐标var x = (int)(uvX * renderTexture.width);// 注意,uv坐标系和Graphics坐标系的y轴方向相反var y = (int)(renderTexture.height - uvY * renderTexture.height);Draw(x, y);}/// <summary>/// 将屏幕坐标抓话为目标RectTransform的局部坐标/// </summary>/// <param name="screenPos">屏幕坐标</param>/// <param name="transform">目标RectTransform</param>/// <param name="cam">摄像机</param>/// <returns>ui局部坐标</returns>private Vector2 ScreenPosToUiLocalPos(Vector3 screenPos, RectTransform transform, Camera cam){Vector2 uiLocalPos;if (RectTransformUtility.ScreenPointToLocalPointInRectangle(transform, screenPos, cam, out uiLocalPos)){return uiLocalPos;}return Vector2.zero;}
}

4.ShaderGraph

创建一个Unlit ShaderGraph,实现UI主贴图的Alpha通道与和RenderTexture的相乘。

image

注意Graph Settings设置Surface为Transparent,Blend设置为Alpha。

image

暴露出两个变量,方便在材质球中设置参数。

image

5. UI制作

准备刮刮乐的UI图片,导入Unity中

image

image

拼成界面,如下。mask层就是要被刮掉的层。text可以写文字,比如恭喜中奖之类的

image

新建一个摄像机,用于渲染UI

image

最终效果

image

6.材质球

创建一个材质球ScratchMaterial,使用上面做的ShaderGraph,给材质球赋值贴图。

image

image

最后将材质赋给mask的Material。

image

7.挂脚本

将ScratchUI.cs脚本附加到mask对象上,并进行如下参数配置:

  • RenderTexture:用于存储Alpha通道的图像
  • Brush Texture:使用白色圆点作为笔刷图案
  • Blank Texture:采用纯黑色的空白纹理
  • RectTransform:绑定mask的RectTransform组件,用于坐标转换
  • Canvas:用于辅助坐标转换

image

四、运行测试

image

五、不同素材实现相同的效果

这是网友提供的素材

image

image

新建材质做相应的修改

image

其他照旧

image

最终效果

image

http://www.dtcms.com/a/329681.html

相关文章:

  • MySQL 分库分表详解(含实践示例)
  • C++ 中构造函数参数对父对象的影响:父子控件管理机制解析
  • 当img占不满div时,图片居中显示,两侧加当前图片模糊效果
  • Redis基础命令
  • 【易错题】C语言
  • Git Bash
  • Linux内存管理机制分析
  • 汽车免拆诊断案例 | 2010款奥迪A4L车行驶中发动机偶尔自动熄火
  • uniapp微信小程序-登录页面验证码的实现(springboot+vue前后端分离)EasyCaptcha验证码 超详细
  • 超实用!ToDesk/网易UU/向日葵:远程办公文件协作效率与安全实测
  • redis 内存使用率高居高不下,如何分析 key占用情况
  • 物联网之小白调试网关设备
  • 18.9 BERT问答模型实战:从数据到部署的完整指南
  • C++面试艺术:我的思考与避坑指南
  • framebuffer
  • 深入理解Java Set集合特性
  • windows下以all-in-one模式快速启动jaeger
  • Linux学习-UI技术
  • ROS2实用工具
  • Spring AI 的特性 及其 最佳实践
  • CompletableFuture介绍及使用方式
  • 天猫商品评论API:获取商品热门评价与最新评价
  • Jmeter TPS与QPS
  • Ant Design 的 `Image` 组件,通过 `preview.src` 加载本地图片文件
  • Dockerhub 代理设置
  • 破解测试数据困境:5招兼顾安全与真实性
  • Nature Communications 西湖大学姜汉卿教授:弹电磁驱动新范式--赋能昆虫级软体机器人的肌肉仿生策略
  • HTML第三次作业
  • Redis ubuntu下载Redis的C++客户端
  • Ubuntu 20.04 虚拟机安装完整教程:从 VMware 到 VMware Tools