To create a game with a scratch mode, I need a shader.
There are 3 images in the screenshot: 1. The little red dot. 2. The image of gray. 3 Background. I need to get in that place where A red dot gray image become transparent.
As a result, after moving the red dot to remain transparent trail where you can see the background.
This should be similar to the eraser.
I tried to use 2 shaders and script with GL. Project was built for Android. But when you open the application on android you can see an error. T[59991-1.png`Shader “TextureMasking”|59991]he bug had appeared only after the use of GL
Blockquote
{
Properties{
_MainTex("Main", 2D) = "white" {}
_MaskTex("Mask", 2D) = "white" {}
}
SubShader{
Tags{ "Queue" = "Transparent" "IgnoreProjector" = "True" "RenderType" = "Transparent" }
ZWrite Off
ZTest Off
Blend SrcAlpha OneMinusSrcAlpha
Pass{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma fragmentoption ARB_precision_hint_fastest
#include “UnityCG.cginc”
uniform sampler2D _MainTex;
uniform sampler2D _MaskTex;
uniform float4 _MainTex_ST;
uniform float4 _MaskTex_ST;
struct app2vert
{
float4 position: POSITION;
float2 texcoord: TEXCOORD0;
};
struct vert2frag
{
float4 position: POSITION;
float2 texcoord: TEXCOORD0;
};
vert2frag vert(app2vert input)
{
vert2frag output;
output.position = mul(UNITY_MATRIX_MVP, input.position);
output.texcoord = TRANSFORM_TEX(input.texcoord, _MainTex);
return output;
}
fixed4 frag(vert2frag input) : COLOR
{
fixed4 main_color = tex2D(_MainTex, input.texcoord);
fixed4 mask_color = tex2D(_MaskTex, input.texcoord);
return fixed4(main_color.r, main_color.g, main_color.b, main_color.a * (1.0f - mask_color.a));
}
ENDCG
}
}
Shader “Scratch”
{
Properties{
_Color(“Main Color”, Color) = (1,1,1,1)
_MainTex(“Base (RGB) Trans (A)”, 2D) = “white” {}
}
SubShader{
Tags{ "Queue" = "Transparent" "IgnoreProjector" = "True" "RenderType" = "Transparent" }
ZWrite Off
ZTest Off
Blend One One
BlendOp Max
Pass{
Lighting Off
SetTexture[_MainTex]{
matrix[_UVMatrix]
ConstantColor[_Color]
combine texture * constant
}
}
}
}
using UnityEngine;
using System.Collections;
using UnityEngine.EventSystems;
using UnityEngine.UI;
public class ScratchController : MonoBehaviour, IPointerDownHandler, IPointerUpHandler
{
public GameObject Dust;
Rect ScreenRect;
RenderTexture rt;
Texture2D tex;
public Material EraserMaterial;
private bool firstFrame;
private Vector2? newHolePosition;
private bool _isMakeHole;
private bool _isNeedReset;
private PanelController _panelController;
private void EraseBrush(Vector2 imageSize, Vector2 imageLocalPosition)
{
Rect textureRect = new Rect(0.0f, 0.0f, 1.0f, 1.0f); //this will get erase material texture part
Rect positionRect = new Rect(
(imageLocalPosition.x - 0.5f * EraserMaterial.mainTexture.width) / imageSize.x,
(imageLocalPosition.y - 0.5f * EraserMaterial.mainTexture.height) / imageSize.y,
EraserMaterial.mainTexture.width / imageSize.x,
EraserMaterial.mainTexture.height / imageSize.y
); //This will Generate position of eraser according to mouse position and size of eraser texture
//Draw Graphics Quad using GL library to render in target render texture of camera to generate effect
GL.PushMatrix();
GL.LoadOrtho();
for (int i = 0; i < EraserMaterial.passCount; i++)
{
EraserMaterial.SetPass(i);
GL.Begin(GL.QUADS);
GL.Color(Color.white);
GL.TexCoord2(textureRect.xMin, textureRect.yMax);
GL.Vertex3(positionRect.xMin, positionRect.yMax, 0.0f);
GL.TexCoord2(textureRect.xMax, textureRect.yMax);
GL.Vertex3(positionRect.xMax, positionRect.yMax, 0.0f);
GL.TexCoord2(textureRect.xMax, textureRect.yMin);
GL.Vertex3(positionRect.xMax, positionRect.yMin, 0.0f);
GL.TexCoord2(textureRect.xMin, textureRect.yMin);
GL.Vertex3(positionRect.xMin, positionRect.yMin, 0.0f);
GL.End();
}
GL.PopMatrix();
}
public IEnumerator Start()
{
_panelController = FindObjectOfType<PanelController>();
firstFrame = true;
var recTr = Dust.GetComponent<RectTransform>();
//Get Erase effect boundary area
ScreenRect.x = recTr.position.x - (recTr.sizeDelta.x / 2);
Debug.Log("ScreenRect.x : " + ScreenRect.x);
ScreenRect.y = recTr.position.y - (recTr.sizeDelta.y / 2);
Debug.Log("ScreenRect.y : " + ScreenRect.y);
ScreenRect.width = recTr.sizeDelta.x;
Debug.Log("Dust.GetComponent<RectTransform>().sizeDelta.x : " + recTr.sizeDelta.x);
ScreenRect.height = recTr.sizeDelta.y;
Debug.Log("Dust.GetComponent<RectTransform>().sizeDelta.y : " + recTr.sizeDelta.y);
//Create new render texture for camera target texture
rt = new RenderTexture(Screen.width, Screen.height, 0, RenderTextureFormat.Default);
yield return rt.Create();
Graphics.Blit(tex, rt);
GetComponent<Camera>().targetTexture = rt;
//Set Mask Texture to dust material to Generate Dust erase effect
Dust.GetComponent<Image>().material.SetTexture("_MaskTex", rt);
}
public void ClearMatrix()
{
Debug.Log("CLEAR MATRIX");
firstFrame = true;
GL.Clear(false, true, new Color(0.0f, 0.0f, 0.0f, 0.0f));
}
public void Update()
{
if (Input.GetKeyDown(KeyCode.R))
{
ClearMatrix();
}
newHolePosition = null;
if (_isMakeHole) //Check if MouseDown
{
Vector2 v = Input.mousePosition;
Rect worldRect = ScreenRect;
if (worldRect.Contains(v))
{
//Get MousePosition for eraser
newHolePosition = new Vector2(800f * (v.x - worldRect.xMin) / worldRect.width, 600f * (v.y - worldRect.yMin) / worldRect.height);
}
}
if (Input.GetKeyDown(KeyCode.R))
_isNeedReset = true;
}
public void OnPostRender()
{
//Start It will clear Graphics buffer
if (firstFrame)
{
firstFrame = false;
GL.Clear(false, true, new Color(0.0f, 0.0f, 0.0f, 0.0f));
}
//Generate GL quad according to eraser material texture
if (newHolePosition != null)
{
EraseBrush(new Vector2(800.0f, 600f), newHolePosition.Value);
}
if (_isNeedReset)
{
Debug.Log("Clear");
_isNeedReset = false;
StartCoroutine(Start());
}
}
public void OnPointerDown(PointerEventData eventData)
{
if (_panelController.CurrentGameState != EnumGameStates.NewCard) return;
_isMakeHole = true;
newHolePosition = null;
Vector2 v = eventData.position;//GetComponent<Camera>().ScreenToWorldPoint(Input.mousePosition);
Rect worldRect = ScreenRect;
if (worldRect.Contains(v))
{
//Get MousePosition for eraser
newHolePosition = new Vector2(800f * (v.x - worldRect.xMin) / worldRect.width, 600f * (v.y - worldRect.yMin) / worldRect.height);
}
}
public void OnPointerUp(PointerEventData eventData)
{
if (_panelController.CurrentGameState != EnumGameStates.NewCard) return;
_isMakeHole = false;
}
}