On 3 November I bought an Android tablet. It is a Galaxy, with a Mali-G615 GPU and 4 GB of memory: the first Android I have ever bought with my own money.
I chose an everyday 4 GB model on purpose, not a high-end one. This is the kind of machine most people actually hold, and I wanted to see with my own eyes how well the globe runs on it.
Everything around me is Mac, iPhone and iPad. Working alone, you can only imagine the machines you do not have. Once one arrived, I could not keep my hands off it. 2.4 is the record of six days spent with that one tablet.
3 November: WebGPU ran
Until now Android started on WebGL2, just in case. In August one Android phone had reported the map going black while moving, so I had played it safe.
On the day the tablet arrived, I first made a GPU check page (/check/). It shows on one page whether the device takes WebGPU or WebGL2, its adapter, features and limits, and a test drawing. Nothing is sent anywhere.
I opened /japan/ on WebGPU, and it worked. PLATEAU buildings were even faster than on WebGL2. That same day Android started on WebGPU like every other platform, so the reflections, fog and other effects added in 2.3 can now be seen on Android too. If anything goes wrong, ?gl2=1 goes back to WebGL2.
Along the way, laptops now use the faster of their built-in and discrete GPUs (powerPreference defaults to "high-performance"). I checked it on a real Windows machine as well.
What only a real device shows
Once it runs, you want it to run well. Touching it on the tablet, I kept finding room to grow that the Mac never showed. The HUD (?hud=1) shows where each frame's time goes, part by part, and I went through them one by one like a treasure hunt.
- The resolution did not drop. Flying over PLATEAU took about 120 ms a frame, yet dynamic resolution stayed at full size. Tile-based GPUs can report less GPU time than they spend. Now real time over 50 ms is taken into account too.
- The main thread stopped for 800 ms. The function that samples elevation did not keep the tiles it read from IndexedDB, so tens of MB of tiles were read again at every move. It now keeps the last three.
- Nearby buildings smeared. The Earth is computed as a sphere of radius 1, so the w of nearby vertices came to about 1e-6, and Mali treated it as 0. Scaling clip space by 220 before handing it over removed the smear. The picture on the Mac does not change.
- Tiles went through the main thread. Tile geometry now goes straight from the tile worker to the render worker; the main thread only receives the index.
A lighter start
On the tablet the screen sometimes waited for a while after the first picture. The start-up timeline ([boot] timeline) showed the GPU process compiling shaders one at a time, 6–14 seconds in all, while the renderer waited.
So the globe and terrain are now drawn first, and the other layers appear as they become ready (progressive drawing). Only the pipelines needed now are built first; the rest come later. The freeze went from 6.5–6.9 s to 1.0–2.1 s. On Mali, unused shader branches are dropped when the shader is generated, which shortens compiling. Baked glyphs can also be kept in IndexedDB so the next start does not bake them again (?glyphdb=1).
From Kyoto to the whole of Japan
One of the demos glides in one go from the streets of Kyoto out to the whole Japanese archipelago. On the tablet the first 8 seconds ran at 8–10 fps.
One culprit was in an unexpected place. Whenever a frame was free, the map took itself to have "landed", even mid-flight, and rewrote the URL. Chrome on Android then redrew the address bar, which blocked the GPU process for 0.1–6 seconds: 102 times in 20 seconds, 11.4 seconds in all. Writing no URL during a flight and waiting until it lands raised the frame count from 167 to 227 (about 36% more).
The other was terrain. With terrain off it ran at about 60 fps. Now, only while moving, terrain is drawn with a coarser mesh. On 4 GB devices, the elevation that lines sample is lighter too.
From Marunouchi to the Rainbow Bridge
What remained last were the PLATEAU buildings. The glide from Marunouchi to the Rainbow Bridge ran at 12–18 fps for its first 6–8 seconds. The middle of Tokyo simply has that much to draw.
So the map now takes a few shortcuts, only while it moves. The full picture comes back the moment it stops, so what you look at does not change.
| Only while moving | Frames in glide seconds 4–12 |
|---|---|
| Skip low buildings (6 → 12 → 24 m) | 182, 240 → 280, 262 (about 30% more) |
| Drop small triangles (reordering only, no extra GPU memory) | 208 → 295 |
| Draw buildings with a lighter pixel shader | average 236 → 294 (about 25% more, ahead in all 3 alternating pairs) |
Note: all measured on the tablet (Mali-G615). They went in one after another, so each row starts from a different point. All three are now the default on every device. They only kick in while the camera moves and a frame takes over 40 ms, so nothing changes on a fast machine.
To games, and back to the globe
The other big newcomer is the link with games. There are three destinations: Unity, Unreal Engine and Minecraft. You can take a city from the globe into a game, and bring what you built in the game back to the globe.
What travels is terrain and PLATEAU buildings (for Unity and Unreal also the building attributes and point clouds), for an area of about two or three city blocks. Streaming tiles inside a game is already done by Cesium for Unity and the PLATEAU SDK for Unity, so this sticks to "cut it out and hand it over as files".
Just one agreement
All three are joined by one agreement. A point on the ground is chosen as the anchor (longitude, latitude, ellipsoidal height and a heading), and everything is given in metres east, north and up from it. The hand-over is a GLB with the anchor inside (asset.extras.orthoEarth). In Minecraft one block is 1 m and the anchor sits at block (0, 0, 0).
| Unity 6 | Unreal Engine 5.6+ | Minecraft | |
|---|---|---|---|
| Install | Plugin (Package Manager) | Plugin (zip into Plugins/) | Nothing (world files are written directly) |
| From the globe | Menu: Place export folder… | Same menu | ortho-minecraft bakes a world |
| To the globe | Export selection to GLB… | Same menu | An area or a diff, taken out as GLB |
| Axes and units | X east, Y up, Z north, m | X east, Y south, Z up, cm | X east, Y up, Z south, 1 block = 1 m |
| Building attributes | In the Inspector | In Details | — |
| Point clouds | PLY | LAS | — |
From the globe to a game
All three start from the same ortho-export. Export an area, and the anchor, terrain, buildings and the building attribute table land in one folder. Point clouds are read at /japan/pointcloud and saved as PLY or LAS.
In Unity and Unreal, choosing Place export folder… from the menu is all it takes: everything is laid out in the right place under the anchor. Each building can be selected by its PLATEAU gml_id and shows attributes such as use, height, address and flood risk; code can read them too, with b.Get("bldg:usage") or b.MeasuredHeight. PLATEAU's webp textures are re-baked to jpeg, which the engines can read.
For Minecraft the same folder goes to ortho-minecraft. Terrain and buildings are baked into blocks, the ground and roofs are painted with the blocks closest in colour to the aerial photo, and buildings get floors. Out come three things: a Java Edition world, a WorldEdit .schem and a Bedrock .mcworld, which opens with a double-click. The anchor is the spawn point, so the coordinates F3 shows are metres from the anchor. It opens in Creative, frozen at midday.
From a game back to the globe
The way back ends at the same door for all three. In Unity and Unreal, put the model under the anchor and choose Export selection to GLB…. In Minecraft, take the house you built out by area, or as the difference from the world you exported. Each becomes a GLB with the anchor inside.
Drop that GLB on /japan/ and it stands where it came from. A model made in Unity and a house built in Minecraft stand side by side in Marunouchi. map.model() also uses the GLB's anchor when no position is given. Large models can be turned into 3D Tiles with glbconv.
Checked in Marunouchi
All three samples are Marunouchi.
- Unity 6: the four corners of the placed terrain matched the exported area exactly, and the tallest building, 238 m, stood where Tokyo Midtown Yaesu is. A test point cloud with its anchor deliberately moved 158 m east and 139 m south came back with all four points within about 1 cm. Terrain exported again and read back matched the original in vertex count and extent.
- Unreal Engine 5.8.4: the same sample was used to check axis directions and point cloud positions. Nanite meshes export as they are.
- Minecraft: the world files are read and written with Node alone. Opened with another reader (Amulet), both the Java and Bedrock worlds matched block for block.
The Unity and Unreal plugins (both 0.1.0) are attached to the GitHub Release. Minecraft is part of ortho-export.
Also new
- Point clouds. Sheets are shown side by side without seams, the memory they use has a ceiling, and they can be filtered by class (
map.readPointCloud). PLY export for Unity. - Lines and terrain. In tilted 3D the edges of wide roads were eaten into by terrain and came out jagged, and nearby lines turned into a string of translucent beads. Both are fixed.
One tablet, faster for everyone
Over 130 changes went in during those six days. Most of what was added for the tablet became the default on every device. Nothing changes on a fast machine; the more modest the device, the more it helps. Choosing an everyday model was the right call. One Android tablet made the globe lighter for everyone.
Please try it on your own Android or Windows device. If anything looks wrong, a report with the result of /check/ attached helps a great deal.
It was not only about speed. Through those six days with Android, the work on Cesium did not stop. A fresh shoot of all 309 Sandcastle examples at the end (v259, v260) raised the same picture from 226 to 234. Examples that do not run stayed at 0.
| Shoot | 3 | 2 | 1 | 0 | What went in |
|---|---|---|---|---|---|
| v2.3.0 | 226 | 77 | 0 | 0 | The last count before |
| v2.4.0 | 234 | 69 | 0 | 0 | Shapes on terrain, classifying 3D Tiles, Cesium's way of choosing tiles, outlines on lines and points |
Note: 303 examples including those checked by eye (on a real Mac GPU). 3 = same picture, 2 = same answers, 1 = runs, 0 = does not run. Every picture is in the Sandcastle gallery, side by side with the original. The MapLibre official examples were shot again the same day and held at 91 / 43 / 3 / 0.
- Shapes on terrain. GroundPrimitive polygons were placed at 0 m and buried inside the 2.5 km Mount St. Helens. Their outlines are now rebuilt from the triangles and painted along the terrain. A fill on terrain that hid under Cesium's imagery is fixed too.
- Classifying 3D Tiles. ClassificationPrimitive boxes for trees and buildings were drawn as translucent solids. Now only the 3D Tiles surfaces inside a box are coloured.
- Cesium's way of choosing tiles. For Cesium's imagery layers only, the distance to a tile is now measured to its point nearest the eye. Keeping the small tiles in front of ridges brought the fog example from 56.6% to 95.0% and the point cloud example from 58.2% to 91.7% of the real thing.
- Lines and points. Entity outlines are 1 px like Cesium's, path outlines (polylineOutline) and glow (PolylineGlow's thin core and soft halo) are drawn, and point outlines sit outside pixelSize. A cos φ applied twice when choosing imagery detail is fixed.
On a globe that runs light on an everyday device, Cesium code came one more step closer to the real picture.
And on to v3
With this, the work on v2 is nearly done. I have started to think about v3. WebGPU now works in almost every browser: Chrome and Edge on computers, Chrome on Android, and Safari on iPhone, iPad and Mac (from 26). Firefox is getting there too. And these six days showed that it runs well enough on an everyday device. Until now I have kept everything working the same on WebGL2, and that has held back what the globe could do. For v3 I am thinking of dropping WebGL2 and going WebGPU only. The API will stay the same, so today's code keeps running. It is planned for the end of the year. Stay tuned.
Published: @ortho-earth/globe and @ortho-earth/core 2.4.0, @ortho-earth/cesium 0.3.0 (globe 2.4 or later), @ortho-earth/voxel 0.6.2, glbconv 0.3.0, and the Unity and Unreal plugins 0.1.0. Same API as 2.3 (npm i @ortho-earth/[email protected]). The knobs that restore the old way of drawing while moving (?meshshed=0 and others) and ?gl2=1 to go back to WebGL2 on Android are still there.