Skip to main content

Use a 3D model to show the user's location

This example demonstrates a custom 3D puck implementation using the Mapbox Maps SDK for iOS. The code sets up a MapView with a specific initial camera view and listens for the style to load before configuring the 3D puck. The 3D puck is customized with a 3D model sourced from a gltf asset (in this case, "sportcar.glb") and additional settings including the model scale and opacity. The puck is then configured to display on the map with bearing information and bearing updates enabled. Whenever there is a change in the user's location, the camera smoothly adjusts to focus on the new location with a specific zoom, bearing, and pitch. The implementation utilizes classes such as CameraOptions, Model, and Puck3DConfiguration provided by the SDK.

Troubleshooting with the iOS simulator

If you cannot see the location puck while testing in the iOS simulator, try the following:

  • Simulate a location in Xcode by going to Debug > Simulate Location and select a location. Then, return to the Simulator and the location puck should appear over the selected location.
  • If you already declined location permissions for your application you can update permission in Settings. Go to Settings > Privacy & Security > Location Services. Then find your application and update the location access to "Always" or "While Using the App".
iOS Examples App Available

This example code is part of the Maps SDK for iOS Examples App, a working iOS project available on Github. iOS developers are encouraged to run the examples app locally to interact with this example in an emulator and explore other features of the Maps SDK.

See our Run the Maps SDK for iOS Examples App tutorial for step-by-step instructions.

Custom3DPuckExample.swift
import UIKit
import MapboxMaps

final class ViewController: UIViewController {
private var cancelables = Set<AnyCancelable>()
private var mapView: MapView!

override func viewDidLoad() {
super.viewDidLoad()

let cameraOptions = CameraOptions(center: CLLocationCoordinate2D(latitude: 37.26301831966747, longitude: -121.97647612483807), zoom: 15, pitch: 55)
mapView = MapView(frame: view.bounds, mapInitOptions: MapInitOptions(cameraOptions: cameraOptions))
mapView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
view.addSubview(mapView)

mapView.mapboxMap.onStyleLoaded.observeNext { _ in
self.setupExample()
}.store(in: &cancelables)
}



private func setupExample() {

// Fetch the `gltf` asset
let uri = Bundle.main.url(forResource: "sportcar", withExtension: "glb")

// Instantiate the model
let myModel = Model(uri: uri, orientation: [0, 0, 180])

let configuration = Puck3DConfiguration(
model: myModel,
modelScale: .constant([10, 10, 10]),
modelOpacity: .constant(0.5),
layerPosition: .default
)
mapView.location.options.puckType = .puck3D(configuration)
mapView.location.options.puckBearing = .course
mapView.location.options.puckBearingEnabled = true

mapView.location.onLocationChange.observeNext { [weak mapView] newLocation in
guard let location = newLocation.last, let mapView else { return }
mapView.camera.ease(
to: CameraOptions(
center: location.coordinate,
zoom: 15,
bearing: 0,
pitch: 55),
duration: 1,
curve: .linear,
completion: nil)
}.store(in: &cancelables)
}
}
Was this example helpful?