Unity中解锁图片像素点,动态闭合轨迹检测

news/2025/3/19 0:52:32/

Unity中解锁图片像素点,动态闭合轨迹检测

  • 介绍
  • 资源下载
  • 搭建
  • 总结

介绍

因为最近在研究Mane天蚕变的游戏完整逻辑,研究了两套方案做解锁图片的功能,这里我先讲一下我的这个图片像素点的方案解锁图片,这个逻辑其实很简单就是利用划线检测是否轨迹点闭合,然后闭合的点在映射到图片的像素中即可,当然这里需要制作一个shader就是主图层和遮罩层,因为遮罩层的图是动态生成的,所以这块你的像素越大则性能消耗越多也就会卡顿,所以根据实际情况去考量项目需求。

资源下载

项目资源

请添加图片描述

搭建

Canvas模式
在这里插入图片描述
相机模式
在这里插入图片描述
ImageMask为空物体
LineRenderer为对应组件的物体
GameObject为挂载我自定义脚本的对象
RawImage是我需要挂载Shader材质球的对象,同时也需要将图放上去
在这里插入图片描述
在这里插入图片描述
代码
UnlockImageWithShader运行脚本

using UnityEngine;
using UnityEngine.UI;public class UnlockImageWithShader : MonoBehaviour
{public RawImage imageToUnlock; // 需要解锁的图片(使用RawImage)public LineRenderer lineRenderer; // 用于绘制曲线的LineRendererpublic Shader unlockShader; // 自定义Shaderprivate Texture2D maskTexture; // 遮罩纹理private Material unlockMaterial; // 使用Shader的材质void Start(){// 初始化遮罩纹理maskTexture = new Texture2D(256, 256); // 根据需要设置分辨率maskTexture.filterMode = FilterMode.Point;maskTexture.wrapMode = TextureWrapMode.Clamp;ClearMaskTexture(); // 初始化为全黑unlockMaterial = new Material(unlockShader);unlockMaterial.SetTexture("_MainTex", imageToUnlock.texture); // 设置主纹理unlockMaterial.SetTexture("_MaskTex", maskTexture); // 设置遮罩纹理imageToUnlock.material = unlockMaterial; // 应用材质到RawImage// 初始化LineRendererlineRenderer.startWidth = 0.05f;lineRenderer.endWidth = 0.05f;lineRenderer.material = new Material(Shader.Find("Sprites/Default"));lineRenderer.positionCount = 0;}void Update(){if (Input.GetMouseButton(0)){// 将鼠标屏幕坐标转换为UV坐标TVector mousePos = GetMouseUVPosition();points = AddPointUV(mousePos.m_uv);linePoints = AddPointWP(mousePos.m_worldPos);lineRenderer.positionCount = points.Length;lineRenderer.SetPositions(System.Array.ConvertAll(linePoints, v => v));}if (Input.GetMouseButtonUp(0)){if (IsClosedCurve(points)){UnlockArea(points);}points = new Vector2[0]; // 清空点数组linePoints = new Vector3[0];lineRenderer.positionCount = 0; // 清空LineRenderer}}private Vector2[] points = new Vector2[0]; // 存储玩家绘制的点private Vector3[] linePoints = new Vector3[0]; // 存储玩家绘制的点Vector2[] AddPointUV(Vector2 point){Vector2[] newPoints = new Vector2[points.Length + 1];points.CopyTo(newPoints, 0);newPoints[points.Length] = point;return newPoints;}Vector3[] AddPointWP(Vector3 point){Vector3[] newPoints = new Vector3[points.Length + 1];linePoints.CopyTo(newPoints, 0);newPoints[points.Length] = point;return newPoints;}bool IsClosedCurve(Vector2[] points){if (points.Length < 3) return false; // 至少需要3个点才能形成闭合曲线float distance = Vector2.Distance(points[0], points[points.Length - 1]);return distance < 0.05f; // 判断起点和终点是否接近(阈值)}void UnlockArea(Vector2[] points){// 将多边形区域填充为白色for (int y = 0; y < maskTexture.height; y++){for (int x = 0; x < maskTexture.width; x++){Vector2 pixelUV = new Vector2((float)x / maskTexture.width, (float)y / maskTexture.height);if (IsPointInPolygon(pixelUV, points)){Color c = new Color(Color.white.r, Color.white.g, Color.white.b, 1);maskTexture.SetPixel(x, y, c); // 设置为白色(解锁)}}}maskTexture.Apply(); // 应用纹理更改byte[] b = maskTexture.EncodeToPNG();System.IO.File.WriteAllBytes(Application.dataPath + "/t1.png", b);Debug.LogError("Mask texture updated."); // 调试日志}bool IsPointInPolygon(Vector2 point, Vector2[] polygon){int intersections = 0;for (int i = 0; i < polygon.Length; i++){Vector2 p1 = polygon[i];Vector2 p2 = polygon[(i + 1) % polygon.Length];if (point.y > Mathf.Min(p1.y, p2.y)){if (point.y <= Mathf.Max(p1.y, p2.y)){if (point.x <= Mathf.Max(p1.x, p2.x)){float xIntersection = (point.y - p1.y) * (p2.x - p1.x) / (p2.y - p1.y) + p1.x;if (p1.x == p2.x || point.x <= xIntersection){intersections++;}}}}}return intersections % 2 != 0; // 奇数交点表示点在多边形内}public class TVector {public Vector2 m_uv;public Vector3 m_worldPos;public TVector(Vector2 uv,Vector3 wp){m_uv = uv;m_worldPos = wp;}}TVector GetMouseUVPosition(){// 将鼠标屏幕坐标转换为UV坐标Vector2 mousePos = Input.mousePosition;// 确保传入的摄像机参数正确bool success = RectTransformUtility.ScreenPointToLocalPointInRectangle(imageToUnlock.rectTransform, mousePos, Camera.main, out Vector2 localPoint);RectTransformUtility.ScreenPointToWorldPointInRectangle(imageToUnlock.rectTransform, mousePos, Camera.main, out Vector3 worldPos);// 将局部坐标转换为 UV 坐标Vector2 uv = Rect.PointToNormalized(imageToUnlock.rectTransform.rect, localPoint);return new  TVector (uv, worldPos);}void ClearMaskTexture(){// 将遮罩纹理初始化为全黑Color[] colors = new Color[maskTexture.width * maskTexture.height];for (int i = 0; i < colors.Length; i++){colors[i] = new Color(Color.black.r, Color.black.g, Color.black.b, 0);}maskTexture.SetPixels(colors);maskTexture.Apply();}
}

