Develop

3D Object sample with Interaction SDK

Updated: May 7, 2026

Overview

This sample demonstrates how to integrate Interaction SDK (ISDK) with physics-enabled 3D object spawning, manual physics state management during grab interactions, and hover affordances. Developers learn to implement custom ISDK input listeners, manage physics state transitions during grab/release, add collision bounds with SpatialBox, and combine Compose UI panels with ISDK-resizable layout panels.

What you will learn

  • Implement ISDK input listeners with semantic filtering for grab-specific pointer events
  • Manage manual physics state transitions (DYNAMIC → KINEMATIC → DYNAMIC) during object grab/release
  • Add hover affordances by scaling objects on Hover/Unhover events
  • Attach collision bounds to spawned objects using the SpatialBox component
  • Register Compose UI panels and ISDK-resizable layout panels in the same scene

Requirements

  • Meta Quest 2, Quest 3, or Quest 3S device
  • Android development environment with Android Studio
For detailed build prerequisites and SDK versions, see the Object3DSampleIsdk README.

Get started

Clone the Meta Spatial SDK Samples repository, open the Object3DSampleIsdk project in Android Studio, and build to your Quest device. When you run the sample, you see a library panel displaying six 3D objects (robot, drone, plant, desk lamp, easy chair, sculpture). Select an object to spawn a physics-enabled instance into the virtual collaboration room. Grab spawned objects with hand tracking or controllers; they scale slightly on hover and maintain physics momentum after release.

Explore the sample

File / SceneWhat it demonstratesKey concepts
Main activity with ISDK input listener registration, scene loading, feature setup
AppSystemActivity, IsdkInputListenerSystem, InputListener, PhysicsFeature, GLXFManager
Compose UI panel with object spawning logic, spawn animation, SpatialTheme
ComposeViewPanelRegistration, Entity creation, ValueAnimator, OvershootInterpolator
Main.scene
Scene composition with library panel, six spawnable objects, and collaboration room environment
Scene hierarchy, Transform, Mesh, Grabbable, Physics, SpatialBox
scrolling.xml
Layout for ISDK-resizable scroll panels
LayoutXMLPanelRegistration, IsdkPanelResize, ResizeMode

Runtime behavior

When you run this sample, you see a library panel floating in front of you with thumbnails for six 3D objects. The collaboration room environment surrounds you — a furnished indoor space with glass walls, cushioned seating, and wood-textured surfaces, all backed by static physics collision so spawned objects interact with the room geometry. Select an object thumbnail to spawn an instance at a fixed spawn point (y=1.2m, z=2.1m); the object animates from scale 0 to full size with an overshoot effect. Hover your hand or controller over a spawned object to see it scale up slightly (+0.05 on each axis). Grab the object to pick it up; during the grab, physics simulation pauses (KINEMATIC state). Release the object to restore physics simulation (DYNAMIC state); the object carries forward with momentum from your release motion. The drone continuously plays its propeller animation. Two decorative scroll panels demonstrate ISDK resize functionality; one uses ResizeMode.Relayout.

Key concepts

ISDK input listener with semantic filtering

The sample registers a custom InputListener via IsdkInputListenerSystem.setInputListener(). The listener filters pointer events by SemanticType.Grab, ignoring non-grab interactions:
if (semanticType != SemanticType.Grab.id) return
when (type) {
    PointerEventType.Select.id -> { /* grab started */ }
    PointerEventType.Unselect.id -> { /* grab ended */ }
}
See Object3DSampleIsdkActivity.kt for the full listener implementation. For API details, see InputListener.

Manual physics state management during grab

Unlike the engine-managed physics grab (enabled via PhysicsFeature.useGrabbablePhysics = true), this sample sets useGrabbablePhysics = false and manually controls physics state. On Select, the sample saves the original physics state and sets the object to PhysicsState.KINEMATIC, preventing physics simulation during the grab. On Unselect, it restores the saved state to PhysicsState.DYNAMIC, allowing the object to carry momentum from the release motion:
// Save state, go KINEMATIC
savedState = physics.state
physics.state = PhysicsState.KINEMATIC

// Restore DYNAMIC on release
physics.state = savedState
This manual approach gives developers precise control over physics behavior during interaction. See Object3DSampleIsdkActivity.kt for the state management logic. For PhysicsState values, see Physics reference.

Collision bounds with SpatialBox

Each spawned object includes a SpatialBox component defining collision bounds. The sample computes an inverse scale so the box dimensions remain correct regardless of the object’s scale factor:
val invScale = Vector3(1f / scale.x, 1f / scale.y, 1f / scale.z)
SpatialBox(min = dimensions * invScale * -1f, max = dimensions * invScale * 1f)
See PanelLayout.kt (setUpButton() function) for the box creation logic.

Object spawning with animation

The setUpButton() function reads mesh URI and scale from a glXF template entity, then creates a new Entity with Mesh, Grabbable, SpatialBox, Scale, Physics, and Transform components. The spawn animation uses ValueAnimator with OvershootInterpolator(1f) and a 1000ms duration, animating the Scale component from zero to the target scale.
See PanelLayout.kt for the spawning and animation implementation. For grabbable configuration, see Grabbable reference.

ISDK panel resize

The sample registers two scroll panels via LayoutXMLPanelRegistration and applies IsdkPanelResize to enable ISDK-based resizing. One panel uses ResizeMode.Relayout; the other uses the default mode. This demonstrates how to add ISDK resize affordances to XML-based panels.
See Object3DSampleIsdkActivity.kt and scrolling.xml for the panel registration and layout.

Extend the sample

  • Change the physics material: Switch from PhysicsMaterial.WOOD to experiment with different friction and restitution values.
  • Add custom hover effects: Go beyond scaling with color changes or particle systems on hover.
  • Implement object deletion: Detect throw gestures or add a UI button to remove spawned objects.
For a non-ISDK comparison, see the Object3DSample. For advanced physics interactions, see the PhysicsSample.