Fusion Sticky Notes 크로스플랫폼 원격 재배치
개요
Fusion Sticky Notes 크로스플랫폼 원격 재배치는 서로 다른 장소에 있거나 서로 다른 헤드셋을 사용하는 사용자들이 혼합 현실 환경에서 협업할 수 있는 방법을 보여줍니다.
이를 위해 각 사용자는 애플리케이션 실행 시 버튼을 눌러 자신의 실제 환경에서 벽을 선택합니다.
이 벽(앵커)은 협업을 위한 기준점으로 사용됩니다.
다른 사용자가 세션에 참여하여 자신의 기준 벽을 선택하면, 시스템은 그 사용자를 유니티 씬 안으로 텔레포트시켜 첫 번째 사용자의 벽 위치에 맞게 정렬합니다.
이 재배치 이후 두 사용자는 유니티 씬 내의 동일한 기준점을 바라보게 되며, 각자의 실제 벽을 마주 보고 있게 됩니다.
이 재배치 기능은 사용하는 헤드셋과 관계없이 작동하며, 사용자는 스티키 노트를 생성하고 그 위에 그림을 그릴 수 있습니다.
이 샘플은 다음 세 가지 그리기 방식을 제공합니다:
- 손가락을 이용한 그리기 (손 또는 컨트롤러 추적을 통해)
- 가상 펜 사용
- Logitech MX Ink 사용 (Meta Quest 전용)
또한 펜을 이용해 3D 드로잉을 생성하고, 그림과 스티키 노트의 색상을 변경할 수도 있습니다.
크로스플랫폼 호환이 필요하지 않은 경우, 보다 단순한 버전의 샘플인 Fusion Sticky Notes Meta SSA Colocation을 사용할 수 있습니다. 이 버전은 Meta Shared Spatial Anchors(SSA) 기능을 기반으로 한 콜로케이션 시스템을 사용합니다.
기술 정보
이 프로젝트는 유니티 2022.3.47, Fusion 2.0.2, Photon Voice 2.53 버전으로 개발되었으며, 다음 패키지와 함께 테스트되었습니다:
- Meta XR Core SDK 68.0.3 : com.meta.xr.sdk.core
- Meta XR Platform 68.0.0 : com.meta.xr.sdk.platform
- Meta MR Utility Kit 68.0.2 : com.meta.xr.mrutilitykit
- VisionOS XR Plugin 1.3.9 : com.unity.xr.visionos
- Unity PolySpatial 1.3.9 : com.unity.polyspatial
- Unity PolySpatial visionOS 1.3.9 : com.unity.polyspatial.visionos
- Unity PolySpatial XR 1.3.9 : com.unity.polyspatial.xr
- Logitech MX Ink Unity Integration package (2024/08/28)
헤드셋 펌웨어 버전:
- Apple VisionOS 2.0
- Meta Quest v69
시작 전 준비
- 샘플을 실행하기 위해 먼저 PhotonEngine Dashboard에서 Fusion AppId를 생성하고, Fusion 메뉴에서 Real Time Settings의
App Id Fusion필드에 붙여 넣습니다.
그런 다음Launch씬을 로드하고Play를 누릅니다.
다운로드
| Version | Release Date | Download |
|---|---|---|
| 2.0.6 | 10월 08, 2025 | Fusion Sticky Notes Crossplateform Relocation 2.0.6 |
입력 조작
Meta Quest
- 텔레포트 : A, B, X, Y 버튼 또는 스틱을 눌러 포인터를 표시합니다. 버튼을 놓으면 허용된 대상 위치로 이동합니다.
- 터치 : 버튼 위에 손을 올리면 버튼이 토글 됩니다.
- 잡기 : 객체 위에 손을 올리고 컨트롤러의 그랩 버튼을 눌러 잡습니다.
- 가상 펜 :
- 조이스틱을 위/아래로 움직여 펜 색상을 변경합니다.
- 트리거 버튼을 눌러 3D 드로잉을 시작합니다. 펜을 놓으면 드로잉이 완료되고, 3D 드로잉을 잡을 수 있는 큐브가 생성됩니다.
- 펜 끝으로 스티키 노트를 터치하면 표면에 그림을 그릴 수 있습니다.
- 스티키 노트 : 조이스틱을 위/아래로 움직여 배경색을 변경합니다.
Logitech MX Ink (Meta 전용)
- 앞쪽 버튼 : 펜 색상 변경
- 가운데 버튼 : 3D 드로잉 시작
- 뒤쪽 버튼 : 3D 드로잉 종료 (완료 후 큐브 생성)
- 펜 끝으로 스티키 노트를 터치하면 표면에 그림을 그립니다.
- 펜 끝으로 실제 표면을 터치하면 3D 드로잉이 시작됩니다.
Apple Vision Pro
- 객체를 바라보고 손가락을 집으면 잡을 수 있습니다.
- 버튼을 바라보고 손가락을 집으면 누를 수 있습니다.
폴더 구조
/Photon폴더: Fusion 및 Photon Voice SDK 포함/Photon/FusionAddons폴더: 샘플에서 사용된 XR 애드온 포함/XR폴더: 가상현실 구성 파일 포함/Scripts폴더: 본 샘플에 특화된 스크립트 포함
아키텍처 개요
이 샘플은 VR Shared 페이지에 설명된 코드 기반을 사용하며, 특히 리그 동기화 부분을 공유합니다.
이 기본 구조 외에도, 재사용 가능한 기능을 처리하기 위해 Fusion Industries 애드온을 사용합니다.
혼합 현실
이 샘플은 패스스루와 평면 감지를 사용하는 혼합 현실에 중점을 두고 있습니다.
사용자의 로컬 환경에서 수직 표면을 감지하고, 상호작용할 수 있는 벽 프리팹을 스폰 합니다.
감지된 표면은 동기화되지 않으며, 감지한 사용자에게만 표시됩니다.
Meta Quest 참고:
실제 표면을 감지하려면 Quest 시스템 설정에서 먼저 방 구성을 수행해야 합니다.
크로스플랫폼
이 샘플은 Apple Vision Pro와 Meta Quest 헤드셋 모두에서 호환됩니다.
플랫폼 간 호환성을 유지하고 에디터 내 오류를 방지하기 위해, 런타임 시 사용 중인 플랫폼에 따라 씬 구성을 조정해야 합니다.
Meta 패키지는 VisionOS 빌드 시 문제를 일으킬 수 있으므로 VisionOS 플랫폼에서는 제거해야 합니다(자세한 내용은 visionOS 빌드 참고).
하지만 동일한 씬을 유지하기 위해 ExtendedRigSelection 기능을 사용하여 플랫폼에 따라 생성되는 오브젝트를 커스터마이즈 했습니다.
ExtendedRigSelection 게임 오브젝트는 두 가지 프로필을 관리합니다: MetaRig 및 VisionOSRig.
각 프로필은 플랫폼에 따라 특정 오브젝트를 활성화하거나, 해당 플랫폼 전용 프리팹을 스폰 합니다.
Meta 플랫폼
ExtendedRigSelection은 다음 일곱 가지 프리팹을 스폰 합니다:
Meta hardware rig(Meta용 커스텀 OVR 리그)Passthrough빌딩 블록Network Manager빌딩 블록 (Runner 포함,UserSpawner에서 플레이어 리그 프리팹 참조)Auto Matchmaking(Fusion Bootstrap으로 룸 이름 설정)Platform Init빌딩 블록MRUK빌딩 블록 변형 (물리 환경 분석용)AnchorPrefabSpawner변형 (수직 표면 감지 시 벽 프리팹 스폰)
Apple 플랫폼
ExtendedRigSelection은 런타임 시 다음 네 가지 오브젝트를 활성화합니다:
OpenXR hardware rigSpace Volume Camera(사용자에게 보이는 Unity 씬 영역 지정)Spatial Touch(사용자 상호작용 감지)Vertical AR Plane Detection(수직 표면 감지 시 벽 프리팹 스폰)
또한 ConnexionManager가 스폰 되며, 네트워크 Runner를 포함하고 플레이어 리그 프리팹을 스폰 합니다.
샘플에 포함된 visionOS 헬퍼 툴은 간접 핀치 지원 등 visionOS 플랫폼에 맞는 적절한 수정이 이루어지도록 보장합니다.
visionOS 빌드
Meta 패키지는 VisionOS 빌드를 방해하므로, 해당 플랫폼 빌드 시 제거해야 합니다.
ExtendedRig 선택 로직 덕분에 패키지를 제거하더라도 동일한 씬을 유지하면서 빌드 오류 없이 진행할 수 있습니다.
벽
벽 감지
애플리케이션이 실행되면 환경의 실제 수직 표면이 하이라이트 됩니다.
Meta Quest
Meta Quest 기기에서는 먼저 시스템 설정에서 방 스캔을 수행해야 합니다.
Meta MRUK(Mixed Reality Utility Kit) 프리팹은 장면 데이터를 관리하며, 환경이 알려진 방과 일치하는지 확인하고 해당 데이터를 로드합니다.
씬 데이터가 로드되면 AnchorPrefabSpawner 프리팹을 통해 벽을 표시할 수 있습니다.
이 프리팹은 수직 표면(레이블: WALL_FACE, DOOR_FRAME, WINDOW_FRAME, STORAGE, WALL_ART)을 감지하면 MagneticARWall Meta 벽 프리팹을 스폰하도록 설정됩니다.
스티키 노트의 MagnetPoint 컴포넌트는 IMagnets 인터페이스를 구현하는 모든 객체에 의해 끌어당겨집니다.
여기서 벽이 StaticMagnet 컴포넌트를 사용하여 해당 인터페이스를 구현합니다.
Apple Vision Pro
Apple Vision Pro에서는 AR Foundation의 ARPlaneManager를 통해 실시간으로 벽을 감지합니다.
이 매니저는 수직 표면이 감지되면 MagneticARWall VisionOS 벽 프리팹을 스폰하도록 설정되어 있습니다.
이 벽은 Meta용 벽과 유사하지만, 재질 처리 및 AR Foundation 관련 로직이 다릅니다.
벽 가시성
벽 프리팹의 WallVisibilityHandler 클래스는 현재 상태에 따라 벽의 가시성을 관리합니다:
- 아직 벽이 선택되지 않은 경우
- 해당 벽이 주 벽으로 선택된 경우
- 일반 벽인 경우
플레이어가 벽 버튼을 터치하면 상태가 변경됩니다. 선택된 벽만이 보이게 됩니다.
또한, 스티키 노트가 벽에 가까워질 때 시각적 효과를 주기 위해 IProximityTarget 인터페이스가 사용됩니다.
스티키 노트의 ProximityHighlighter 컴포넌트는 MagnetPoint 이벤트를 통해 거리 변화를 감지하고, IProximityTarget을 구현하는 오브젝트(WallVisibilityHandler)에 이를 전달합니다.
Meta 플랫폼의 셰이더는 Apple 플랫폼과 호환되지 않기 때문에 두 가지 시각 효과가 있습니다:
- Meta: 알파값(투명도)을 변경
- Apple: 색상 강도를 변경
벽 선택 및 재배치
플레이어 재배치의 일반적인 개념은 다음과 같습니다:
- 첫 번째 플레이어가 벽을 선택하면, 그 벽의 위치에 기준 앵커를 생성합니다.
이 앵커는 네트워크로 동기화되어 이후 참여자들이 참조할 수 있습니다. - 두 번째 플레이어가 벽을 선택하면, 씬 내에서 기존의 네트워크 기준 앵커가 있는지 확인합니다.
- 플레이어의 벽 상대 위치와 기준 앵커의 위치를 이용해, 두 번째 플레이어를 Unity 씬 내의 동일한 기준 위치 앞에 텔레포트시킵니다.

