Unity实现刮刮乐效果
2018-01-24 20:31
1041 查看
Unity实现刮刮乐效果
本文转自:http://www.manew.com/thread-113128-1-1.html,请点击链接查看原文,尊重楼主版权。网上看过了很多刮刮乐的文章,自己参考了一些,也改良了一些方法,比如说改良了画的每个点不连续的情况。具体效果如下:
做出这种效果,其实挺简单,主要就是利用unity的render texture加上自己写的遮罩shader。
我们首先设置两个摄像机,一个是专门渲染render texture用的,让它只能看到笔刷图层,命名为brushCamera,并且要设为dont clear模式:
然后我们要创建一个笔刷预设体,这个笔刷预设体主要实现笔刷效果:
下面的实现思路就是:
当按下鼠标时,我们就克隆一个笔刷,这样就形成了涂画的效果。
然后我们写一个遮罩shader,shader中需要两张图,一张是遮罩的图片(就是图中的蓝色图片),另一张是用于剔除遮罩的图片,我们将渲染出的rendertexture作为剔除遮罩的图片。这样就完成了刮刮乐效果。
其中,我们要注意几个问题:
1、由于当鼠标快速滑动时,可能会产生每个点不连续的情况,这里我们用了贝塞尔平滑方法进行处理。
2、大量克隆笔刷,会非常消耗性能,这里我们采用创建对象池方法的方法解决这个问题。
下面是主要的代码:
c#代码:
using System; using System.Collections; using System.Collections.Generic; using UnityEngine; public class DrawMask : MonoBehaviour { public float radius = 0.5f;//半径 public GameObject brush; bool startDraw = false; bool twoPoints = false; Vector2 lastPos;//最后一个点 Vector2 penultPos;//倒数第二个点 List<GameObject> brushesPool = new List<GameObject>(),activeBrushes = new List<GameObject>();//笔刷对象池 public delegate void DrawHandler(Vector2 pos); public event DrawHandler onStartDraw; public event DrawHandler onEndDraw; public event DrawHandler drawing; void Update () { GetInput(); } void GetInput() { if (Input.GetMouseButtonDown(0)) { startDraw = true; if (onStartDraw != null) { onStartDraw(VectorTransfer(Input.mousePosition)); } penultPos = Input.mousePosition; } else if (Input.GetMouseButton(0)) { if (twoPoints && Vector2.Distance(Input.mousePosition,lastPos) > 0.5f)//如果两次记录的鼠标坐标距离大于一定的距离,开始记录鼠标的点 { Vector2 pos = Input.mousePosition; float dis = Vector2.Distance(lastPos, pos); int segments = (int)(dis / radius);//计算出平滑的段数 segments = segments < 1 ? 1 : segments; Vector2[] points = Beizier(penultPos, lastPos, pos, segments);//进行贝塞尔平滑 for (int i = 0; i < points.Length; i++) { InstanceBrush(VectorTransfer(points[i])); } if (drawing != null) { drawing(VectorTransfer(Input.mousePosition)); } lastPos = pos; penultPos = points[points.Length - 2]; } else { twoPoints = true; lastPos = Input.mousePosition; } } else if (Input.GetMouseButtonUp(0)) { if (onEndDraw != null) { onEndDraw(VectorTransfer(Input.mousePosition)); } startDraw = false; twoPoints = false; } } private void OnPostRender() { InitBrushes(); } void InitBrushes() { for (int i = 0; i < activeBrushes.Count; i++) { activeBrushes[i].SetActive(false); brushesPool.Add(activeBrushes[i]); } activeBrushes.Clear(); } void InstanceBrush(Vector2 pos) { GameObject brushClone; if (brushesPool.Count > 0) { brushClone = brushesPool[brushesPool.Count - 1]; brushesPool.RemoveAt(brushesPool.Count - 1); } else { brushClone = Instantiate(brush, pos, Quaternion.identity); } brushClone.transform.position = pos; brushClone.transform.localScale = Vector3.one * radius; brushClone.SetActive(true); activeBrushes.Add(brushClone); } /// <summary> /// 贝塞尔平滑 /// </summary> /// <param name="start">起点</param> /// <param name="mid">中点</param> /// <param name="end">终点</param> /// <param name="segments">段数</param> /// <returns></returns> public Vector2[] Beizier(Vector2 start,Vector2 mid, Vector2 end,int segments) { float d = 1f / segments; Vector2[] points = new Vector2[segments - 1]; for (int i = 0; i < points.Length; i++) { float t = d * (i + 1); points[i] = (1 - t) * (1 - t) * mid + 2 * t * (1 - t) * start + t * t * end; } List<Vector2> rps = new List<Vector2>(); rps.Add(mid); rps.AddRange(points); rps.Add(end); return rps.ToArray(); } Vector2 VectorTransfer(Vector2 point) { return Camera.main.ScreenToWorldPoint(new Vector3(point.x, point.y, 0)); } }
遮罩shader:
// Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)' Shader "Custom/MaskShader" { Properties { _Color ("Color", Color) = (1,1,1,1) //_MainTex ("Albedo (RGB)", 2D) = "white" {} _MaskTex("Mask Texture",2D) = "white"{} _Mask("Mask",2D) = "white"{} } SubShader { Tags{"RenderType" = "Transparent" "Queue" = "Transparent"} pass { Blend SrcAlpha OneMinusSrcAlpha CGPROGRAM #pragma vertex vert #pragma fragment frag #include "unitycg.cginc" struct v2f { float4 pos:POSITION; float2 uv:TEXCOORD1; }; //sampler2D _MainTex; sampler2D _MaskTex; sampler2D _Mask; v2f vert(appdata_base v) { v2f o; o.pos = UnityObjectToClipPos(v.vertex); o.uv = v.texcoord; return o; } float4 frag(v2f i):COLOR { //float4 mainColor = tex2D(_MainTex,i.uv); float4 maskTexColor = tex2D(_MaskTex,i.uv); float4 maskColor = tex2D(_Mask,i.uv); maskTexColor.a = 1 - maskColor.a; return maskTexColor; } ENDCG } } FallBack "Diffuse" }
项目源码:请点击原链接查看楼主原文,尊重楼主版权,
相关文章推荐
- unity 使用shader加rendertexture实现刮刮乐效果
- Unity UGUI教程之实现滑页效果
- Unity鼠标悬停实现图片的浮动效果
- Paint之setXfermode----实现刮刮乐效果
- Unity教程之- UGUI分页效果的实现
- unity制作刮刮乐效果
- unity使用协程实现打字效果
- 如何在Unity中实现文字的渐隐效果?
- unity用shader实现物体的忽隐忽现效果
- unity使用AnimationCurve实现RPG中攻击与受伤时的分数的动态效果ScoreFlash
- 【Android界面实现】使用Canvas对象实现“刮刮乐”效果
- Unity Shaders and Effects Cookbook (2-1) 修改 UV 坐标实现纹理贴图的滚动 模拟水流效果
- NetWork网络_TCP_在unity中初步实现局域网互联效果
- unity_音轨可视化_效果实现_欧拉角的妙用和进一步理解
- unity_NGUI系统学习(十四)_游戏界面滑动切换的效果实现(无代码实现)
- unity5实现数字矩阵效果实现
- Unity 实现物体破碎效果(转)
- 【NGUI】Unity实现英雄联盟选择皮肤效果
- unity使用vuforia实现模型AR效果
- 【Unity】NGUI自制 Scroll View实现触摸滚动相册效果