Я столкнулся с проблемой с RenderTexture, который отображает точку зрения других игроков на панели в моем многопользовательском проекте Unity VR. Функция реализована таким образом, что при касании панели правой рукой в виртуальное пространство, соответствующее месту касания, попадает луч. Однако направление луча отклоняется от положения касания, из-за чего он не работает должным образом.
Окружающая среда:
Устройство: Meta Quest 3
Нет отслеживания рук, используется контроллер
Рука отображается в виртуальной среде
Цель:
Я хочу точно поражать цели в виртуальном пространстве с помощью отбрасывание лучей, соответствующих положению касания объекта панели с помощью RenderTexture.
Сведения о проблеме:
Положение касания на панели нормализуется (внизу слева — (0,0), вверху справа — (1,1)), а луч создается с помощью камеры, показывающей RenderTexture, но особенно, когда камера и панель находятся под углом 180 градусов (около 1:19 в видео), положение касания и луч не совпадают симметрично. В целях отладки в месте касания создается красный куб, а также подтверждается, что положение куба отключено.
Справочное видео
Соответствующий код:
using UnityEngine;
using Photon.Pun;
public class PanelManager : MonoBehaviourPun
{
public Camera displayRenderCamera; // Camera rendering the image to the RenderTexture
private GameObject displayGameObject; // GameObject displaying the RenderTexture
private bool collisionStatus = false;
private Vector3 colliderPoint = Vector3.zero;
void Start()
{
InitializeCameraAndPanel();
}
void Update()
{
bool gripHeld = OVRInput.Get(OVRInput.Button.PrimaryHandTrigger, OVRInput.Controller.RTouch);
bool triggerNotPressed = !OVRInput.Get(OVRInput.Button.PrimaryIndexTrigger, OVRInput.Controller.RTouch);
if (gripHeld && triggerNotPressed && collisionStatus)
{
InteractWithRenderTexture();
}
InitializeCameraAndPanel();
}
private void InitializeCameraAndPanel()
{
PhotonView[] allPhotonViews = FindObjectsOfType
();
foreach (PhotonView view in allPhotonViews)
{
if (view.Owner != null)
{
if (view.Owner.ActorNumber != PhotonNetwork.LocalPlayer.ActorNumber)
{
// Find the other player's camera
GameObject camera = view.gameObject.transform.Find("Head/ViewCamera")?.gameObject;
if (camera != null)
{
displayRenderCamera = camera.GetComponent();
Debug.Log(displayRenderCamera);
}
}
else if (view.Owner.ActorNumber == PhotonNetwork.LocalPlayer.ActorNumber)
{
GameObject panel = view.gameObject.transform.Find("Panel/Panel")?.gameObject;
if (panel != null)
{
displayGameObject = panel;
}
else
{
Debug.LogWarning("Panel/Panel not found on my object");
}
}
}
}
}
private void InteractWithRenderTexture() // Main logic
{
Vector3 localHitPoint = getLocalHitPoint();
// var displayGameObjectSize = displayGameObject.GetComponent().bounds.size;
Vector3 displayGameObjectSize = new Vector3(0.55f, 0.38f, 0.001f);
// Calculate the viewport
var viewportPoint = new Vector3()
{
x = (localHitPoint.x / displayGameObjectSize.x) + 0.5f, // Center at 0.5
y = (localHitPoint.y / displayGameObjectSize.y) + 0.5f, // Center at 0.5
}; // Range: 0-1
float angleBetween = Vector3.Angle(displayRenderCamera.transform.forward, displayGameObject.transform.forward);
// Adjust x coordinate based on the angle
viewportPoint.x = AdjustedCoordinate(angleBetween, viewportPoint.x);
// Generate a ray from the camera based on the viewport
Ray ray = displayRenderCamera.ViewportPointToRay(viewportPoint);
RaycastHit hit;
// Get the coordinates of the hit point (for debugging)
// Vector3 point = ray.GetPoint(2.0f);
// GameObject Cube = GameObject.CreatePrimitive(PrimitiveType.Cube);
// Cube.transform.position = point;
// Cube.transform.localScale = new Vector3(0.1f, 0.1f, 0.1f);
// Cube.GetComponent().material.color = Color.red;
// Destroy(Cube, 0.1f);
if (Physics.Raycast(ray, out hit, 10.0f))
{
// Activate the particle system of the detected object
var cubeManager = hit.transform.GetComponent();
if (cubeManager != null)
{
cubeManager.StartParticleSystem();
}
}
}
private Vector3 getLocalHitPoint() // Get the local coordinates of the touched point on the panel
{
Vector3 localHitPoint = colliderPoint;
if (localHitPoint != Vector3.zero)
{
return localHitPoint - displayGameObject.transform.position;
}
return Vector3.zero;
}
public static float AdjustedCoordinate(float theta, float x)
{
if (theta == 180.0f) return 1.0f - x;
if (theta == 0.0f) return x;
float adjustmentFactor = Mathf.Cos(theta * Mathf.Deg2Rad);
float adjustedX = (1 - adjustmentFactor) * (1 - x) + adjustmentFactor * x;
return adjustedX;
}
void OnTriggerEnter(Collider other)
{
if (other.gameObject.tag == "rightHand")
{
collisionStatus = true;
colliderPoint = other.ClosestPointOnBounds(transform.position);
}
}
void OnTriggerExit(Collider other)
{
if (other.gameObject.tag == "rightHand")
{
collisionStatus = false;
colliderPoint = Vector3.zero;
}
}
}
Что я пробовал:
Я рассмотрел метод расчета положения касания в местной системе координат, но отклонение сохраняется.
Будем признательны за любые советы о причине и решении этой проблемы. Если с этой реализацией возникла проблема, как ее следует исправить?
Дополнительные примечания:
Я пытался отредактировать ее следующим образом, но проблема не решена.
private Vector3 getLocalHitPoint()
{
Vector3 localHitPoint = displayGameObject.transform.InverseTransformPoint(colliderPoint);
return localHitPoint;
}
Подробнее здесь: https://stackoverflow.com/questions/784 ... ion-in-uni
Проблема с точностью рейкастинга в RenderTexture на основе положения касания в Unity VR ⇐ C#
-
- Похожие темы
- Ответы
- Просмотры
- Последнее сообщение