UnlockImageShader.Shader

Shader "Custom/UnlockImageShader"
{Properties{_MainTex ("Main Texture", 2D) = "white" {} // 主纹理_MaskTex ("Mask Texture", 2D) = "white" {} // 遮罩纹理}SubShader{Tags { "Queue"="Transparent" "RenderType"="Transparent" }LOD 200Pass{CGPROGRAM#pragma vertex vert#pragma fragment frag#include "UnityCG.cginc"struct appdata{float4 vertex : POSITION;float2 uv : TEXCOORD0;};struct v2f{float2 uv : TEXCOORD0;float4 vertex : SV_POSITION;};sampler2D _MainTex;sampler2D _MaskTex;v2f vert (appdata v){v2f o;o.vertex = UnityObjectToClipPos(v.vertex);o.uv = v.uv;return o;}fixed4 frag (v2f i) : SV_Target{fixed4 mainColor = tex2D(_MainTex, i.uv); // 主纹理颜色fixed4 maskColor = tex2D(_MaskTex, i.uv); // 遮罩纹理颜色// 如果遮罩纹理的 alpha 值大于 0.5,显示主纹理,否则显示黑色return maskColor.a > 0.5 ? mainColor : fixed4(0, 0, 0, 1);}ENDCG}}
}

总结

需要的同学们可以去我上面资源下载的位置去下载。
感谢大家的支持!


http://www.ppmy.cn/news/1580197.html

相关文章

RabbitMQ五种消息模型

RabbitMQ 是一款基于 AMQP 协议的高性能消息中间件&#xff0c;广泛应用于分布式系统中&#xff0c;用于实现服务之间的异步通信、解耦和负载均衡。RabbitMQ 提供了五种常见的消息模型&#xff0c;每种模型都有其独特的特点和适用场景。本文将详细介绍这五种消息模型&#xff0…

汉桑科技IPO:潜藏两大风险 公众投资者权益或受损

冰山之所以危险&#xff0c;是因为只有八分之一在水面上。 ——语出小说家海明威。 引 言 野村证券提供的一份报告显示&#xff0c;2025年前两个月&#xff0c;我国出口同比增长仅有2.3%&#xff0c;与去年四季度9.9%的增长显著下滑。与此同时&#xff0c;从2月1日开始&a…

基于金融产品深度学习推荐算法详解【附源码】

深度学习算法说明 1、简介 神经网络协同过滤模型(NCF) 为了解决启发式推荐算法的问题&#xff0c;基于神经网络的协同过滤算法诞生了&#xff0c;神经网络的协同过滤算法可以 通过将用户和物品的特征向量作为输入&#xff0c;来预测用户对新物品的评分&#xff0c;从而解决…

给文件提添加高亮信息

给文件提添加高亮信息 因为在查看log的时候需要人工校验标签&#xff0c;因此萌生了用插件高亮标签方便查看的想法。 效果展示&#xff1a; 设备&#xff1a;VScode 设置步骤 下载Highlight插件 点击管理→设置→在setting.json中编辑 添加以下内容 "(<…

Android手机中各类安全相关知识总结

更多内容请见: 爬虫和逆向教程-专栏介绍和目录 文章目录 1. Android 安全威胁2. Android 安全防护措施3. Android 安全建议和最佳实践4. Android 安全工具推荐5. Android 安全常见问题5.1 如何检测设备是否感染恶意软件?5.2 如何防止应用滥用权限?5.3 如何保护设备免受网络攻…

在 Qt 中自定义控件样式:使用 QProxyStyle 代理和修改绘制元素

文章目录 在 Qt 中自定义控件样式&#xff1a;使用 QProxyStyle 代理和修改绘制元素1. 什么是 QProxyStyle&#xff1f;QStyle 和 QProxyStyle何时使用 QProxyStyle&#xff1f;关键方法&#xff1a;drawPrimitive() 2. drawPrimitive() 方法详解参数解析1. PrimitiveElement e…

单元测试、系统测试、集成测试、回归测试的步骤、优点、缺点、注意点梳理说明

单元测试、系统测试、集成测试、回归测试的梳理说明 单元测试 步骤&#xff1a; 编写测试用例&#xff0c;覆盖代码的各个分支和边界条件。使用测试框架&#xff08;如JUnit、NUnit&#xff09;执行测试。检查测试结果&#xff0c;确保代码按预期运行。修复发现的缺陷并重新测…

【解决】XCode不支持旧版本的iOS设备

办法&#xff1a; 手动添加设备支持文件&#xff08;暂时解决方式&#xff09; 如果您无法立即升级 Xcode&#xff0c;也可以通过下载设备支持文件来暂时解决问题。 检查当前设备的 iOS 版本&#xff1a; 连接设备到 Mac&#xff0c;打开 Xcode 查看提示的 iOS 版本。例如&…