Display a 3D model in a model layer
The ModelLayer
API is experimental and may still change in a future version of the SDK.
This example demonstrates how to use the ModelLayer
class from the Mapbox Maps SDK for iOS to add 3D models to a map visualization in
an iOS application. In this scenario, two models, a duck and a car,
are displayed on the map using a GeoJSON data source created at runtime.
The ModelLayer
is configured with specific settings such as model ID, type, scale, translation,
rotation, and opacity. Additionally, the code includes the creation of Model
instances for the duck and car, association of these models with a GeoJSONSource
,
and finally the instantiation of the ModelLayer
to visualize the models according
to the provided settings.
The duck model is sourced from a remote URL, while the car model is loaded from a local file within the app bundle. By following this implementation, developers can incorporate 3D models into their Mapbox-based iOS applications, enriching the map visualization with custom 3D content.
Read more about the Model layer in the Style Documentation.
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.
import UIKit
@_spi(Experimental) import MapboxMaps
@objc(ViewController)
final class ViewController: UIViewController {
private var mapView: MapView!
override func viewDidLoad() {
super.viewDidLoad()
let cameraOptions = CameraOptions(
center: mid(Constants.duckCoordinates.coordinates, Constants.mapboxHelsinki.coordinates),
zoom: 16,
pitch: 45
)
let options = MapInitOptions(cameraOptions: cameraOptions)
mapView = MapView(frame: view.bounds, mapInitOptions: options)
mapView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
mapView.ornaments.options.scaleBar.visibility = .visible
/// Create a Feature to hold the coordinates of the duck and car.
/// Both Features will be added to a GeoJSONSource below as a feature collection
var duckFeature = Feature(geometry: Constants.duckCoordinates)
duckFeature.properties = [Constants.modelIdKey: .string(Constants.duckModelId)]
var carFeature = Feature(geometry: Constants.mapboxHelsinki)
carFeature.properties = [Constants.modelIdKey: .string(Constants.carModelId)]
if #available(iOS 13, *) {
mapView.mapboxMap.setMapStyleContent {
/// Add Models for both the duck and car using an id and a URL to the resource
Model(id: Constants.duckModelId, uri: Constants.duck)
Model(id: Constants.carModelId, uri: Constants.car)
/// Add a GeoJSONSource to the map and add the two features with geometry information
GeoJSONSource(id: Constants.sourceId)
.data(.featureCollection(FeatureCollection(features: [duckFeature, carFeature])))
/// Add a Model visualization layer which displays the two models stored in the GeoJSONSource according to the set properties
ModelLayer(id: "model-layer-id", source: Constants.sourceId)
.modelId(Exp(.get) { Constants.modelIdKey })
.modelType(.common3d)
.modelScale(x: 40, y: 40, z: 40)
.modelTranslation(x: 0, y: 0, z: 0)
.modelRotation(x: 0, y: 0, z: 90)
.modelOpacity(0.7)
}
}
view.addSubview(mapView)
}
}
extension ViewController {
private enum Constants {
static let mapboxHelsinki = Point(CLLocationCoordinate2D(latitude: 60.17195694011002, longitude: 24.945389069265598))
static let duckCoordinates = Point(CLLocationCoordinate2D(latitude: mapboxHelsinki.coordinates.latitude + 0.002, longitude: mapboxHelsinki.coordinates.longitude - 0.002))
static let modelIdKey = "model-id-key"
static let sourceId = "source-id"
static let duckModelId = "model-id-duck"
static let carModelId = "model-id-car"
static let duck = URL.init(string: "https://raw.githubusercontent.com/KhronosGroup/glTF-Sample-Models/master/2.0/Duck/glTF-Embedded/Duck.gltf")
static let car = Bundle.main.url(forResource: "sportcar", withExtension: "glb")!
}
}