Use augmented reality (AR) to pin a scene to a table or desk for easy exploration.
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
- Create a
TableTopSceneView
with an anchor point, translation factor, clipping distance, andSceneView
. - 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. - 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.
- Set the
clippingDistance
to clip the scene to the area you want to show. - Create a
SceneView
with a scene. To allow you to look at the content from below, set the base surface navigation constraint tounconstrained
.
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
// 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")!
}
}