文章目录
一、前言
嗨,大家好,我是新发。昨天写了篇文章:《使用Unity ShaderGraph实现在模型上涂鸦的效果,那么,纹个手吧》。
这个原理,可以触类旁通,比如刮刮乐的刮卡效果,也可以利用这个原理来实现,今天就教大家如何使用Unity ShaderGraph
实现刮刮乐的刮卡剔除效果。
本文最终效果如下:
本文Demo
工程已上传到CodeChina
(最近GitHub
貌似有问题,经常连不上),感兴趣的同学可自行下载学习。CodeChina
地址:https://codechina.csdn.net/linxinfa/UnityShaderGraphScratchTicket
注意,我使用的Unity
版本是2020.2.7f1c1
,ShaderGraph
版本是Version 10.3.2 - March 01, 2021
,如果你使用的版本比我的版本低,则可能运行我的Demo
工程会有问题。
二、原理
原理就是利用Alpha
通道,Alpha
为0
时透明,我们可以使用一张RenderTexture
作为Alpha
通道图,与UI
的主贴图的Alpha
通道图相乘即可。
根据鼠标刮的位置,在RenderTexture
上对应的位置画笔刷印记即可。
三、实操
1、RenderTexture
首先,创建一个Render Texture
。
设置一下Render Texture
的尺寸和格式。
2、笔刷图案
用photoshop
做两张图,一张纯黑色的方图(用于初始化填充Render Texture
),一张笔刷图,简单起见,笔刷图案我就用一个白点。
如下:
3、写脚本:ScratchUI.cs
开始写代码,就一个脚本:ScratchUI.cs
。代码的注释我写得比较清晰了,大家应该能看懂。
代码如下:
// 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()
{
// 激活rt
RenderTexture.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)
{
// 激活rt
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);
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)
{
onm ouseMove(Input.mousePosition);
}
}
/// <summary>
/// 刮卡
/// </summary>
/// <param name="position">刮卡的屏幕坐标</param>
private void onm ouseMove(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
的相乘。
注意Graph Settings
设置Surface
为Transparent
,Blend
设置为Alpha
。
暴露出两个变量,方便在材质球中设置参数。
5、UI制作
准备刮刮乐的UI
图片,导入Unity
中。
拼成界面,如下。mask
层就是要被刮掉的层。
6、材质球
创建一个材质球ScratchMaterial
,使用上面做的ShaderGraph
,给材质球赋值贴图。
最后将材质赋给mask
的Material
。
7、挂脚本
将ScratchUI.cs
脚本挂到mask
上,并设置好参数。RenderTexture
:用于Alpha
通道图;Brush Texture
:笔刷图案,一个白点;Blank Texture
:一张纯黑色的空白图;RectTransform
:mask
的RectTransform
,用于坐标转换;Canvas
:用于坐标转换。
四、运行测试
运行Unity
,测试效果如下: