---
title: "Creating an interactive VR scene with Android XR"
content_type: tutorial
url: "https://learn.unity.com/course/android-xr-with-unity/tutorial/creating-interactive-vr-scene?language=en"
language: en
container_type: course
container_title: "Android XR with Unity: From Setup to Hands-on Interaction"
container_url: "https://learn.unity.com/course/android-xr-with-unity.md?language=en&version=6.2"
standalone_markdown_url: "https://learn.unity.com/tutorial/creating-interactive-vr-scene.md?language=en&version=6.2"
previous_title: "Getting started with Android XR in Unity"
previous_url: "https://learn.unity.com/course/android-xr-with-unity/tutorial/getting-started-android-xr?language=en&version=6.2"
previous_markdown_url: "https://learn.unity.com/course/android-xr-with-unity/tutorial/getting-started-android-xr.md?language=en&version=6.2"
difficulty: beginner
duration_minutes: 20
unity_version:
  - "6.2"
supported_unity_versions:
  - name: "6.2"
    url: "https://learn.unity.com/course/android-xr-with-unity/tutorial/creating-interactive-vr-scene.md?language=en&version=6.2"
last_updated: "2026-08-13T17:19:23.000Z"
---

# Creating an interactive VR scene with Android XR

Build an Android XR scene using XR Interaction Toolkit and XR Hands with grab, throw, and poke button interactions.

In this tutorial, you'll build a basic VR scene for Android XR using Unity’s XR Interaction Toolkit and XR Hands. You'll create grab-and-throw interactions using tracked hand input (with controller fallback), and implement a 3D pokeable button that resets a cube using a simple custom script.

You’ll gain hands-on experience with the following:

- Physics-based grabbing and throwing
- Poke interactions and affordances
- Unity Events for interaction scripting

## 1. Overview

In this tutorial, you’ll build a basic VR scene for Android XR using Unity’s XR Interaction Toolkit and XR Hands. You’ll create physics-based grab-and-throw interactions driven by tracked hand input with controller fallback, and implement a 3D pokeable button that resets a cube via a simple custom script. Along the way, you’ll gain hands-on experience with poke affordances and using Unity Events for interaction scripting.

## 2. Before you begin _(Optional)_

