Skip to main content
graphwiz.aigraphwiz.ai
← Back to Posts

Unity XR Development: Setting Up for Meta Quest and Vision Pro

XRUnity
unityxrmeta-questvision-provrar

Unity XR Development: Setting Up for Meta Quest and Apple Vision Pro

Unity is the most popular engine for XR development. This guide covers setting up projects for both Meta Quest and Apple Vision Pro.

Project Setup

Requirements

  • Unity 2022.3 LTS or 2023.2+
  • XR Plugin Management package
  • XR Interaction Toolkit
  • Platform-specific SDKs

Create XR Project

  1. Open Unity Hub → New Project
  2. Select "3D (URP)" template
  3. Name your project

Install XR Packages

Window → Package Manager → Unity Registry

Install:
- XR Plugin Management
- XR Interaction Toolkit
- OpenXR Plugin
- XR Hands
```text

## Meta Quest Setup

### XR Plugin Configuration

```text
Edit → Project Settings → XR Plug-in Management

✓ Oculus
✓ OpenXR (optional, for cross-platform)
```text

### Quest Features

```text
Edit → Project Settings → XR Plug-in Management → Oculus

✓ Shared Depth Buffer
✓ Low Overhead Mode (optional)
✓ Hand Tracking Support
✓ Passthrough Support
```text

### Build Settings

```text
File → Build Settings

Platform: Android
Texture Compression: ASTC
Graphics APIs: OpenGLES3 + Vulkan
```text

### Android Manifest

Add to `Assets/Plugins/Android/AndroidManifest.xml`:

```xml
<uses-feature android:name="android.hardware.vr.headtracking" />
<uses-permission android:name="com.oculus.permission.HAND_TRACKING" />
```text

## Apple Vision Pro Setup

### Requirements

- Unity 2023.2.4f1+
- Xcode 15.2+
- visionOS SDK

### XR Plugin Configuration

```text
Edit → Project Settings → XR Plug-in Management

✓ Apple visionOS
```text

### Build Settings

```text
File → Build Settings

Platform: iOS (visionOS)
Architecture: ARM64
```text

### Required Capabilities

In Xcode project settings:

- ARKit capability
- Hand Tracking capability

## XR Interaction Toolkit

### Basic Setup

```csharp
using UnityEngine;
using UnityEngine.XR.Interaction.Toolkit;

public class XRSetup : MonoBehaviour
{
    void Start()
    {
        var xrOrigin = FindObjectOfType<XROrigin>();
        var locomotion = xrOrigin.GetComponent<ActionBasedContinuousMoveProvider>();
    }
}
```text

### Grab Interactable

```csharp
using UnityEngine.XR.Interaction.Toolkit;

public class GrabbableItem : XRGrabInteractable
{
    protected override void OnSelectEntered(SelectEnterEventArgs args)
    {
        base.OnSelectEntered(args);
        // Object grabbed
    }

    protected override void OnSelectExited(SelectExitEventArgs args)
    {
        base.OnSelectExited(args);
        // Object released
    }
}
```text

## Hand Tracking

### Enable Hand Tracking

```csharp
using UnityEngine.XR.Hands;

public class HandTrackingExample : MonoBehaviour
{
    XRHandSubsystem handSubsystem;

    void Start()
    {
        var manager = XRGeneralSettings.Instance?.Manager?.activeLoader?.GetLoadedSubsystem<XRHandSubsystem>();
        handSubsystem = manager;
    }

    void Update()
    {
        if (handSubsystem != null)
        {
            handSubsystem.TryUpdateHands(XRHandSubsystem.UpdateType.Dynamic);

            var leftHand = handSubsystem.leftHand;
            var thumbTip = leftHand.GetJoint(XRHandJointID.ThumbTip);

            if (thumbTip.TryGetPose(out var pose))
            {
                transform.position = pose.position;
            }
        }
    }
}
```text

### Gesture Detection

```csharp
public class PinchDetector : MonoBehaviour
{
    public float pinchThreshold = 0.02f;

    public bool IsPinching(XRHand hand)
    {
        var thumbTip = hand.GetJoint(XRHandJointID.ThumbTip);
        var indexTip = hand.GetJoint(XRHandJointID.IndexTip);

        if (thumbTip.TryGetPose(out var thumbPose) &&
            indexTip.TryGetPose(out var indexPose))
        {
            float distance = Vector3.Distance(thumbPose.position, indexPose.position);
            return distance < pinchThreshold;
        }
        return false;
    }
}
```text

## Passthrough (Meta Quest)

### Enable Passthrough

```csharp
using UnityEngine.XR.Management;
using UnityEngine.XR;

public class PassthroughController : MonoBehaviour
{
    OVRPassthrough passthrough;
    OVRManager ovrManager;

    void Start()
    {
        ovrManager = FindObjectOfType<OVRManager>();
        passthrough = gameObject.AddComponent<OVRPassthrough>();
        passthrough.Enable();
    }

    public void SetPassthroughEnabled(bool enabled)
    {
        if (enabled)
            passthrough.Enable();
        else
            passthrough.Disable();
    }
}
```text

## Room Setup (Vision Pro)

```csharp
using UnityEngine.XR.ARKit;

public class RoomSetupController : MonoBehaviour
{
    ARKitSessionSubsystem arKitSession;

    void Start()
    {
        arKitSession = XRGeneralSettings.Instance?.Manager?.activeLoader?.GetLoadedSubsystem<ARKitSessionSubsystem>();
    }

    void RequestRoomMapping()
    {
        if (arKitSession != null)
        {
            arKitSession.RequestRoomMapping();
        }
    }
}
```text

## Build and Deploy

### Meta Quest

```bash
# Build APK
File → Build Settings → Build

# Deploy via ADB
adb install -r build.apk

# Or use Oculus Developer Hub
```text

### Apple Vision Pro

```bash
# Build for device
File → Build Settings → Build And Run

# Or build Xcode project
File → Build Settings → Build (creates .xcodeproj)
# Open in Xcode → Select visionOS target → Deploy
```text

## Conclusion

Unity XR development requires platform-specific setup but shares common interaction patterns. Start with XR Interaction Toolkit, add platform-specific features as needed.