【Unity(C#)】VR카메라를 임의의 포지션으로 이동하는 방법

14453 단어 Unitywarp카메라C#VR

여름 어드벤트 캘린더



Unity 유루 후와 여름 어드벤트 캘린더 2019 #유루 후와 의 테두리가 비었기 때문에
갑자기 대타로 참가했습니다! !

Unity 관련 기사라고 하는 것으로 본 기사는 스레스레입니다만, 느슨한 푹신이므로 세이프 세이프!

VR 사진기



SteamVR과 OculusIntegration에서의 VR 개발로 독특한 카메라의 계층구조에 막혔습니다.





보시다시피 CameraRig라는 게임 객체의 하위 계층에 카메라가 있습니다.

이러한 계층 구조가 된 이유는
VR의 카메라가 HMD를 따라 움직이기 때문입니다. (그 밖에도 이유가 있을지도 모릅니다만)

즉, 직접 카메라를 움직일 수 없으며 상위 계층의 CameraRig를 움직여 이동을 재현합니다.

하위 계층의 카메라는 자유롭게 움직입니다.



그러나 상위 계층의 CameraRig를 움직여 이동을 재현하면 문제가 발생합니다.
이것은 하위 계층의 카메라 위치를 고려하지 않으면 어떤 위치로도 이동할 수 없다는 것입니다.

카메라는 사용자의 이동에 따라 위치가 바뀌므로 특정 위치로 유도가 어려운 경우強制ワープさせた先で壁にめり込んでしまう 와 같은 현상이 일어날 우려가 있습니다.

그림



설명을 알기 쉽게하기 위해 그림을 사용하여 설명합니다.

빨간 점 A의 위치에 플레이어를 워프하고 싶습니다.
밝은 녹색의 테두리는 방, 파란 사각형은 CameraRig, 노란 점은 CameraRig의 중심, 검게 채워진 사각형은 카메라(플레이어)입니다.



카메라 (플레이어)의 위치를 ​​직접 변경할 수 없으므로,
CameraRig의 위치를 ​​빨간색 점 A로 이동하여
카메라(플레이어) 이동을 재현합니다만, 그대로 이동시키면 이렇게 됩니다↓

빨간색 사각형이 이동 후 CameraRig입니다.

보시다시피 카메라가 방에서 튀어 나왔습니다.
카메라의 위치를 ​​고려하여 이동해야 하는 이유는 이상입니다.

데모



던진 큐브의 위치로 플레이어가 이동하는 데모입니다.
조금 이해하기 어렵지만,
큐브를 잡은 상태에서 걷고 카메라의 위치를 ​​초기 위치에서 벗어난 후 던집니다.


큐브와 같은 좌표로 플레이어가 이동하고 있는 것을 알 수 있을까 생각합니다.

코드



이번 데모에 이용한 코드입니다.

적절한 객체에 부착
using UnityEngine;

public class WarpCenterCamera : MonoBehaviour
{
    [SerializeField]
    GameObject ovr_Rig;

    [SerializeField]
    GameObject centerCamera;

    [SerializeField]
    GameObject warpPointCube;

    void Update()
    {
        Vector3 ovr_Rig_Pos = ovr_Rig.transform.position;
        Vector3 centerCamera_Pos = centerCamera.transform.position;

        if (OVRInput.GetDown(OVRInput.RawButton.RIndexTrigger))
        {
            ovr_Rig.transform.position = warpPointCube.transform.position;
            ovr_Rig.transform.position += new Vector3(ovr_Rig_Pos.x - centerCamera_Pos.x, 0, ovr_Rig_Pos.z - centerCamera_Pos.z);
        }
    }
}

아래와 같은 부분에서 카메라의 좌표를 고려한 CameraRig의 좌표의 계산을 실시하고 있습니다.
    ovr_Rig.transform.position += new Vector3(ovr_Rig_Pos.x - centerCamera_Pos.x, 0, ovr_Rig_Pos.z - centerCamera_Pos.z);

특정 방향을 지정하고 다시 이동을 원한다면
    ovr_Rig.transform.Rotate(new Vector3(0, 90, 0));
    ovr_Rig.transform.position = warpPointCube.transform.position;
    ovr_Rig.transform.position += new Vector3(ovr_Rig_Pos.x - centerCamera_Pos.x, 0, ovr_Rig_Pos.z - centerCamera_Pos.z);

와 같이 회전시키고 나서 이동하는 것으로 실장 가능합니다.

실은 좀 더 쉬운 방법이 있을 것 같고 무서운데, 떠올랐기 때문에 메모할 때입니다.

2019/11/14 추가

회전도 실장했으므로 메모합니다.

인수로 대상 객체를 전달하면
플레이어가 그 위치로 이동하고 카메라의 방향도 물체의 정면 방향에 딱 맞습니다.
using UnityEngine;
using UnityEngine.Events;
/// <summary>
/// Recenter your camera when you start VR. Attach to CameraRig.
/// </summary>
public class PlayerPositionChange : Singleton<PlayerPositionChange>
{
    [SerializeField, Tooltip("Set this child camera")]
    GameObject eyeCamera;

    [SerializeField, Tooltip("This event is called after moving")]
    UnityEvent afterMovingEvent;

    public void  WarpTargetPosition(Transform target)
    {
        Vector3 cameraRig_Angles = this.gameObject.transform.eulerAngles;
        Vector3 eyeCamera_Angles = eyeCamera.transform.eulerAngles;

        this.gameObject.transform.eulerAngles = target.eulerAngles;
        this.gameObject.transform.eulerAngles += new Vector3(0, cameraRig_Angles.y - eyeCamera_Angles.y, 0);

        Vector3 cameraRig_StartPos = this.gameObject.transform.position;
        Vector3 eyeCamera_Pos = eyeCamera.transform.position;

        this.gameObject.transform.position = target.transform.position;
        this.gameObject.transform.position += new Vector3(cameraRig_StartPos.x - eyeCamera_Pos.x, 0, cameraRig_StartPos.z - eyeCamera_Pos.z);

        afterMovingEvent.Invoke();
    }
}

2020/08/19 추가

OculusQuest에서 위치 추적이 완료되기 전에
위치 조정 처리가 호출되어 잘 작동하지 않았습니다.

그래서 아래와 같이 UniTask (또는 코루틴)을 사용하여
호출 측에서 위치 추적 완료를 기다리면 잘 작동합니다.
private async void Start()
{ 
    OVRTracker ovrTracker = new OVRTracker();

    //HMDがトラッキングされるまで待つ
    await UniTask.WaitUntil(() =>ovrTracker.isPositionTracked);
    Debug.Log("Tracked");

    WarpTargetPosition(target);
}

좋은 웹페이지 즐겨찾기