ArcGIS Blog

3D Visualization & Analytics

Developers

SceneView Improvements in ArcGIS Maps SDKs for Native Apps 300.0

By Koushik Hajra

The 300.0 release of ArcGIS Maps SDKs for Native Apps introduces an array of new functionality across our 3D stack. Alongside the introduction of the new LocalSceneView, this release also delivers a set of targeted enhancements that make working with the existing SceneView faster, smoother, and more capable.

This release introduces support for rendering KmlPhotoOverlay, a new Surface API for efficiently retrieving elevation data, and performance improvements that streamline demanding workflows—such as identifying feature layers in high density datasets. Together, these updates improve user experience while unlocking richer 3D experiences.

Below, we take a closer look at what’s new and how these improvements can benefit your applications.

A quick note: While some of the code snippets below show code from Qt Maps SDK, the principles broadly apply to .NET, Swift, Kotlin, and Flutter Maps SDKs (except KmlPhotoOverlay. Kml support will be added in a future release of the Flutter SDK).  

Rendering of KmlPhotoOverlay

SceneView now supports rendering KmlPhotoOverlay when present in a KML document. A KmlPhotoOverlay allows a photograph to be precisely positioned in geographic space, aligning imagery directly with its real‑world location.

This unlocks several practical workflows, including:

  • Visually correlating imagery with terrain
  • Performing contextual analysis using one or more georeferenced photos

In short, you can now seamlessly integrate spatially accurate KmlPhotoOverlays into your 3D scenes.

Let’s see what this looks like in code.

 


if (auto *photoOverlay = findPhotoOverlayRecursive(document)) {
    m_sceneView->setViewpointCameraAsync(Camera(photoOverlay->viewpoint().location(),
          photoOverlay->viewpoint().heading(),
          photoOverlay->viewpoint().pitch(),
          photoOverlay->viewpoint().roll()));
    }

KmlPhotoOverlay *PhotoOverlayTest::findPhotoOverlayRecursive(KmlNode *node)
{
    if (!node)
        return nullptr;

    // Found PhotoOverlay. Return it.
    if (node->kmlNodeType() == KmlNodeType::KmlPhotoOverlay)
        return dynamic_cast<KmlPhotoOverlay *>(node);

    // Only container-like nodes have children.
    if (auto *container = dynamic_cast<KmlContainer *>(node)) {
        auto *children = container->childNodesListModel();
        if (!children)
            return nullptr;

        for (int i = 0; i < children->size(); ++i) {
            if (auto *found = findPhotoOverlayRecursive(children->at(i)))
                return found;
        }
    }

    return nullptr;
}

A KmlPhotoOverlay showing Esri Headquarters, Redlands.

ApplyElevationAsync method on Surface class

Before the 300.0 release, retrieving elevation data required calling getElevationAsync() one point at a time, using the topmost loaded elevation source, and returning the best possible Z value per request. While functional, this approach quickly became inefficient—and cumbersome—when working with multiple points, such as generating an elevation profile along a path.

To address this, we introduced a new Surface API: applyElevationAsync().

In a single operation, this method returns a copy of the geometry with the best possible Z values populated for every vertex. The benefits are immediate:

  • A simpler, more expressive API for elevation workflows
  • Improved performance through batching
  • Order‑of‑magnitude speed improvements in many scenarios

Pro tip: Since applyElevationAsync returns a copy of the input geometry, it might be simpler to use that instead of getElevationAsync even if your workflow involves a single point. Using getElevationAsync, if you need the same point geometry again, you need to reconstruct the point geometry with the returned Z value.

Below is a simple code example, followed by a video demonstrating the performance gains in action.


// create two point geometries
    const Point p1(-157.81576537139006, 21.264810165716789, SpatialReference::wgs84());
    const Point p2(-157.80740661838993, 21.263212689250874, SpatialReference::wgs84());

    // create a polyline using the points from above
    PolylineBuilder *pb = new PolylineBuilder(SpatialReference::wgs84(), this);
    pb->addPoints(QList<Point>() << p1 << p2);
    m_polyline = pb->toPolyline();
    
    // get a densified polyline with 100 vertices
    const auto densePolyline = static_cast<Polyline>(densifyPolylineGeodetic(m_polyline, 100));
    
    // call applyElevationAsync using the densified polyline
    auto future
        = m_scene->baseSurface()->applyElevationAsync(densePolyline).then(this, [this](Geometry g) {
              // the returned polyline has a Z value added for each of the 100 vertices.
              const auto densePolylineElev = static_cast<Polyline>(g);
              // use each vertex as your geometry to create an elevation profile...
          });

// function to create a densified polyline
Polyline ElevationProfileTest::densifyPolylineGeodetic(const Polyline& polyline, double numPoints) {

    // determines the distance between each point that will be needed to input into densifyGeodetic() based off NumPoints
    const double incrementalDistance = GeometryEngine::lengthGeodetic(polyline, LinearUnit(LinearUnitId::Meters), GeodeticCurveType::Geodesic) /
                                 (numPoints - m_vertices.size());

    return static_cast<Polyline>((GeometryEngine::densifyGeodetic(polyline, incrementalDistance,
                                            LinearUnit(LinearUnitId::Meters), GeodeticCurveType::Geodesic)));
}

Generating an elevation profile using applyElevation

Realistic stars

We made an aesthetic improvement to the SceneView by adding realistic stars to the background. The background responds to date and time changes set on the SceneView. This adds temporal realism to scenes, enabling you to create more context-aware 3D experiences.

The video below demonstrates the visual update and how it responds to the current time of the day.

Realistic stars responding to change of time of the day.

Performance improvements

Beyond the new features highlighted above, this release delivers meaningful performance gains across the scene and SceneView. These improvements significantly enhance responsiveness and overall user experience. Some of the key performance enhancements are highlighted below

Performance of 3D Tiles layer using the Google Photorealistic Tiles

Support for 3D Tiles has been available for some time, but prior to 300.0, rendering massive datasets—such as Google Photorealistic Tiles—could become a performance bottleneck.

In this release, we made rendering optimizations that greatly improve performance and responsiveness when working with Google Photorealistic 3D Tiles. The result is a noticeably smoother, faster, and more immersive experience, even when visualizing dense, city‑scale data. With these improvements you can now confidently include Google Photorealistic Tiles in your native apps to take advantage of the rich detail they deliver.

The video below highlights this improvement in action.

Google Photorealistic Tiles added as an Ogc3DTilesLayer.

Faster Identify in Scenes containing Dense FeatureLayers

Identify performance in SceneView has also been significantly improved for scenarios involving very high data density. While the change may be subtle with smaller datasets, the impact becomes clear at scale. In our testing, a scene with over 7 million features across 60 or more layers experienced up to 30% reduction in an identify response and retrieving the popup information across all the layers.

These improvements make Identify more responsive and reliable, helping users interact fluidly with even the most complex 3D scenes.

Conclusion

The 300.0 release reinforces our commitment to making SceneView faster, simpler, and more capable at scale. For you, this means better visual fidelity, simpler elevation workflows, and noticeably faster interactions—even at city scale. These improvements enhance existing SceneView workflows and complement other 300.0 additions, including the new LocalSceneView and BuildingSceneLayer support.

If you’re deciding which view best fits your use case, this blog walks through the key differences and recommended workflows. We’re excited to see the experiences you build with these improvements and look forward to continuing the conversation through your feedback.

If you are ready to put these improvements into practice explore the resources below to start building with the latest SceneView enhancements in Native Maps SDK 300.0.

Upgrade to 300.0 and start building faster, more immersive 3D experiences today.

Share this article

Leave a Reply