当前位置: 首页 > news >正文

unity实现点击rawimage,确定对应的世界坐标点

前提:存在多个摄像机和rawimage

代码:

using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using FluffyUnderware.DevTools.Extensions;
using FluffyUnderware.DevToolsEditor;
using ISCAS.Common;
using Unidux.Util;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
using Zenject;public class FollowWindow : MonoBehaviour, IPointerClickHandler
{[Header("对应的跟随摄像机obj")]public GameObject followCameraObj;[Header("ui圆点")]public Image dot;private Camera _followCam;//对应的跟随摄像机private RawImage _rawimage; //对应的rawimagepublic LayerMask hitLayers;  // 可检测的物体层级//测试public Material highMaterial;void Start(){hitLayers = LayerMask.NameToLayer("model");_rawimage = this.GetComponentInChildren<RawImage>();_followCam = followCameraObj.GetComponent<Camera>();}// 实现点击事件接口public void OnPointerClick(PointerEventData eventData){// 获取点击的物体GameObject hitObject = GetObjectAtClick(eventData);if (hitObject != null){Debug.Log($"点击了物体: {hitObject.name}");// 触发自定义事件OnObjectClicked(hitObject);}}/// <summary>/// 获取点击位置对应的3D物体/// </summary>public GameObject GetObjectAtClick(PointerEventData eventData){// 1. 获取RawImage组件if (_rawimage == null || _followCam == null) return null;// 2. 获取点击位置在RawImage上的本地坐标Vector2 localPoint;RectTransformUtility.ScreenPointToLocalPointInRectangle(_rawimage.rectTransform,eventData.position,eventData.pressEventCamera,out localPoint);// 调试日志:本地坐标Debug.Log($"原始本地坐标: {localPoint}");dot.rectTransform.localPosition = localPoint;// 3. 转换为视口坐标Vector2 viewportPoint = ConvertToViewportPoint(localPoint,_rawimage.rectTransform);Debug.Log($"视口坐标: {viewportPoint}");// 4. 发射射线检测物体return RaycastFromViewport(viewportPoint);}/// <summary>/// 将RawImage本地坐标转换为视口坐标(0-1),就是获得localPoint相对于整个rawimage的比例/// </summary>private Vector2 ConvertToViewportPoint(Vector2 localPoint, RectTransform rectTransform){//获取rawimage的长宽float imageWidth = rectTransform.rect.width;float imageHeight = rectTransform.rect.height;//获取rawimage的左下角点,适用于所有的pivot情况float localPositionX = rectTransform.localPosition.x - (rectTransform.rect.width * rectTransform.pivot.x);float localPositionY = rectTransform.localPosition.y - (rectTransform.rect.height * rectTransform.pivot.y);//获取在预览映射相机viewport内的坐标(坐标比例);float p_x = (localPoint.x - localPositionX) / imageWidth;float p_y = (localPoint.y - localPositionY) / imageHeight;return new Vector2(p_x, p_y);}/// <summary>/// 从视口坐标发射射线检测物体/// </summary>private GameObject RaycastFromViewport(Vector2 viewportPoint){// 创建射线(根据视口坐标创建射线)Ray ray = _followCam.ViewportPointToRay(viewportPoint);// 可视化射线(在场景视图中查看)ray.origin是射线起点,ray.direction是射线方向Debug.DrawRay(ray.origin, ray.direction * 100000, Color.red, 2);// 执行射线检测RaycastHit hit;if (Physics.Raycast(ray, out hit, Mathf.Infinity, hitLayers)){return hit.collider.gameObject;}return null;}/// <summary>/// 物体点击事件处理/// </summary>private void OnObjectClicked(GameObject clickedObject){// 示例:高亮被点击的物体HighlightObject(clickedObject);// 示例:在目标窗口显示选中物体// DisplaySelectedTarget(clickedObject);}// 高亮物体方法private async void HighlightObject(GameObject obj){// 实现高亮逻辑if (highMaterial == null)return;// 获取渲染器MeshRenderer renderer = obj.GetComponent<MeshRenderer>();if (renderer == null) return;// 保存原始材质Material[] originalMaterials = renderer.materials;// 创建新材质列表(添加高亮材质)List<Material> newMaterials = new List<Material>(originalMaterials);newMaterials.Add(highMaterial);// 应用新材质renderer.materials = newMaterials.ToArray();try{// 使用Unity协程替代Task.Delay(确保在主线程)await Task.Delay(2000).ConfigureAwait(true); // 确保在主线程继续// 恢复原始材质renderer.materials = originalMaterials;}catch (Exception ex){Debug.LogError($"高亮恢复失败: {ex.Message}");// 确保恢复材质if (renderer != null)renderer.materials = originalMaterials;}}
}

整体流程:根据屏幕上的鼠标坐标->得到rawimage上的局部坐标(直接使用api:RectTransformUtility.ScreenPointToLocalPointInRectangle)->得到摄像机的视口坐标(就是比例换算,得到0-1的比例)->摄像机发射射线,碰撞到指定层级的物体

http://www.dtcms.com/a/343115.html

相关文章:

  • 记录前端菜鸟的日常——小程序内嵌H5页面自定义分享按钮
  • 环形子数组的最大和
  • Ubuntu24.04 交叉编译libuv库(已编译好的) 之undefined reference to `pthread_getname_np‘解决
  • VMware Workstation里的Ubuntu22.04找不到共享文件夹
  • Ubuntu Server 安装 gvm 管理 Go 语言开发环境
  • 代码随想录Day58:图论(拓扑排序精讲、最短路算法dijkstra朴素版精讲)
  • Android焦点窗口变化导致遥控键值监听失效问题分析
  • AI编程避坑指南:常见错误与解决策略
  • 年化42%,最大回撤18%,卡玛比率2.3的策略可查看参数 | 全A股市场构建技术方案
  • 数据库审计是什么?主要功能详解与厂商解析
  • 第7章 区分鸟和飞机:从图像学习
  • 【网络运维】初见Shell:Shell 变量基础知识
  • Vue图解!!!Vue的生命周期管理【7】
  • MFC中使用libtorch的实例
  • 【一分钟教程】用ZMC600E实现关节机器人±180度精准转动
  • Ubuntu网络图标消失/以太网卡显示“未托管“
  • 人工智能之数学基础:随机变量和普通变量的区别?
  • 什么是测度?
  • 实践题:智能客服机器人设计
  • 魔乐开发者教程 | 基于openMind实现大模型微调指南(二):大模型微调实操
  • 图像边缘检测
  • Spring AI 入门学习指南
  • 2025.8.21总结
  • CMake使用【c/c++】
  • 2025Java面试红皮书:1000道BAT真题详解
  • plc与plc无线通讯实现PLC1200和ET200SP无线通讯解决方案实践
  • uniapp 懒加载图片
  • 力扣面试150(62/150)
  • SAP FIORI Elements深度定制:注解扩展与审批流程增强完全指南
  • 软件工程 + AI 不是 “硬凑”,3 步走通落地关键环节