Unity+Meta Quest中RenderTexture触摸射线投射坐标偏移修正
问题修复方案
针对你遇到的触摸无响应和射线坐标偏移问题,以下是修正后的代码及关键修改说明:
修正后的完整代码
using UnityEngine; using Photon.Pun; using UnityEngine.UI; public class PanelManager : MonoBehaviourPun { [Header("References")] public Camera displayRenderCamera; // 渲染到RenderTexture的相机 private RawImage displayRawImage; // 显示RenderTexture的RawImage private Vector2? panelTouchPos = null; // 面板上的触摸位置(UV坐标) // 初始化只执行一次,避免反复查找引用 void Awake() { // 直接获取自身挂载的RawImage(假设脚本挂在面板RawImage所在物体上) displayRawImage = GetComponent<RawImage>(); if (displayRawImage == null) { Debug.LogError("当前物体未挂载RawImage组件"); } } void Update() { // 检测右手控制器的触摸交互(改用射线检测面板,替代Trigger) CheckHandPanelInteraction(); // 当握持Grip且有触摸点时执行射线投射 bool gripHeld = OVRInput.Get(OVRInput.Button.PrimaryHandTrigger, OVRInput.Controller.RTouch); if (gripHeld && panelTouchPos.HasValue && displayRenderCamera != null) { CastRayFromRenderCamera(); } } // 查找其他玩家的渲染相机(仅在需要时调用,比如玩家加入时) public void FindOtherPlayerRenderCamera() { PhotonView[] allPhotonViews = FindObjectsOfType<PhotonView>(); foreach (PhotonView view in allPhotonViews) { if (view.Owner != null && view.Owner.ActorNumber != PhotonNetwork.LocalPlayer.ActorNumber) { GameObject cameraObj = view.gameObject.transform.Find("Head/ViewCamera")?.gameObject; if (cameraObj != null) { displayRenderCamera = cameraObj.GetComponent<Camera>(); Debug.Log("找到其他玩家相机: " + displayRenderCamera.name); break; // 只取第一个其他玩家,若有多玩家需调整逻辑 } } } } // 检测右手与面板的交互,获取精确触摸位置 private void CheckHandPanelInteraction() { // 获取右手控制器的世界空间射线 Vector3 controllerPos = OVRInput.GetLocalControllerPosition(OVRInput.Controller.RTouch); Quaternion controllerRot = OVRInput.GetLocalControllerRotation(OVRInput.Controller.RTouch); Ray handRay = new Ray(controllerPos, controllerRot * Vector3.forward); // 检测射线是否命中面板的RectTransform if (RectTransformUtility.RaycastWorldPointInRectangle(displayRawImage.rectTransform, handRay.origin, Camera.main, out var result)) { // 记录面板上的局部触摸位置 panelTouchPos = result.localPosition; } else { panelTouchPos = null; } } // 从其他玩家相机投射射线 private void CastRayFromRenderCamera() { Rect rect = displayRawImage.rectTransform.rect; // 将局部触摸位置转换为0-1范围的Viewport坐标 Vector2 viewportPos = new Vector2( (panelTouchPos.Value.x + rect.width / 2) / rect.width, (panelTouchPos.Value.y + rect.height / 2) / rect.height ); // 翻转Y轴:RawImage的Y轴顶部为0,Unity Viewport的Y轴底部为0 viewportPos.y = 1 - viewportPos.y; Ray ray = displayRenderCamera.ViewportPointToRay(viewportPos); // 调试:生成红色立方体 Vector3 debugPoint = ray.GetPoint(2.0f); GameObject cube = GameObject.CreatePrimitive(PrimitiveType.Cube); cube.transform.position = debugPoint; cube.transform.localScale = new Vector3(0.1f, 0.1f, 0.1f); cube.GetComponent<Renderer>().material.color = Color.red; Destroy(cube, 0.1f); // 射线检测触发粒子系统 if (Physics.Raycast(ray, out RaycastHit hit, 10.0f)) { if (hit.transform.TryGetComponent<CubeManager>(out CubeManager cubeManager)) { cubeManager.StartParticleSystem(); } } } // 玩家加入房间后延迟查找相机,确保玩家物体加载完成 public override void OnJoinedRoom() { base.OnJoinedRoom(); Invoke(nameof(FindOtherPlayerRenderCamera), 1f); } }
关键修改说明
1. 修复触摸无响应问题
- 移除不稳定的
OnTriggerEnter/Exit检测,改用控制器射线精确命中面板的方式,适配VR交互逻辑,避免触发范围不准确的问题。 - 将相机和面板的初始化逻辑从
Update中移除,改为在玩家加入房间后延迟执行,避免反复查找组件导致引用被覆盖,同时确保玩家物体加载完成。 - 直接获取脚本所在物体的
RawImage组件,减少不必要的层级查找。
2. 修正射线坐标偏移问题
- 使用
RectTransformUtility.RaycastWorldPointInRectangle获取面板上的精确触摸位置,替代之前用手部包围盒中心估算的方式,位置精度大幅提升。 - 正确转换坐标空间:将RawImage的局部触摸位置转换为相机Viewport坐标时,处理了Y轴方向翻转(RawImage与Unity Viewport的Y轴原点方向相反),彻底解决偏移问题。
- 简化了UV坐标计算逻辑,避免复杂的UVRect转换错误。
3. 其他优化
- 添加
Header属性,方便在Inspector面板管理组件引用。 - 增加错误日志输出,便于排查组件缺失问题。
- 限制只查找第一个其他玩家的相机,若支持多玩家可修改
FindOtherPlayerRenderCamera逻辑。
内容的提问来源于stack exchange,提问作者Yumekawa-chan
相关产品推荐
相关产品推荐

