This document is about: FUSION 2
SWITCH TO

구조 결합(Structure Cohesion)

Fusion XR 프로토타이핑 애드온

이 모듈은 여러 파트로 구성된 네트워크 오브젝트를 협력하여 구축하는 기능을 제공합니다.

목표

이 시스템의 설계 목표는 다음과 같습니다:

  • 하나의 구조는 여러 개의 구조 파트(Structure Parts)로 구성되며, 각각 독립적으로 움직일 수 있어야 합니다 (대부분 잡을 수 있음)
  • 구조 파트가 하나 움직일 때, 같은 구조에 속한 모든 파트가 자연스럽게 함께 움직여야 합니다
  • 여러 사용자가 동시에 파트를 추가하거나 제거할 수 있어야 하며, 충돌이나 전환 시간을 최소화하기 위해 권한 변경을 최소화해야 합니다
  • 구조 파트를 기존 구조(또는 단일 파트) 근처에 놓으면 사전 정의된 결합 지점을 통해 스냅 되어야 합니다
  • 두 개의 서로 다른 구조 파트를 잡으면 구조가 둘로 나뉘어야 하며, 가장 최근에 결합된 지점을 기준으로 분리되어야 합니다
  • 한 손으로 구조를 분리할 수 있도록, 일부 파트는 "가벼운 무게"를 가질 수 있어야 하며, 이 파트를 잡을 경우 구조가 쉽게 분리되어야 합니다
  • 선택적으로, 구조 이동 시 모든 파트의 위치를 네트워크로 전송하지 않고, 변경된 지점만 네트워크로 전송하여 대역폭을 절약할 수 있도록 설정할 수 있어야 합니다

로직 개요

여러 파트로 구성된 구조를 협력적으로 조작할 수 있도록 다음과 같은 로직을 따릅니다:

  • 구조 파트와 파트 간 연결은 네트워크를 통해 동기화됩니다. 구조는 로컬에서 재구성되며, 생성/삭제된 결합 정보를 감지하여 재구성됩니다 (권한이 없는 파트도 포함)

  • 구조 파트에는 여러 결합 지점이 있을 수 있으며, 다른 구조 파트의 결합 지점과 연결될 수 있습니다

  • 결합은 한쪽 결합 지점에만 저장되므로, 해당 지점에 대한 권한만 있으면 네트워크 정보를 수정할 수 있습니다

  • 구조 파트의 상태 권한은 여러 사용자 간에 공유될 수 있습니다. 파트를 조작하거나 결합할 때 권한이 필요합니다

  • 구조 파트는 네트워크상에 IsMoving 프로퍼티를 저장합니다. 이를 통해 움직이는 구조를 감지하여 분리할 수 있습니다

  • 모든 결합에는 순서가 부여되어 최근 결합 여부를 판단할 수 있습니다. 이는 구조 분리 시 사용됩니다

  • 구조는 두 가지 경우에 분리될 수 있습니다:

    • 두 개 이상의 파트가 동시에 움직이는 경우
    • 가벼운 무게를 가진 파트를 통해 구조가 조작되는 경우
  • StructureManager는 전체 구조를 추적하고 새로운 구조를 생성하는 역할을 합니다

  • StructurePartsManager는 모든 파트와 결합 지점 태그를 관리하는 데 도움을 줄 수 있습니다

Structure logic overview

놓을 때(언그랩) 결합 생성

구조 파트를 놓으면 AttachClosestPartInProximity()가 호출됩니다.
이 함수는 현재 구조 내 다른 파트의 결합 지점 중 가장 가까운 지점을 찾아 결합을 생성합니다.
결합 정보는 놓은 파트에 저장되며, 만약 권한이 없다면 먼저 권한을 가져온 후 결합을 설정합니다.

New attachment on ungrabbing

놓은 파트는 기존 파트에 맞춰 위치를 조정합니다. (움직이지 않던 파트를 기준으로 스냅)

