IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 游戏开发 -> Unity中使用RenderTexture判断不规则形状按钮的点击 -> 正文阅读

[游戏开发]Unity中使用RenderTexture判断不规则形状按钮的点击

对于判断不规则形状的按钮的点击,一般使用的方式是:

  1. 打开按钮图片的“Read/Write Enabled”选项,并设置图片的Image.alphaHitTestMinimumThreshold来判断alpha低于阈值的区域响应点击;
  2. 使用 PolygonCollider2D 并重写 Image 的 IsRaycastLocationValid 方法来判断;

但是上述方法都有各自的缺点,第一种方法开启 Read/Write 之后会使图片的内存占用翻倍,并且不支持Crunched压缩图片格式,第二种方法需要编辑多边形形状,对于有大量不规则图片按钮的项目来说有点耗时耗力。

为了解决上述问题,研究了另外一种方法来进行点击判断,原理很简单,就是用一个单独的shader将按钮的id(或者序号)通过同一个摄像机渲染到一张RenderTexture上,然后监听点击事件,点击之后根据点击的屏幕坐标从之前渲染的图上读取颜色信息,并转化回按钮的id(或者序号)来判断点中了哪个按钮。

此方法对于按钮位置变化不大,按钮数量又非常多的情况是比较合适的。只有在按钮有变化的情况下需要重新渲染一张位置贴图,其余时间只要监听点击事件并取样判断即可。如果精度要求不高,取样贴图的分辨率可以进一步降低以提高采样效率。对于原按钮图片几乎没有要求,可以关闭 Read/Write Enable,也可以设置任意压缩格式。

示例代码和shader如下:


public class TouchDetectHelp : MonoBehaviour {
	public Texture2D renderTex; // 渲染图,可以在Inspector面板检查
	public float sizeScale = 0.5f;
	
	// 在判断点击之前需要先调用,渲染一张按钮位置贴图
	public void CaptureButton()
	{
		var uiCam = ZGameRuntime.Instance.cameras.ui;
		var shaderToRender = Shader.Find("Custom/TouchDetect");
		RenderTexture rt = RenderTexture.GetTemporary(Mathf.RoundToInt(Screen.width * sizeScale), Mathf.RoundToInt(Screen.height * sizeScale));

		uiCam.targetTexture = rt;
		uiCam.RenderWithShader(shaderToRender, "RenderType");
		uiCam.targetTexture = null;

		Texture2D texture = new Texture2D(rt.width, rt.height, TextureFormat.R8, false);
		RenderTexture.active = rt;
		texture.ReadPixels(new Rect(0, 0, rt.width, rt.height), 0, 0);
		RenderTexture.active = null;
		texture.Apply();

		RenderTexture.ReleaseTemporary(rt);

		if(renderTex)
			Destroy(renderTex);
		renderTex = texture;
	}

	// 根据玩家点击屏幕坐标,获取按钮位置渲染贴图上的像素颜色,反向计算获取对应点击到的按钮id
	public int GetTouchButtonId()
	{
		if (!renderTex)
		{
			CaptureButton();
		}

#if UNITY_EDITOR || UNITY_STANDALONE
		var screenPosX = Input.mousePosition.x;
		var screenPosY = Input.mousePosition.y;
#else
		var touch = Input.GetTouch(0);
		var screenPosX = touch.position.x;
		var screenPosY = touch.position.y;
#endif

		var touchColor = renderTex.GetPixel(Mathf.RoundToInt(screenPosX * sizeScale), Mathf.RoundToInt(screenPosY * sizeScale));
		if (!GameUtils.FloatEqual(touchColor.r, 0))
		{
			return Mathf.RoundToInt(touchColor.r * 255 / 5f - 5);
		}
		
		return -1;
	}

	private int _buttonIndexId;
	private int ButtonIndexIndexId
	{
		get
		{
			if(_buttonIndexId == 0)
			{
				_buttonIndexId = Shader.PropertyToID("_ButtonId");
			}

			return _buttonIndexId;
		}
	}

	// 按钮初始化时在Image的材质球上设置一下按钮id(即使当前shader没有此参数也不要紧)
	private void SetButtonId(Image buttonImg, int buttonId)
	{
		var buttonMat = new Material(Shader.Find("Legacy Shaders/Particles/Alpha Blended"));
		var btnIndex = buttonId + 5;
		buttonMat.SetFloat(ButtonIndexIndexId, btnIndex);
		buttonImg.material = buttonMat;
	}
}
对应的渲染用shader,在build in shader 基础上略做修改:
Shader "Custom/TouchDetect" {
Properties {
    _MainTex ("Particle Texture", 2D) = "white" {}
    _ButtonId("Furnish Id", Range(0, 1)) = 0
}

Category {
    Tags { "Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent" "PreviewType"="Plane" }
    Blend SrcAlpha OneMinusSrcAlpha
    ColorMask RGB
    Cull Off Lighting Off ZWrite Off

    SubShader {
        Pass {

            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #pragma target 2.0

            #include "UnityCG.cginc"

            sampler2D _MainTex;
            float _ButtonId;
            
            struct appdata_t {
                float4 vertex : POSITION;
                fixed4 color : COLOR;
                float2 texcoord : TEXCOORD0;
                UNITY_VERTEX_INPUT_INSTANCE_ID
            };

            struct v2f {
                float4 vertex : SV_POSITION;
                fixed4 color : COLOR;
                float2 texcoord : TEXCOORD0;
                UNITY_VERTEX_OUTPUT_STEREO
            };

            float4 _MainTex_ST;

            v2f vert (appdata_t v)
            {
                v2f o;
                UNITY_SETUP_INSTANCE_ID(v);
                UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o);
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.texcoord = TRANSFORM_TEX(v.texcoord,_MainTex);
                return o;
            }

            UNITY_DECLARE_DEPTH_TEXTURE(_CameraDepthTexture);

            fixed4 frag (v2f i) : SV_Target
            {
                clip(_ButtonId - 0.01);
                fixed4 col = tex2D(_MainTex, i.texcoord);
                clip(col.a - 0.1);
                
                // 这里把记录的id转换为颜色输出,注意id只支持 50 个
                fixed idToColor = _ButtonId * 5 / 255;
                return fixed4(idToColor, 0, 0, 1);
            }
            ENDCG
        }
    }
}
}
  游戏开发 最新文章
6、英飞凌-AURIX-TC3XX: PWM实验之使用 GT
泛型自动装箱
CubeMax添加Rtthread操作系统 组件STM32F10
python多线程编程:如何优雅地关闭线程
数据类型隐式转换导致的阻塞
WebAPi实现多文件上传,并附带参数
from origin ‘null‘ has been blocked by
UE4 蓝图调用C++函数(附带项目工程)
Unity学习笔记(一)结构体的简单理解与应用
【Memory As a Programming Concept in C a
上一篇文章      下一篇文章      查看所有文章
加:2022-03-10 22:58:11  更:2022-03-10 22:58:53 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/27 14:34:05-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码