Prerequisite**:** This tutorial builds on the scene created in [**Getting Started with Android XR in Unity**](https://learn.unity.com/tutorial/getting-started-with-android-xr-in-unity).
Complete that tutorial first to set up the base XR project using the VR Template and XR Interaction Toolkit samples.

## 3. Initial scene setup

To begin, you’ll add the core components that are needed for hand tracking and turn off shadows, which aren’t necessary for this basic interaction scene.

**1.**  In the **Hierarchy** window, delete the **XR Origin (XR Rig)** GameObject.

**2.**  In the **Project** window, go to **Assets** > **Samples** > **XR Interaction Toolkit** > **3.2.1** > **Hands Interaction Demo** > **Prefabs**.

**3.**  Drag the **XR Origin Hands (XR Rig)** prefab into the **Hierarchy** window.

**4.**  Set its **Transform** component’s **Position** property to **X** = **0**, **Y** =  **0**, and **Z** = **0**.

This prefab includes preconfigured **XR** **Hand** GameObjects for poke and pinch interactions, as well as useful components like the **XRInputModalityManager**, which automatically switches between hands and controllers depending on the input source.

![](https://connect-mediagw.unity.com/h1/20251014/learn/images/724a210d-1558-41af-abcd-62553cf07f1b_1._scene-with-xr-origin-hands.png)

To access hand tracking data on Android, your app must prompt the user for the correct permission. The **PermissionsManager** prefab is preconfigured to request hand tracking but can also support additional permissions or platforms.

**5.**  In the **Project** window, go to **Assets** > **Samples** > **XR Interaction Toolkit** > **3.2.1** > **Starter Assets** > **Prefabs**.

**6.**  Drag the **PermissionsManager** prefab into the **Hierarchy** window.

![](https://connect-mediagw.unity.com/h1/20251014/learn/images/7272b640-c388-41b7-80d9-a60add9880f7_2._scene-with-permissions-manager.png)

The VR Template's **BasicScene** uses soft shadows by default, but for this basic scene, shadows are not needed.

**7.**  In the **Hierarchy** window, select the **Directional Light** GameObject.

**8.**  In the **Inspector** window, in the **Light** component, use the foldout (triangle) to expand the **Shadows** section, then open the **Shadow Type** property dropdown and select **No Shadows**.

![](https://connect-mediagw.unity.com/h1/20251014/learn/images/29e4665b-1b08-40c2-ba9a-6f570d6f54af_3._direction-light-no-shadows.png)

You’ve now set up your project for hand tracking.

## 4. Create a table and interactable cube

Now you’ll create a small table and a cube that users can grab and throw using hands or controllers.

**1.**  Right-click in the **Hierarchy** window, select **Create Empty**, and rename it “TableGroup”.

**2.**  Under **TableGroup**, create a **3D Object** > **Cube**, and rename it “Table”.

**3.**  Set the **Table** GameObject’s **Transform** component’s **Scale** property to **X** = **1**, **Y** = **0.1**, and **Z** = **1** to create a flat surface.

**4.** Under **TableGroup**, create another **Cube**, and rename it “InteractableCube”.

**5.**  Set the **InteractableCube** GameObject’s **Transform** component’s **Scale** property to **X** = **0.3**, **Y** = **0.3**, and **Z** = **0.3** so it can be easily grabbed.

**6.**  Set its **Transform** component’s **Position** property’s **Y** value to **0.5** to lift it slightly above the table.

![](https://connect-mediagw.unity.com/h1/20251014/learn/images/5edf85d6-bafd-424c-aee3-ba58690ee452_4._scene-table-cube-objects.png)

**7.**  In the **Inspector** window, select **Add** **Component** and search for and add the **XR Grab Interactable** script component to the **InteractableCube** GameObject.

**8.**  In the **Inspector** window, enable the **Use Dynamic Attach** property and the **Force Gravity On Detach** property.

The **Use** **Dynamic** **Attach** property keeps the cube from snapping too close to the hand, and the **Force Gravity On Detach** property simulates realistic throwing.

![](https://connect-mediagw.unity.com/h1/20251014/learn/images/37b9ef81-d007-4680-ac38-23cad956f686_5._inspector-grab-interactable-configuration.png)

**9.**  Add a **Rigidbody** component (if not present) and, in the **Inspector** window, disable the **Use Gravity** property.

Disabling the **Use Gravity** property allows the cube to float when released.

**10.**  Select **TableGroup** GameObject and set its **Transform** component’s **Position** property to **X** = **0**, **Y** = **1**, and **Z** = **0.7** so the scene appears comfortably in front of the user in seated XR.


You can now grab and throw the cube using hands or controllers.

## 5. Add a 3D Button to the scene

Now you’ll create a simple 3D button that will later reset the cube's position.

**1.** Under **TableGroup**, create an empty GameObject and name it “InteractableButton”.

**2.**  Under **InteractableButton**, create an empty GameObject called “ButtonOffset”.

**3.**  Under **ButtonOffset**, add a **3D Object** > **Cylinder**, rename it “ButtonMesh”, and set its **Transform** component’s **Scale** property to **X** = **0.1, Y** =  **0.03**, and **Z** = **0.1**.

These child GameObjects are necessary for implementing the **XR Poke Follow Affordance** component. Separating the mesh allows it to move independently during a poke interaction.

**4.**  Right-click in the **Assets** folder, select **Create** > **Material**, rename it “ButtonMaterial”, set the **Base Map** property to **#FD7B7B** (or any other color), and drag the material onto the **ButtonMesh** GameObject.

To ensure a stable poke interaction, you need to add the collider separately from the moving mesh.

**5.**  Remove the **Capsule Collider** from the **ButtonMesh** GameObject.

**6.**  Under the **InteractableButton** GameObject, create an empty GameObject and name it “Button Collider”.

**7.**  Add a **Box Collider** component to the **ButtonCollider** GameObject and set its **Transform** component’s **Size** property to **X** = **0.1, Y** = **0.06**, and **Z** = **0.1** to match the mesh.

**8.**  Select the **InteractableButton** GameObject and set its **Transform** component’s **Position** property to **X** = **0, Y** = **0.05,** and **Z** = **-0.4** so it sits near the table and within reach.

![](https://connect-mediagw.unity.com/h1/20251014/learn/images/f566f399-71c6-44de-ab38-c4907a566b96_6._scene-interactable-button-objects.png)

Your button is now positioned and visually styled.

## 6. Make the button pokeable

In this step, you’ll enable the button to respond visually to poke gestures using XR Hands.

**1.**  Select the **ButtonMesh** GameObject and set its **Transform** component’s **Position Y** property to **-0.025** to simulate the pressed position of the button.

This setup offsets the button mesh so that, once the XR Poke Follow Affordance is configured, the button appears in its unpressed starting position.

![](https://connect-mediagw.unity.com/h1/20251014/learn/images/951dbee8-a1c6-4511-9ab8-31fef28f9e35_7._scene-button-mesh-positioning.png)

**2.  Add XR Simple Interactable**, **XR Poke Filter**, and **XR Poke Follow Affordance** scripts components to the **InteractableButton** GameObject.

The **XR Simple Interactable** component enables Unity Events, the **XR Poke Filter** component is required for poke detection by the XR Hands prefab, and the **XR Poke Follow Affordance** component enables the mesh to move down during a poke.

**3.**  Use the dropdown (triangle) to expand the **Value section** of the **XR Poke Filter** component’s **Poke Settings**, then, set the **Poke Direction** property to **Negative Y**. Ensure the **Interactable** property is set to **InteractableButton, and** the **Poke Collider** property is set to **ButtonCollider.**

**4.**  Select the **XR Poke Follow Affordance** component’s **Poke Follow Transform** property picker (**⊙**) and select **ButtonOffset**, set the **Max Distance** property to **0.025**, enable the **Clamp to Max Distance** property.

![](https://connect-mediagw.unity.com/h1/20251014/learn/images/77d4b308-753a-476d-b3cd-54f16dbf316f_8._scene-interaction-component-settings.png)

The button now visually moves when poked using hand tracking.

## 7. Create the reset script

To reset the cube when the button is poked, you’ll create a script that restores the cube’s original position and rotation.

**1. Right-click** In the **Assets** folder, select **Create** > **Folder**, and name it “Scripts”.

**2.**  Right-click in the **Scripts** folder, select **Create** > **MonoBehaviourScript**, and name it “CubeResetController”.

**3.**  Copy and paste the following lines of code into the **CubeResetController script:**

```csharp
using UnityEngine;

public class CubeResetController : MonoBehaviour
{
    [SerializeField] private Rigidbody cubeRigidbody;

    private Pose originalCubePose;

    private void Awake()
    {
        if (cubeRigidbody == null)
        {
            Debug.LogError("CubeResetController: Rigidbody reference is missing.", this);
            return;
        }

        originalCubePose = new Pose(
            cubeRigidbody.transform.position,
            cubeRigidbody.transform.rotation
        );
    }

    public void ResetCube()
    {
        cubeRigidbody.linearVelocity = Vector3.zero;
        cubeRigidbody.angularVelocity = Vector3.zero;

        cubeRigidbody.transform.SetPositionAndRotation(
            originalCubePose.position,
            originalCubePose.rotation
        );

        cubeRigidbody.useGravity = false;
    }
}
```

**4.** Save the script.

This script stores the cube’s starting pose and includes a method to restore it.

## 8. Connect the button to the reset script

Now you'll use Unity Events to call the cube reset method when the button is poked.

**1.**  In the **Hierarchy** window, select the **InteractableButton** GameObject, add the **CubeResetController** script component, and click and drag the **InteractableCube** GameObject’s **Rigidbody** component into the **Cube Rigidbody** property box.

**2.**  In the **XR Simple Interactable** component, use the foldout (triangle) to expand the **Interactable Events** section**.**

**3.**  Under the **Select Entered** property, select the **Add** (**+**) button to add an event.

**4.**  Click and drag the **InteractableButton** GameObject into the **None (Object)** property box.

**5.**  Open the **No Function** dropdown and select **CubeResetController** > **ResetCube()**.

![](https://connect-mediagw.unity.com/h1/20251014/learn/images/9a0dea1e-be28-481b-be19-f122a5d4ade0_9._inspector-interactable-selected-event.png)

**6.**  Build and deploy the scene to your Android XR device (Revisit **Getting Started with Android XR in Unity** for a refresher on building to the device if needed), grab and throw the cube, then poke the button to reset it.


You’ve now completed a full XR interaction loop using hands and the XRI Toolkit.

## 9. Next steps _(Optional)_

Now that you’ve built a basic XR interaction scene, keep building by doing the following:

- Testing your scene with both hands and controllers and using the **XR Input Modality Manager** to react to input source changes
- Adding more interactive elements using components from the XR Interaction Toolkit.
- Experimenting with different types of interactables like sliders, toggles, or UI panels.
