Monday, January 16, 2017

Purple (?) Mountain Majesties

Previously I looked at scaling the mountain symbols to look good on a map; now I'm going to look at how to color the mountains to fit into the map.

Initially, I wasn't filling in the mountains at all -- just drawing the outline and shading -- but that has a problem:
When you draw a mountain in front of another mountain, the back mountain shows through.  So I need to fill in the mountains so that they properly obscure anything that's "behind" them.
Filling in the mountains is straightforward in the case of a map with a flat background like this one.  It becomes more challenging when the background is more complicated:
In this example, the mountains are using the default land color, but on the map itself the color changes to reflect the height of the land.  What I'd probably like to do is grab an image of the underlying land and paint that into the mountain, but unfortunately that's not possible in SVG.  (Remember that SVG is a vector format -- there is no grid of color pixels to copy as there would be in a raster image.)  The closest I can get is to sample the color at the center bottom of the mountain and fill the mountain with that color.  Doing this makes the center bottom of the mountain match the map.
This looks pretty good, although you can see spots where the mountains seem too light or two dark because the background is changing too much.

Although SVG's fill options are limited, it does offer linear and radial gradients.  Radial gradients aren't of much use here, but with a linear gradient I can make the color of the mountain vary smoothly from top to bottom.  I can make "snow topped" mountains by making the mountain fade to white at the top.
This actually works nicely with a varying background as well:
The intentional gradient on the mountain symbols helps conceal the unintentional mismatch with the background colors.

SVG handles gradients in a slightly unusual way.  Rather than specifying the gradient for the object being filled, you create the gradient in a special definitions section of the SVG file and then reference the gradient.  When I'm creating the gradients for the mountains, each one might be different, depending upon the shade at the base of the mountain.  I could just create a separate gradient for each mountain, but on a map with a lot of mountains that might balloon the size of the SVG file.  So instead I keep track of gradients as I create them, and if I can re-use a gradient I do so rather than create another copy of the same gradient.

Gradients could also be used to indicate something like biomes, e.g., green at low altitudes, brown in the middle altitudes, and then white at the top.  I don't want to implement a three color gradient at the moment, but this is something of the effect:
I can also use the gradient to create the purple mountain majesties of song:
Although I'm not sure that's an option I'll be using often. 

1 comment:

  1. You could use the color code from the underlying object. SVG doesn allow pixel level color detection for security reasons (think of script reading the entire screen and sending it back to a 3rd party). Many of the limitations of SVG are driven by the browser community rather than anything else. Still it managed to enter the HTML5 specs so for the next x years it will be safe to use.

    ReplyDelete