This one is really easy to reproduce, in an emulator and on a real device.
.NET MAUI app, .NET 10, latest runtime with SceneView, loading an ArcGISTiledElevationSource terrain source from https://elevation3d.arcgis.com/arcgis/rest/services/WorldElevation3D/Terrain3D/ImageServer - first SceneView works fine, shows 3D mountains and such. Any subsequent SceneView claims to load the elevation source, but the map renders flat.
I've attempted a number of workarounds, e.g. removing and re-adding the source. No luck. It only works once per process.
Any ideas?
Hello, thanks for the report! Would you mind sharing the exact code that leads to this behavior? I'm not able to reproduce with the below code in 300.0.0. When clicking the button I see the terrain go flat on the first scene and move to the second as expected.
I'll note that a layer object cannot be held by two different scene objects, so you should get an error if you add the elevation source to a second scene without having removed it from the first.
public partial class MainPage : ContentPage
{
private ArcGISTiledElevationSource? _source;
public MainPage()
{
InitializeComponent();
_ = Initialize();
}
private async Task Initialize()
{
try
{
_source = new ArcGISTiledElevationSource(new Uri("https://elevation3d.arcgis.com/arcgis/rest/services/WorldElevation3D/Terrain3D/ImageServer"));
var scenea = new Scene(BasemapStyle.ArcGISImageryStandard);
scenea.BaseSurface.ElevationSources.Add(_source);
var sceneb = new Scene(BasemapStyle.ArcGISImageryStandard);
SceneViewA.Scene = scenea;
SceneViewB.Scene = sceneb;
}
catch (Exception ex)
{
Debug.WriteLine(ex.ToString());
}
}
private void Button_Clicked(object sender, EventArgs e)
{
try
{
SceneViewA.Scene!.BaseSurface.ElevationSources.Clear();
SceneViewB.Scene!.BaseSurface.ElevationSources.Add(_source!);
}
catch (Exception ex)
{
Debug.WriteLine(ex.ToString());
}
}
}
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<esri:SceneView x:Name="SceneViewA" />
<esri:SceneView x:Name="SceneViewB" Grid.Column="1" />
<Button Text="Switch" Clicked="Button_Clicked" VerticalOptions="End" HorizontalOptions="Start" Grid.ColumnSpan="2"/>
</Grid>
@imalcolm_esri: thanks for your response.
I've spent hours today attempting to isolate a nice repro for you, but I've been unable to do so. I attempted to add some confounding factors from my app such as the SceneView being instantiated in code (not XAML), the page in question being a TabbedPage, rendering some Graphics, etc. No luck, sadly.
I'll paste in my app's initialization code below. I doubt it will help.
I remain able to easily repro in my app. On a physical device, I have to switch from the ESRI handler to Google Maps and back, and that kills 3D rendering pretty quickly for the lifetime of the process. Restarting restores 3D.
In an Android emulator I don't even have to do that: just enter/leave a page that displays a SceneView a few times and after 3-4 tries it will no longer render in 3D. Again, once if fails it never works again.
Is there a way I can give you private access to my app?
async Task InitializeSceneViewAsync(IMapControlHandler source, GeoView existing)
{
const string elevationUrl = "https://elevation3d.arcgis.com/arcgis/rest/services/WorldElevation3D/Terrain3D/ImageServer";
ElevationSource elevationSource = new ArcGISTiledElevationSource(new Uri(elevationUrl));
Surface surface = new() { ElevationExaggeration = 1.25 };
surface.ElevationSources.Add(elevationSource);
Viewpoint initialVp = source != null ? await ToInitialSceneViewpointAsync(source) : existing.TryGetCurrentViewpoint(ViewpointType.CenterAndScale);
this.sceneView = new()
{
InteractionOptions = new() { ZoomFactor = 1.75 },
Scene = new(new Basemap()) { BaseSurface = surface, InitialViewpoint = initialVp },
IsAttributionTextVisible = false,
#if WINDOWS_UWP
HorizontalAlignment = HorizontalAlignment.Stretch,
VerticalAlignment = VerticalAlignment.Stretch,
#elif NET_MAUI
HorizontalOptions = LayoutOptions.Fill,
VerticalOptions = LayoutOptions.Fill,
#endif
};
this.grid.Children.Add(this.sceneView);
if (existing != null)
{
CopyOverlays(existing, this.sceneView);
await this.SetMapTileServiceAsync(this.MapTileService);
MapTileService[] overlays = this.overlays.Count > 0 ? [.. this.overlays] : [];
foreach (MapTileService overlay in overlays)
await this.AddOverlayAsync(overlay);
}
Task surfaceLoadTask = elevationSource.LoadAsync();
this.sceneView.DrawStatusChanged += OnDrawStatusChanged;
async void OnDrawStatusChanged(object _, DrawStatusChangedEventArgs args)
{
if (args.Status == DrawStatus.Completed)
{
this.sceneView.DrawStatusChanged -= OnDrawStatusChanged;
try
{
await surfaceLoadTask;
ElevationSource source = this.sceneView.Scene.BaseSurface.ElevationSources.FirstOrDefault();
Log.Debug($"[{GetType().Name}] Loaded elevation source {source?.Name} - LoadStatus: {source?.LoadStatus}, IsEnabled: {source?.IsEnabled}");
}
catch (HttpRequestException e)
{
Log.Warn($"[{GetType().Name}] Unable to load elevation source", e, e.Message);
}
catch (Exception e)
{
Log.Warn($"[{GetType().Name}] Unable to load elevation source", e);
}
if (source != null)
{
Viewpoint vp = await this.ToInitialSceneViewpointAsync(source);
await this.sceneView.SetViewpointAsync(vp);
}
this.MapLoadingStatus = MapLoadingStatus.Loaded;
this.MapLoadingStatusChanged?.Invoke(this, EventArgs.Empty);
}
}
}
Hi @mfeingol, thanks for taking the time to figure out a repro case. The code you provided was helpful! I'm able to reproduce when repeatedly recreating a new SceneView each iteration. That could mean you can work around the issue by making sure you reuse the same SceneView each time, assuming that's not already the case and that there aren't any other factors involved. Another thing I noticed is in the below app I can fix the problem by ensuring the previous SceneView is removed from the grid each iteration (see the comment in the Button_Clicked function).
If the above doesn't help the issue, go ahead and send me a link to your github repo (or equivalent) at [email protected]. I'll take a closer look at figuring out where this is coming from, and see if I or someone else can figure out a fix. (*That said, we are close to the next release, so even if we can find a fix it probably won't become available until the release after.)
Repro main page: Note that clicking the button too fast can cause a probably-unrelated threading crash in Mono
public partial class MainPage : ContentPage
{
private Scene? _scene;
public MainPage()
{
InitializeComponent();
_ = Initialize();
}
private async Task Initialize()
{
try
{
_scene = new Scene(BasemapStyle.ArcGISImageryStandard);
var source = new ArcGISTiledElevationSource(new Uri("https://elevation3d.arcgis.com/arcgis/rest/services/WorldElevation3D/Terrain3D/ImageServer"));
_scene.BaseSurface.ElevationSources.Add(source);
var startPoint = new MapPoint(-72.5, -48.7, 1000, SpatialReferences.Wgs84);
var initialViewpoint = new Viewpoint(startPoint, new Camera(startPoint, 270, 90, 0));
_scene.InitialViewpoint = initialViewpoint;
MainSceneView.Scene = _scene;
}
catch (Exception ex)
{
Debug.WriteLine(ex.ToString());
}
}
private async void Button_Clicked(object sender, EventArgs e)
{
try
{
MainGrid.Children.Remove(MainSceneView); // Comment this line out to reproduce after ~30 taps
MainSceneView.Scene = new();
MainSceneView = new() { Scene = _scene, };
MainGrid.Children.Add(MainSceneView);
}
catch (Exception ex)
{
Debug.WriteLine(ex.ToString());
}
}
}