Winter update on Shade Map

This winter, coding Shade Map took lowest priority behind skiing, climbing and reading on the couch. I ran into some large technical challenges which I was unable to tackle in a single coding session (more on this at the end) and did a poor job of breaking them down into manageable chunks. This led to a few marathon coding sessions where I could not quite get across the line and ended up throwing most of the code away and starting from scratch. I should have documented/salvaged things that worked. But first, the good news…

Traffic #

Screenshot 2021-03-29 at 10.07.53.png

I had over 400 visitors in the past 3 months. The two noticeable spikes were a mention on Hacker News under a “What are you currently working on” thread. Most other traffic is coming via my react-leaflet-canvas-overlay NPM package where Shade Map is listed as an example in the README. In Google search results for “shademap” already list the website on the first page, but the website does not come up in the search results for “shade map” (two words) at all. I’m a bit stumped by this.

Two major bug fixes last month increased the average time people spend on the site. The first existed from the earliest days and broke the website for all visitors whose clocks were not in MM/DD/YYYY format, effectively all visitors from outside the USA. If it wasn’t for somebody’s comment on Hacker News, I would have never even known the bug existed. The other bug broke the website on GPU’s that had less the 32-bit floats. My MacBook/iPad Pro/iPhone SE use 32-bit floats, but luckily you can still force iPads/iPhones to use 16-bit floats and I used my iPad Pro to debug and fix this issue. Once again, I only knew it was a bug because a user messaged me. It might be time for a feedback widget.

Open Source #

I used gpu.js library for the first release of Shade Map. It compiles Javascript into WebGL shaders. It allowed me to write calculations in familiar, but slow Javascript and then have it compile to OpenGL and take advantage of the massive parallel computations possible on a GPU. It got me off the ground fast, but overtime I have learned enough to start writing and optimising native OpenGL code. It’s an awesome library for experimenting with WebGL/WebGPU.

Screenshot 2021-03-29 at 15.00.42.png

One bad Shade Map bug was caused by how gpu.js translates Math.atan2 to OpenGL. Mistakenly, the library translates atan2 (two argument arctangent) to arctan (single argument arctangent). Both atan2 and atan produce the same results for a range of inputs (including the ones used in gpu.js test cases) but in some cases they produce different results. I opened a pull request to fix this issue and am really proud to contribute to this project that made Shade Map possible.

Focus for April #

Fix artifacts on 16-bit GPUs #

You can specify the precision (lowp, mediump, highp) to use when running WebGL code. I have read that lower precision calculations will run faster and are more-widely supported. If I want Shade Map to run fast and on as many machines as possible I need it to work well at mediump precision. It currently runs at highp.

According to the spec, mediump precision is 10 bits, I believe the smallest number it can hold is 0.00006103515625 . A problem occurs when the angle of the sun changes by .00001 radians or the earth curves .00001 meters between two points and using these numbers in a calculation with bigger numbers effectively makes them 0. You can see artifacts appear at mediump that don’t exist at highp. They manifest as blocky, repeating or phantom shadows. Here’s an example:

Screenshot 2021-03-29 at 12.53.30.png

Optimize finding max elevation #

Currently, one of the slowest operations is figuring out the highest elevation on the screen. Anytime you drag or zoom the map, there is a brief lag as the highest elevation is recalculated. There is an elevation associated with each pixel on the map and finding the largest value involves iterating through each pixel and seeing if its elevation is largest encountered so far. On my display that’s close to 2 million (pixels) iterations! A smarter way is to use the GPU and check pixels in parallel, instead of one at a time. I can group 4 pixels at a time and choose the largest elevation among them, take those results and group them by fours to find their highest elevation and repeat the grouping until only the largest elevation is left. On my screen this would only take 20 iterations of grouping. A significant performance improvement at the cost of much more complicated code which I have tried to write and re-write many times but am yet to master renderbuffers and textures.


Now read this

Monkey Face - Smith Rock

Monkey Face is a distinct pillar in the center of Smith Rock State Park outside of Bend, OR. One side of it resembles the face of a monkey (although, I would say ape) with eyes and forehead slanting away from a protruding mouth and nose.... Continue →