Augment reality to show tabletop scene

View on GitHub

Use augmented reality (AR) to pin a scene to a table or desk for easy exploration.

Image of augment reality to show tabletop scene

Use case

Tabletop scenes allow you to use your device to interact with scenes as if they are 3D-printed models sitting on your desk. You could use this to virtually explore a proposed development without needing to create a physical model.

How to use the sample

You'll see a feed from the camera when you open the sample. Tap on any flat, horizontal surface (like a desk or table) to place the scene. With the scene placed, you can move the camera around the scene to explore. You can also pan and zoom with touch to adjust the position of the scene.

How it works

  1. Create a TableTopSceneView with an anchor point, translation factor, clipping distance, and SceneView.
  2. For this sample, the anchorPoint is set to the center of the scene for best results. This will give the impression that the scene is centered on the location the user tapped.
  3. Set the translationFactor on the scene view such that the user can view the entire scene by moving the device around it. The translation factor defines how far the virtual camera moves when the physical camera moves.
    • A good formula for determining translation factor to use in a tabletop map experience is translationFactor = sceneWidth / tableTopWidth. The scene width is the width/length of the scene content you wish to display in meters. The tabletop width is the length of the area on the physical surface that you want the scene content to fill. For simplicity, the sample assumes a scene width of 800 meters.
  4. Set the clippingDistance to clip the scene to the area you want to show.
  5. Create a SceneView with a scene. To allow you to look at the content from below, set the base surface navigation constraint to unconstrained.

Relevant API

  • SceneView
  • Surface
  • TableTopSceneView

Offline data

This sample uses offline data, available as an item on ArcGIS Online.

About the data

This sample uses the Philadelphia Mobile Scene Package. It was chosen because it is a compact scene ideal for tabletop use. Note that tabletop mapping experiences work best with small, focused scenes. The small, focused area with basemap tiles defines a clear boundary for the scene.

Additional information

Tabletop AR is one of three main patterns for working with geographic information in augmented reality. Augmented reality is made possible with the ArcGIS Maps SDK Toolkit.

Tags

augmented reality, drop, mixed reality, model, pin, place, table-top, tabletop

Sample Code

AugmentRealityToShowTabletopSceneView.swift
Use dark colors for code blocksCopy
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
// Copyright 2023 Esri
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//   https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

import ArcGIS
import ArcGISToolkit
import SwiftUI

@available(macCatalyst, unavailable)
struct AugmentRealityToShowTabletopSceneView: View {
    /// The scene used to create the scene view.
    @State private var scene = ArcGIS.Scene()

    /// The error shown in the error alert.
    @State private var error: Error?

    /// The location point of the scene that will be anchored on a physical surface.
    private let anchorPoint = Point(
        latitude: 39.95787000283599,
        longitude: -75.16996728256345
    )

    /// The translation factor that defines how much the scene view translates as the device moves.
    private let translationFactor = {
        // The width of the scene, which is about 800 m.
        let geographicContentWidth = 800.0

        // The physical width of the surface the scene will be placed on in meters.
        let tableContainerWidth = 1.0

        return geographicContentWidth / tableContainerWidth
    }()

    var body: some View {
        // Create a tabletop scene view using a scene view.
        TableTopSceneView(
            anchorPoint: anchorPoint,
            translationFactor: translationFactor,
            clippingDistance: 400
        ) { _ in
            SceneView(scene: scene)
        }
        .task {
            do {
                // Load a mobile scene package from a URL.
                let package = MobileScenePackage(fileURL: .philadelphia)
                try await package.load()

                // Set up the scene using first scene in the package.
                if let scene = package.scenes.first {
                    // Create an elevation source from a URL and add to the scene's base surface.
                    let elevationSource = ArcGISTiledElevationSource(url: .worldElevationService)
                    scene.baseSurface.addElevationSource(elevationSource)

                    // Set the navigation constraint to allow you to look at the scene from below.
                    scene.baseSurface.navigationConstraint = .unconstrained

                    // Update the scene for the scene view.
                    self.scene = scene
                }
            } catch {
                // Present the error loading the mobile scene package.
                self.error = error
            }
        }
        .errorAlert(presentingError: $error)
    }
}

private extension URL {
    /// A URL to mobile scene package of Philadelphia, Pennsylvania on ArcGIS Online.
    static var philadelphia: Self {
        Bundle.main.url(forResource: "philadelphia", withExtension: "mspk")!
    }

    /// A URL to world elevation service from Terrain3D ArcGIS REST service.
    static var worldElevationService: Self {
        .init(string: "https://elevation3d.arcgis.com/arcgis/rest/services/WorldElevation3D/Terrain3D/ImageServer")!
    }
}

Your browser is no longer supported. Please upgrade your browser for the best experience. See our browser deprecation post for more details.