자세히 살펴보면, 사용자가 벽 버튼을 누르면 ElectAsMainWall() 메서드가 호출되어 벽 가시성을 변경하고, 동시에 벽 게임 오브젝트의 SpaceLocalizationHandler 컴포넌트의 ReferenceWallSelection() 함수를 호출합니다.
이 함수는 기준 앵커를 검색하고, 이미 존재한다면 텔레포트하며, 없다면 새로 생성합니다.
C#
public void ElectAsMainWall()
{
ChangeStatus(Status.MainWall);
foreach (var otherWall in SceneWalls)
{
if (otherWall == this) continue;
otherWall.ChangeStatus(Status.BaseWall);
}
if (spaceLocalizationHandler != null)
spaceLocalizationHandler.ReferenceWallSelection();
}
C#
public void ReferenceWallSelection()
{
...
// Check if a reference wall has been spawned by a previous player
DetectReferenceWall();
if (referenceWall)
{
// Teleport the user
TeleportUserToPlaceReferenceAnchoreAtSelectedRealLifeposition();
}
else
{
// Compute the reference anchor and spawn it
...
}
runner.Spawn(referenceWallPrefab, transform.position, referenceWallRotation);
}
}
펜(Pens)
사용자는 가상 펜 또는 Logitech MX Ink를 이용해 3D 드로잉을 생성하거나 스티키 노트와 상호작용할 수 있습니다.
가상 펜
첫 번째 사용자가 네트워크에 연결되면 SpawnOnConnect 클래스를 통해 두 개의 가상 펜이 자동으로 생성됩니다.
가상 펜은 트리거 버튼을 눌러 3D 드로잉을 시작하고, 조이스틱을 위/아래로 움직여 색상을 변경할 수 있습니다.
펜을 놓으면 드로잉이 완료되고, 해당 드로잉을 잡을 수 있는 큐브가 생성됩니다.
또한, 펜 끝으로 스티키 노트를 터치하면 표면에 그림을 그릴 수 있습니다.
Logitech MX Ink
Logitech MX Ink는 가운데 버튼으로 3D 드로잉을 시작하고, 앞쪽 버튼으로 색상을 변경합니다.
뒤쪽 버튼을 누르면 드로잉이 종료되며, 실제 표면을 터치하면 3D 드로잉이 생성됩니다.
펜 끝으로 스티키 노트를 터치하면 표면에 그림을 그리며, 가상 펜과 동일하게 포스트잇에 의해 시각적으로 차단됩니다.
플레이어의 NetworkRig에는 NetworkMXInkPen 프리팹이 포함되어 있으며, ColoredNetworkMXPen은 NetworkMXPen을 상속받아 확장됩니다.
MX Ink 펜은 IsStylusActive 네트워크 변수에 따라 표시됩니다. 상태가 변경되면 OnChangeIsStylusActive()가 호출됩니다.
C#
[Networked, OnChangedRender(nameof(OnChangeIsStylusActive))]
public NetworkBool IsStylusActive { get; set; }
protected virtual void OnChangeIsStylusActive()
{
UpdateDisplayedGameObjects();
}
NetworkMXPen 클래스는 실제 MX Ink 펜의 위치와 회전을 네트워크상에 동기화하는 역할도 합니다.
C#
public override void Spawned()
{
base.Spawned();
#if OCULUS_SDK_AVAILABLE
if (Object.HasStateAuthority)
{
localHardwareStylus = FindObjectOfType<VrStylusHandler>();
}
#endif
UpdateDisplayedGameObjects();
}
public override void FixedUpdateNetwork()
{
base.FixedUpdateNetwork();
if (localHardwareStylus)
{
transform.position = localHardwareStylus.transform.position;
transform.rotation = localHardwareStylus.transform.rotation;
IsStylusActive = localHardwareStylus.CurrentState.isActive;
IsReplacingRightHand = localHardwareStylus.CurrentState.isOnRightHand;
}
}
Meta 기기의 하드웨어 리그에는 HardwareMXInkPen 클래스가 포함되어 있으며, 이는 Logitech의 VrStylusHandler 클래스를 상속받습니다.
드로잉 동기화
가상 펜의 3D 선 생성 및 동기화는 Line Drawing 애드온의 NetworkGrabbableLineDrawer 클래스가 관리합니다.
Logitech MX Ink 펜의 경우, MX Ink Integration 애드온 내 NetworkMXPen 클래스가 처리합니다.
피드백
두 펜 모두 사용 시 오디오 및 햅틱 피드백이 제공됩니다.
이를 위해 피드백이 필요한 클래스는 IFeedbackHandler 인터페이스를 탐색하며, 해당 인터페이스는 XRShared 애드온의 BasicFeedback 클래스에서 구현됩니다.
예를 들어, GrabbableColorSelection 클래스는 사용자가 펜 색상을 변경할 때 오디오 및 햅틱 피드백을 생성합니다.
C#
[Header("Feedback")]
IFeedbackHandler feedback;
[SerializeField] string audioType;
[SerializeField] FeedbackMode feedbackMode = FeedbackMode.AudioAndHaptic;
protected virtual void Awake()
{
...
feedback = GetComponent<IFeedbackHandler>();
...
}
private void CheckColorModification()
{
...
// Audio & Haptic feedback
if (feedback != null)
feedback.PlayAudioAndHapticFeeback(audioType: audioType, audioOverwrite: true, feedbackMode: feedbackMode);
...
}
스티키 노트
스티키 노트는 Sticky Notes 애드온을 기반으로 구성되어 있습니다.
스티키 노트 표면의 그림 동기화
사용자는 손가락, 가상 펜 또는 Logitech MX Ink로 스티키 노트 표면에 그림을 그릴 수 있습니다.
스티키 노트의 텍스처 동기화는 Texture Drawings 애드온의 TextureDrawer 및 TextureDrawing 클래스가 담당합니다.
손가락으로 그리기
일반 펜을 사용할 때는 애드온의 TexturePen 클래스가 사용되지만, 손가락으로 그리기 위해서는 TouchDrawing이라는 별도의 클래스가 제공됩니다.
이 클래스는 사용자 네트워크 리그 내의 TextureDrawer 컴포넌트(손마다 하나씩)와 연결되어 작동합니다.
TouchDrawing은 ITouchable 인터페이스를 구현하여, 손가락 끝에 있는 Toucher 컴포넌트(정확히는 Pincher 서브 클래스)가 포스트잇을 터치할 때 알림을 받습니다.
사용자가 스티키 노트를 잡으려는 동작과 구분하기 위해, DetectGrabbingOrDrawingStart는 손가락의 방향을 확인하여 실제로 그림을 시작하려는 의도인지 감지합니다.
손가락이 표면에 닿아 있는 동안에는 Draw 메서드가 호출되고, SmoothPosition이 평균 접촉점을 계산하여 떨림 없이 부드러운 선이 그려지도록 합니다.
이 기능은 numberOfToucherPositionsToSmoothOn 값을 조정하여 비활성화할 수도 있습니다(0으로 설정 시 비활성화).
마지막으로, TextureDrawer의 AddDrawingPoint 메서드를 호출하여 드로잉 포인트를 추가합니다.
visionOS 공간 터치 드로잉
프로젝트에는 TouchDrawing을 상속한 SpatialTouchDrawing 클래스가 포함되어 있으며, 이는 visionOS 공간 터치를 사용합니다.
이 클래스는 SpatialTouchHandler 컴포넌트가 트리거 하는 ISpatialTouchListener 콜백을 통해 동작합니다.
visionOS 1에서는 손 스켈레톤의 업데이트 속도가 느렸기 때문에 공간 터치가 훨씬 더 정확하고 빠른 드로잉 방법이었습니다.
하지만 visionOS 2에서는 손 추적이 개선되어 기본적으로 TouchDrawing을 사용합니다.
SpatialTouchDrawing은 반응 속도가 더 빠르고 매끄럽지만, Polyspatial의 제약으로 인해 동일 객체를 반복 터치할 수 없는 문제가 있어 기본 설정에서는 사용하지 않습니다.
UI 및 상호작용
기본 스티키 노트 애드온 프리팹에는 다음과 같은 UI가 추가되었습니다:
- 배경색 변경
- 드로잉 색상 변경
- 그림 삭제
- 스티키 노트 삭제
펜 상호작용
스티키 노트 버튼(SpatialButton, SpatialButtonWithIcons)은 SpatialTouchable 클래스에서 ITouchable 인터페이스를 구현합니다.
펜에는 Toucher 컴포넌트가 있어, ITouchable 인터페이스가 있는 객체와 충돌 시 이를 감지합니다.
손 상호작용
손가락을 사용한 상호작용에서는 하드웨어 리그의 검지에 위치한 Pincher 컴포넌트가 사용됩니다.
이 컴포넌트는 Toucher를 상속받아 ITouchable 및 IPinchable 인터페이스를 지원합니다.
따라서 손가락으로 UI 버튼(SpatialButton, SpatialButtonWithIcons)을 직접 터치할 수 있습니다.
HandRepresentationManager는 손 추적 모드(컨트롤러/손가락)에 따라 표시할 손 모델을 제어합니다.
이 샘플에서는 손가락 추적이 활성화되면 하드웨어 리그 손 모델이 표시되도록 설정되어 있습니다.
로컬 손 표현은 다음과 같습니다:
- visionOS: XR Hands 패키지
- Meta Quest: Meta OVR 손 모델
원격 사용자 손은 항상 XR Hands 패키지 모델을 사용합니다.
손 상태 동기화에 대한 자세한 내용은 XR Hands Synchronization 애드온을 참고하세요.
스티키 노트 UI를 통한 색상 변경
스티키 노트의 색상 버튼에는 ColorDipper 컴포넌트가 있습니다.
펜에는 ColorDipperDetector가 있어 충돌 시 새로운 색상을 감지합니다.
충돌이 감지되면 ColorDipperDetector는 색상 변경 요청을 기록하고 FixedUpdateNetwork()에서 이를 적용합니다.
C#
private void OnTriggerEnter(Collider other)
{
if (Object && Object.HasStateAuthority)
{
ColorDipper colorDipper = other.GetComponentInParent<ColorDipper>();
if (colorDipper != null)
{
colorChangeRequest = true;
requestedColor = colorDipper.color;
}
}
}
public override void FixedUpdateNetwork()
{
base.FixedUpdateNetwork();
if(colorChangeRequest)
{
colorProvider.CurrentColor = requestedColor;
colorChangeRequest = false;
}
}
그다음으로, GrabbableColorSelection 클래스는 색상 변경을 네트워크 상에서 동기화합니다 (OnColorChanged()).
또한 이 클래스는 플레이어가 컨트롤러의 조이스틱을 사용해 색상을 변경할 때도 해당 색상 변경을 네트워크에 동기화하는 역할을 합니다.
Logitech MX Ink의 경우, ColoredNetworkMXPen 클래스가 IColorProvider 인터페이스를 구현하고 있으므로, 사용자가 MX Ink 하드웨어 버튼을 사용하거나 색상 버튼과 상호작용할 때 드로잉 색상을 변경하는 책임을 가집니다.
또한 UI도 네트워크를 통해 동기화된다는 점에 유의해야 합니다.
새로운 색상이 선택되면, SpatialButton 클래스가 StickyNoteColorSelectionWithMenu 클래스의 ChangeDrawingColor() 메서드를 호출합니다.
이 메서드는 먼저 사용자가 해당 오브젝트에 대한 StateAuthority를 가지고 있는지 확인한 뒤, 색상 인덱스 변수를 변경합니다.
이 변수는 FixedUpdateNetwork()에서 검사되며, 필요시 네트워크 변수 DrawingColorMenuIndex가 업데이트되어 원격 사용자의 UI에 색상 변경이 반영됩니다.
마지막으로, 모든 플레이어에서 OnDrawingColorMenuIndexChanged() 함수가 호출됩니다.
C#
[Networked, OnChangedRender(nameof(OnDrawingColorMenuIndexChanged))]
[SerializeField] private int DrawingColorMenuIndex { get; set; }
// ChangeDrawingColor is called by menu buttons (SpatialButtonWithIcons) in the scene
public void ChangeDrawingColor(int index)
{
if (Object == null) return;
await Object.WaitForStateAuthority();
drawingColorRequestedWithMenu = index;
}
public override void FixedUpdateNetwork()
{
base.FixedUpdateNetwork();
if (Object == null || Object.HasStateAuthority == false) return;
CheckBackgroundColorSelectionWithStickyNoteMenu();
CheckDrawingColorSelectionWithStickyNoteMenu();
}
private void CheckDrawingColorSelectionWithStickyNoteMenu()
{
if (DrawingColorMenuIndex != drawingColorRequestedWithMenu)
{
if (Object.HasStateAuthority)
{
// change the DrawingColorMenuIndex networked var so remote player's UI will be updated
DrawingColorMenuIndex = drawingColorRequestedWithMenu;
}
}
}
// Update the menu selected color when the network var DrawingColorMenuIndex has been changed
protected virtual void OnDrawingColorMenuIndexChanged()
{
// change drawing color
ApplySpatialTouchDrawingColorChange(DrawingColorMenuIndex);
if (DrawingColorMenuIndex == previousDrawingColorMenuIndex) return;
// Update the color index
previousDrawingColorMenuIndex = DrawingColorMenuIndex;
// update buttons
ActivateRadioButton(drawingColorRadioGroupButtons, DrawingColorMenuIndex);
}
배경색 변경
사용자가 UI에서 새로운 색상을 선택하면 스티키 노트의 배경색을 변경할 수 있습니다.
UI 업데이트 과정은 앞서 설명한 드로잉 색상 선택 과정과 매우 유사합니다.
텍스처 색상 변경 과정에 대해 살펴보면, 새로운 배경색이 선택될 때 SpatialButton 클래스는 StickyNoteColorSelectionWithMenu 클래스의 ChangeStickyNoteColor() 메서드를 호출합니다.
이 메서드는 먼저 사용자가 해당 오브젝트에 대한 State Authority를 가지고 있는지 확인한 뒤, backgroundColorRequestedWithMenu 변수를 변경합니다.
이 변수는 FixedUpdateNetwork() 내에서 CheckBackgroundColorSelectionWithStickyNoteMenu() 메서드를 통해 확인됩니다.
C#
// ChangeStickyNoteColor is called by menu buttons (SpatialButtonWithIcons) in the scene
public async void ChangeStickyNoteColor(int index)
{
if (Object == null) return;
await Object.WaitForStateAuthority();
backgroundColorRequestedWithMenu = index;
}
private void CheckBackgroundColorSelectionWithStickyNoteMenu()
{
if (backgroundColorRequestedWithMenu != -1 && colorIndex != backgroundColorRequestedWithMenu)
{
ChangeColor(backgroundColorRequestedWithMenu);
backgroundColorRequestedWithMenu = -1;
}
}
GrabbableColorSelection 클래스의 ChangeColor() 함수는 네트워크 변수인 CurrentColor를 업데이트합니다.
이에 따라 OnCurrentColorChange(), OnColorChanged(), 그리고 ApplyColorChange() 메서드가 순차적으로 호출됩니다.
C#
public class GrabbableColorSelection : NetworkBehaviour, IColorProvider
{
[Networked, OnChangedRender(nameof(OnCurrentColorChange))]
public Color CurrentColor { get; set; }
...
void OnCurrentColorChange()
{
OnColorChanged();
}
// Update the color when the network var has been changed
protected virtual void OnColorChanged(bool forceChange = false)
{
if (CurrentColor == previousColor) return;
// Update the color
previousColor = CurrentColor;
...
ApplyColorChange(CurrentColor);
}
...
새로운 배경색은 StickyNoteColorSelection 파생 클래스의 오버라이드 된 ApplyColorChange() 함수에 의해 TextureSurface에 적용됩니다.
C#
public class StickyNoteColorSelection : GrabbableColorSelection
{
TextureSurface texture;
protected override void Awake()
{
base.Awake();
texture = GetComponent<TextureSurface>();
if (texture == null)
Debug.LogError("TextureSurface not found");
}
protected override void ApplyColorChange(Color color)
{
texture.ChangeBackgroundColor(color);
}
}
삭제
스티키 노트를 삭제하면 DespawnObject의 DeleteObject()가 호출됩니다.
오디오 피드백을 재생할 시간을 두기 위해 약간의 지연 후 오브젝트가 제거됩니다.
C#
public void DeleteObject()
{
await Object.WaitForStateAuthority();
if (Object.HasStateAuthority)
{
StartCoroutine(DeleteObjectAfterDelay(delayBeforeDespawn));
}
}
IEnumerator DeleteObjectAfterDelay(float delay)
{
if (feedback != null)
{
feedback.PlayAudioFeeback(audioType);
}
yield return new WaitForSeconds(delay);
Object.Runner.Despawn(this.Object);
}
스냅
벽 프리팹의 Static Magnet 컴포넌트에는 PostItStickingSurface 마그넷 레이어가 설정되어 있습니다.
스티키 노트의 Magnet Point 컴포넌트도 동일한 레이어로 설정되어야 벽에 자동으로 붙습니다.
사용된 XR 애드온 및 인더스트리 애드온
3D/XR 프로젝트를 빠르게 시작할 수 있도록, Photon은 다양한 재사용 가능한 애드온을 제공합니다.
자세한 내용은 Industries Addons를 참고하세요.
XRShared
핵심 리그 동기화 및 기본 상호작용(잡기, 이동 등)을 제공합니다.
XR Shared
Meta Core 통합
Meta 플랫폼의 빌딩 블록 통합을 간소화합니다.
Meta Core Integration
VisionOS Helpers
visionOS 플랫폼의 간접 핀치, Polyspatial 상태 동기화, 교차 플랫폼 도구 등을 지원합니다.
VisionOS Helpers
MXInkIntegration
Logitech MX Ink 펜 지원을 위한 통합 애드온입니다.
MX Ink Integration
Voice Helpers
Photon Voice 설정을 간소화하는 구성 요소를 제공합니다.
Voice Helpers
ConnectionManager
플랫폼별 네트워크 연결 및 사용자 스폰을 관리합니다.
ConnectionManager
ExtendedRigSelection
플랫폼별 리그 전환을 지원합니다.
Extended Rig Selection
Line Drawing
펜 드로잉 기능을 제공합니다.
Line Drawing
Texture Drawing
스티키 노트의 표면 드로잉을 네트워크로 동기화합니다.
Texture Drawing
Data Sync Helpers
3D/2D 드로잉 포인트 및 스티키 노트 데이터를 동기화합니다.
Data Sync Helpers
Blocking Contact
펜이 스티키 노트 표면을 관통하지 않도록 차단합니다.
Blocking Contact
Magnets
스티키 노트가 벽에 부착되도록 관리합니다.
Magnets
Sticky Notes
스티키 노트를 생성하고 관리할 수 있도록 합니다.
Sticky Notes
XRHands Synchronization
XR Hands 손 상태를 네트워크로 동기화하며, 손동작(핀치, 그랩 등)을 감지하는 헬퍼 클래스를 제공합니다.
XR Hands Synchronization
서드파티 구성 요소
Oculus Sample Framework 손 모델
사운드 리소스: