일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
- meta
- 연습
- 가상현실
- VR
- 팀 프로젝트
- 오큘러스
- Oculus
- 포트폴리오
- 길건너 친구들
- CGV
- HAPTIC
- 드래곤 플라이트
- 개발
- 드래곤 플라이트 모작
- 멀티플레이
- 개발일지
- meta xr
- 오브젝트 풀링
- 팀프로젝트
- 유니티 UI
- ChatGPT
- 유니티 GUI
- 유니티 Json 데이터 연동
- input system
- XR
- 유니티
- Photon Fusion
- 모작
- 앱 배포
- OVR
- Today
- Total
EasyCastleUNITY
CGV 개발일지8 (VR 플레이어 손, 머리 위치 동기화) 본문
전에 개발일지6 번에서는 Photon Fusion을 사용하여 멀티플레이를 구현해보고자 했었습니다.
하지만, Fusion을 사용하면, VR 플레이어를 동기화 하는 구조가 너무나도 복잡해졌습니다.
그래서, 방향을 선회하여, Fusion이 아닌 Photon Pun2를 사용하여 멀티플레이를 구현하고자 합니다.
먼저 Photon Pun2를 프로젝트에 세팅해주겠습니다.
https://assetstore.unity.com/packages/tools/network/pun-2-free-119922
Photon Pun2는 Asset Store에 올라가 있습니다. 그래서 간단하게 다운로드를 마쳤습니다.
그 다음에 사용한 앱을 만들어 보겠습니다.
포톤 홈페이지에서 관리하면으로 넘어간 다음 새로운 앱 만들기를 클릭합니다.
그 다음 위 사진과 같이 입력하고 앱을 생성해주었습니다.
그러면 Pun2를 설치한 프로젝트로 들어갑니다.
프로젝트에서 위 사진의 경로대로 가서 PUN Wizzard를 엽니다.
위 사진에서 Setup Project를 누르고 나오는 창에 만든 앱의 앱 id를 입력합니다.
연결이 되면 위의 사진 같은 창이 나옵니다.
이렇게 기본적인 멀티 세팅은 끝납니다.
https://doc.photonengine.com/fusion/v1/technical-samples/fusion-vr-host
비록 Pun2를 통해 개발을 할 예정이지만, 기본적인 가상현실 플레이어의 구조는 위 사진을 참고하여 만들생각입니다.
그러므로 필요한 스크립트는 실제로 VR 플레이어가 움직이는 정보를 가지고 있을,
HardwareRig, HardwareHead, HardwareHand
해당 정보를 받아, Network 상에서 움직이게 하는
NetworkRig, NetworkHead, NetworkHand
를 만들어 움직임을 동기화하도록 해보겠습니다.
중요한 점은 Hardware가 움직이는 것을 Network가 따라가는 것이 중요합니다.
Hardware 스크립트들은 OVR SDK에 있는 OVRCameraRig의 assign하여 사용합니다.
하드웨어 구조
HardwareRig -> OVRCameraRig
HardwareHand -> OVRCameraRig의 TrackingSpace의 LeftHandAnchor와 RightHandAnchor에 부착
HardwareHead -> OVRCameraRig의 TrackingSpace의 CenterEyeAnchor에 부착
네트워크 리그 구조
Network는 방에 들어오면 만들어야 하기에, Prefab으로 NetworkRig를 만들었습니다.
NetworkRig의 자식으로 HeadSet, LeftHand, RightHand를 가지고 있습니다.
NetworkRig는 NetworkRig 컴포넌트를 가지고 있습니다.
Headset은 NetworkHead 컴포넌트를 가지고 있습니다.
LeftHand, RightHand는 각각 NetworkHand를 가지고 있습니다.
그리고 각각의 Visuals의 실제로 이동할 모델들을 넣어주었습니다.
아직 프로토타입이기에 머리는 유니티에서 기본적으로 제공하는 Cube를 그리고 양 손은 OVR SDK에 포함되어 있는 CustomHandLeft와 CustomHandRight를 사용하였습니다.
이렇게 기본적인 네트워크 구조 설계를 마쳤습니다. 이제 컴포넌트 안쪽을 작성해보겠습니다.
HardwareRig
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class HardwareRig : MonoBehaviour
{
public HardwareHead headset;
public HardwareHand leftHand;
public HardwareHand rightHand;
public NetworkRig networkRig;
private void Update()
{
if (this.networkRig != null)
{
this.NetworkTransformTracking();
}
}
private void NetworkTransformTracking()
{
this.networkRig.TrasformSet(this.transform);
this.networkRig.networkHeadset.SetLocalPosition(this.headset.transform.localPosition);
this.networkRig.networkLeftHand.SetLocalPosition(this.leftHand.transform.localPosition);
this.networkRig.networkRightHand.SetLocalPosition(this.rightHand.transform.localPosition);
this.networkRig.networkHeadset.SetLocalRotation(this.headset.transform.localRotation);
this.networkRig.networkLeftHand.SetLocalRotation(this.leftHand.transform.localRotation);
this.networkRig.networkRightHand.SetLocalRotation(this.rightHand.transform.localRotation);
}
public void TransformSet(Transform trans)
{
this.transform.position = trans.position;
this.transform.rotation = trans.rotation;
}
}
HardwareRig는 하드웨어들의 정보를 전부 관리해야 되기에, HardwareHead와 각 손의 HardwareHand를 가지고 있습니다.
NetworkTransformTracking 함수를 통해 각 부위의 정보를 networkRig의 헤드셋과 양손으로 전달하여 Hardware들을 따라가게 합니다.
HardwareHead
HardwareHand
using Oculus.Interaction;
using Oculus.Interaction.HandGrab;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class HardwareHand : MonoBehaviour
{
public OVRInput.Controller controller;
public HandGrabInteractor handGrabInteractor;
private void Start()
{
if(this.controller == OVRInput.Controller.RTouch)
{
Debug.Log("오른손 잡음");
this.handGrabInteractor.WhenInteractableSelected.Action += interactable =>
{
var grabbable = interactable.transform.GetComponentInParent<Grabbable>();
Debug.LogFormat("Right interactable name : {0}",grabbable.gameObject.tag);
};
}
if(this.controller == OVRInput.Controller.LTouch)
{
Debug.Log("왼손 잡음");
this.handGrabInteractor.WhenInteractableSelected.Action += interactable =>
{
var grabbable = interactable.transform.GetComponentInParent<Grabbable>();
Debug.LogFormat("Left interactable name : {0}",grabbable.gameObject.tag);
};
}
}
}
어느 손인지 구분하기 위해 OVRInput.Controller의 controller를 가지고 있습니다.
그리고 각 손의 HandGrabInteractor와 연결하여 어느 손이 어떤 물체를 잡았는지에 대해, 정보를 가져옵니다.
위 사진처럼 인스펙터에서 어느 손인지 지정해줄 수 있습니다.
NetworkRig
using Photon.Pun;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class NetworkRig : MonoBehaviour
{
public NetworkHead networkHeadset;
public NetworkHand networkLeftHand;
public NetworkHand networkRightHand;
public HardwareRig hardwareRig;
public PhotonView pv;
private void Awake()
{
this.pv = this.GetComponent<PhotonView>();
if (this.pv.IsMine)
{
this.hardwareRig = GameObject.FindAnyObjectByType<HardwareRig>();
this.hardwareRig.networkRig = this;
}
}
public void TrasformSet(Transform trans)
{
this.transform.position = trans.position;
this.transform.rotation = trans.rotation;
}
}
네트워크 리그는 Network들을 관리하여야 하기에 NetworkHead와 각 손의 NetworkHand 그리고 HardwareRig와 동기화하여야 하기에 hardwareRig의 정보를 가지고 있습니다.
네트워크 객체는 생성되고, 네트워크 동기화를 하기 위해, PhotonView를 가지고 있습니다.
객체가 생성될 때, Awake를 통해 PhotonView와 hardwareRig를 찾습니다.
NetworkHead
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class NetworkHead : MonoBehaviour
{
public void SetLocalPosition(Vector3 pos)
{
this.transform.localPosition = pos;
}
public void SetLocalRotation(Quaternion rot)
{
this.transform.localRotation = rot;
}
}
중요한 점은 local이라는 점입니다. 각각의 OvrCameraRig의 각 Anchor의 local값을 받아 위치를 동기화 합니다.
NetworkHand
using Photon.Pun;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class NetworkHand : MonoBehaviour
{
public enum eHandSide
{
Left,Right
}
public eHandSide handSide;
public void SetLocalPosition(Vector3 pos)
{
this.transform.localPosition = pos;
}
public void SetLocalRotation(Quaternion rot)
{
this.transform.localRotation = rot;
}
}
enum을 사용하여 무슨 쪽인지를 지정해줍니다.
Photon Transform View 부착
Photon Transform View이 컴포넌트를 붙여두면 알아서 위치 값을 네트워크 상에서 동기화 해줍니다.
NetworkRig 프리팹의 NetworkRig, Headset, LeftHand, RightHand에 부착합니다.
이렇게 작성을 마치고 시연해 보도록 하겠습니다.
이렇게 손 머리 위치 동기화 구현 R&D를 마치겠습니다.
'CGV(Castle Giant Virtual) 프로젝트 일지' 카테고리의 다른 글
CGV 개발일지 10 (잡은 플레이어 위치 동기화) (0) | 2023.12.14 |
---|---|
CGV 개발일지 9(잡은 물체 위치 동기화) (0) | 2023.12.13 |
CGV 개발일지 7 (주제 변경) (1) | 2023.12.11 |
CGV 개발일지 6 (멀티, 랜덤한 방 번호 만들기) (1) | 2023.11.29 |
CGV 개발일지 5 (Throw Object 개선 하기) (0) | 2023.11.25 |