AttachmentPoint는 추상 클래스이며, 다음 메서드를 구현해야 합니다:

  • TryFindClosestAttachmentPoint(out AttachmentPoint closestPoint, out float minDistance, bool excludeSameGroupId = true)
  • Snap(AttachmentPoint other)

동시에 움직일 때 결합 삭제

같은 구조 안에서 두 파트가 동시에 움직이면,
가장 최근 결합된 지점을 찾아 구조를 분리합니다.

splitting structure with 2 moving parts

가벼운 파트 하나만 움직일 때 결합 삭제

하나의 파트만 움직이고, 구조의 StructuralCohesionModeWeightBasedCohesion일 경우,
움직이는 파트의 무게가 다른 파트보다 가벼우면 구조를 분리합니다.

만약 이 파트가 "끝"에 연결된 경우, 바로 해당 결합을 끊습니다.
그렇지 않으면 가장 무거운 섹션으로 이어지는 결합을 찾아 분리합니다.

재배치

구조가 유지되도록, 파트들이 함께 이동해야 합니다.
다음 기준에 따라 기준 파트를 선택하여 재배치합니다:

  • 움직이는 파트가 기준 (있다면)
  • 없다면 가장 낮은 ID를 가진 파트가 기준
  • 가능한 경우 마지막 사용된 기준 파트를 계속 유지하여 불필요한 점프를 방지

재배치는 FixedUpdateNetwork에서 실행되며, LateUpdate에서도 렌더링 일관성을 위해 수행됩니다.

태그 호환성

AttachmentPoint에서는 다음을 관리합니다:

  • AttachmentPointTags: 결합 지점의 태그
  • CompatibleAttachmentPointTags: 연결할 수 있는 결합 지점의 태그 목록

스냅 감지 기반

StructurePart 클래스는 그 자체로 잡기(Grabbing) 기능을 가지지 않습니다.
GrabbableStructurePartXRShared 애드온을 통해 IsMoving을 설정하고, 결합 처리를 담당합니다.

스냅 로직은 Magnets 애드온을 기반으로 구현되었습니다.

Actual classes implementation

선택적 컨테인먼트(Containment)

대역폭 최적화를 위해 NetworkTransform의 부모-자식 관계를 이용할 수 있습니다.
부모가 움직이면 자식들의 네트워크 업데이트가 필요하지 않게 됩니다.

ContainmentHandler는 구조 파트들을 자동으로 하나의 컨테이너에 묶습니다.
ProxyGrabbing은 실제로 컨테이너를 움직이도록 동작을 재정의합니다.

안정된 구조 상태(변동 없음, 모두 컨테이너 있음)에서는 구조 파트들의 재배치를 건너뛸 수 있습니다.

주의: 현재 구현은 컨테이너를 반복 생성/제거하기 때문에, 추후 풀링 최적화가 필요합니다.

설정 방법

  • StructureManager를 씬에 추가해야 합니다.

선택적 컨테인먼트 설정

  • ContainmentManager를 추가해야 합니다.
  • 모든 GrabbableStructurePart 옆에 ContainmentHandlerProxyGrabbing 컴포넌트를 추가해야 합니다.
  • ContainmentManagerdisableContainerParenting 옵션을 통해 빠르게 비교할 수 있습니다.

독립적인 AttachmentPoint 사용

AttachmentPoint 클래스는 구조 없이도 사용할 수 있습니다.
단순히 두 개의 오브젝트 간 "연결"을 동기화하고 알리는 역할을 합니다.

구조 내부에서 사용하려면 IStructurePartPoint를 구현해야 합니다 (MagnetStructureAttachmentPoint 참고).

MagnetAttachmentPoint 예시

두 마그넷이 서로 스냅 할 때의 연결 추적에 사용할 수 있습니다.
이 예시는 MagnetAttachmentPoint 클래스에서 보여줍니다.

의존성

  • XRShared 애드온
  • Magnets 애드온

다운로드

이 애드온의 최신 버전은 Industries 애드온 프로젝트에서 다운로드할 수 있습니다.

지원 토폴로지

  • 공유 모드

변경 기록

  • 버전 2.0.0: 첫 번째 릴리스
Back to top