Thursday, August 17, 2017

Decorating the Ocean (Part Four)

A simple coastline embellishment is to darken the water around the coastline:
This is easily done by drawing a darker line around the coast and blurring it into the ocean, and creates subtle effect that helps create visual interest and a break between land and ocean.  It's sometimes seen combined with the horizontal lines embellishment:
The gradient and the shading lines reinforce each other, in a way very similar to the mountain shading used above.

Interestingly enough, this effect also looks pretty good if the water is lightened around the coastline:
This doesn't create as compelling a contrast between the land and the ocean, but it does suggest a surf line (or shallows) which is nice.

A variant of this embellishment is to turn the dark edge into a drop shadow by making it more distinct and offsetting it opposite the light direction:
This creates the impression that the land is floating above the ocean; not my favorite effect but it is dramatic and works well on certain sorts of maps.

This map demonstrates another lovely ocean decoration:
This is an Oriental-inspired map by Ilanthar at the Cartographer's Guild.   He has decorated the ocean in this map by overlaying it with a Japanese-inspired wave pattern.  It adds a lot of interest and character to the ocean.

In SVG, to overlay a pattern of some sort onto a graphic, you use a filter that composes the base image with the overlay image.  If the image is small, you can tile it using an feTile filter. The whole stack looks like this:
// Create a new filter
  // Bring in the overlay pattern
  // Tile the image to repeat over the whole area   
  // Blend the pattern into the background via "multiply"   
  <feBlend mode='multiply'>
You have to take some care when doing this to pick sizes that display and tile correctly.  Non-square patterns also offer some challenges.  If you're just using one pattern, you can work out the proper values and hard-code the solution, but if you're picking between multiple patterns it gets a bit tricky.

Here's an example of a map using a pattern on the ocean:
Keen-eyed observers may detect a tiny little problem:  There's a noticeable gap between the repeats of the pattern!  Bad programming?  No.  It turns out I have discovered yet another bug in Chrome. Perhaps not unsurprisingly, I seem to be testing the limits of what SVG can do in the browser and uncovering areas that no one else has explored.

The work-around (and it took me an embarrassingly long time to think of this) is to tile the pattern myself into an image bigger than my map size and then use that as the pattern.  This also has the advantage that it eliminates some of the fussing to make tiling work, although you are limited to the tiling that you create in the big pattern.  And obviously this can break if the map size gets bigger than the pattern, but for the moment is fine:
One unexpected hurdle for this decoration is finding good patterns.  The pattern that Ilanthar used in his original map and I re-used above can be found fairly easily on the Internet, but there's not a great deal of other usable patterns to be found.  (Even, so far as I can tell, in paid resources.)  Here's an example of another pattern:
Ilanthar has another map where he uses an ocean pattern; in this case it's a more of wave texture than a graphical pattern.  It also doesn't seem to tile perfectly, creating some artifacts.
Here's a quick attempt to re-use this pattern:
Some artifacts are visible here, as I haven't yet put a lot of effort into cleaning up this pattern.

There's a lot of flexibility with ocean patterns and probably some nice opportunities to create interesting effects.  For example, using the wave pattern above at a much smaller scale has the effect of creating a water texture rather than a graphical pattern:
And just to suggest more possibilities, this example map has an interesting approach:
It uses the horizontal lines decoration on the coast, but the rest of the sea is decorated with dots.  That could be easily done with a pattern.

Thursday, August 10, 2017

Decorating the Ocean (Part Three)

In the previous posts, I've described how Dragons Abound draws oceans and how it creates a common coastline embellishment where a series of parallel lines are drawn outward from the coastline:
In this post I'm going to describe how I've implemented another common embellishment.  Here's an example map that illustrates what I'm going to try to do:
In this map, the ocean is indicated by parallel horizontal lines that radiate a short ways from the land before trailing off.  These might have originated as more illustrative wave symbols, but now they're more graphic and stylized.  This example map is nicely hand-drawn and quite artistic.  A fair number of fantasy maps use this technique, but few of them do this nice job with it.

The straightforward approach to implementing this embellishment would be to walk along the coast and draw lines outward and some interval.  But there are a couple of problems with this approach.  First, you can see that the lines are at regular vertical intervals.  If you just step along the coast a certain distance, the lines will be closer together where the slope of the coast is shallow (i.e., close to flat).  Another problem occurs when the coast bends so that the lines from two parts of the shore meet, as happens on the example map near Dennies Point to the upper right.  You would need to make sure as you walk along the coast drawing lines that the lines you draw on the left side of this feature meet up with the lines you draw on the right side of this feature.  A final problem is that you sometimes have to draw lines that don't start from the shore at all, as happens on this map at each of the Points.

It's probably better to think of this embellishment as a pattern that is filling a buffer zone around the coastline.  After some thought, my approach to implementing this was to fill the entire ocean with parallel horizontal lines, and then mask away the parts that were away from the shore.  Let's see how that can be done.

To start with, I need to fill the ocean with the basic line pattern.  This is simply a matter of drawing a series of horizontal lines into the ocean layer of the map, like so:
All I've done here is fill the ocean with color and then draw lines on top.

The next step is to mask away the lines that aren't near the coasts.  However, as I mentioned in the previous post, the problem of "draw a line X pixels away from this polygon" is actually very difficult.  So I can't just expand the coastline and use that to cut off the lines.  Instead, I'll make use of the same trick I used in the last post -- drawing the coastline with a big pen.

To see how this will work, let's first visualize the desired mask.  Typically, a mask is just a black and white image that blocks drawing where it is black.  To start with, I can create a mask that is entirely black and use that to mask the ocean stripes.  This is the unsurprising result:
The mask blocks out all of the lines.  Now I want to modify the mask so that it shows the lines near the coast.  To do this, I want to paint the mask white in a swath around the coast.  How do I do that?  Remember how I used big pens on the coast to create the previous embellishment?
I'll do the same trick, only (1) I'll only draw one big white coastline, and (2) I'll draw into the mask instead of into the display.  The mask will then allow the stripes to show through wherever the big white pen drew:
And indeed, the stripes are now showing along the coastline.

This is too obviously mechanical, so let's working on making it more artistic.  To start with, I can vary the width of the mask so that the distance from the coast isn't always the same.
This effect is subtle, but you can see how the ocean stripes have shrunk in some areas and grown in others.

If you examine the example map above, you'll see that the stripes in that map don't all abruptly end but trail off or get spotty near the end.  Having the stripes trail off (get narrower) is not possible the way I'm doing this, but I can make the ends spotty and irregular.  What I'll do is apply a noise filter to the map to perturb the edges of the map.  A little blur helps too.
That's not quite the same as the hand-drawn version, but it does a lot to break up the artificial edge.

Another problem is that the lines are too regular.  We can start to address that by adding a slight variance to the spacing.
Now I'll add some variation of the line width as well.
Finally, I can add some jitter to the lines so that they aren't so straight.
And putting it all together:
I think the final results look pretty good.

Saturday, August 5, 2017

Decorating the Ocean (Part Two Revisited)

In Part Two of this series, I mentioned that my method for drawing repeated coastlines didn't work well with a mottled sea. The coastlines themselves are made of solid colors, creating a weird effect where they butted up against the mottled sea:
If you look at the peninsula in the right-middle, you can see that the colors in-between the coastlines seem to change as you go around the peninsula.  Actually, that color is staying the same, but it appears to change because the color next to it (the sea) is changing.  For this reason, this coastline embellishment doesn't always work well unless the sea is a flat color.

After posting this to /r/proceduralgeneration, /u/Azgarr suggested that I could use opacity to overcome this problem, by essentially making the areas in between the coastlines transparent so that the sea behind them shows through.  It turns out it isn't quite possible to do it that way, because the way these coastlines are drawn, making pens transparent just reveals the pen underneath, not the sea. But it is possible to get the same effect through careful masking of the pens.

The basic idea is to draw each pen and then mask away the portion where we want the sea to show through for a later pen. That's not too difficult to implement, although just for fun I made it a lot harder by over-generalizing the routine and also re-writing my "change luminance" routine at the same time:
You can see that now the changing sea color is visible underneath the coastlines.

However, there's an odd thing happening around the smaller islands:
It looks like the coastlines are getting clipped.  The problem is more obvious if I make the coastlines black and thicker:
It looks like the lines are getting clipped to a rectangular box a little bigger than the bounding box for the island.  This seems pretty strange, but I've seen something similar before, with SVG filters.

SVG filters have a specification for both an origin and a width and height to define the area of the filter.  This defines the area where the filter will be applied.  Normally a filter is attached to an SVG object, and by default the filter area is set to be bounding box for that object.   You might expect that the filter would then get applied to everything inside the box.  And it does.  For example, a blur filter would be applied to everything inside the box, and the resulting graphic would then be shown on the screen. But -- and this is a little non-intuitive -- the effect of the filter is also limited to the box.  For many filters this doesn't matter, but if you have something like a blur filter that might smear the object out beyond the edges of the box, that doesn't happen.  Instead the smear ends at the edge of the box:
That is an SVG circle with a blur applied.  You can see the straight edges of the filter limits.

The solution is to manually increase the size of the filter area.  And apparently the same is true for masks.  In the case of my map, the mask is getting clipped to the overall bounding box for coastline path of the islands.  Although I've used filters in other places in the program, they'd always been applied to the whole map, so I hadn't noticed this issue.

As with filters, the solution is to manually specify a bigger area of effect:
With that fixed, here's an example of another style:
One problem with this method occurs when adjacent coasts cause the coastline embellishments to overlap:
Since the embellishment lines are not completely opaque, when they cross each other they "stack up" and make a new color.  That's a little unartistic.  The impact can be minimized by keeping the outermost area very light, but I can't offhand think of any easy way to prevent the problem.

Despite that problem, I think the new approach is an improvement, so thanks again to /u/Azgarr for the suggestion!

Wednesday, August 2, 2017

Decorating the Ocean (Part Two)

In the previous posting, I started talking about how Dragons Abound draws oceans.  In this installment, I'm going to talk about how coastlines are drawn.

On the land side, coastlines are just lines around the edges of the landmasses, sometimes with some shading added to create a slight 3D effect:
On the ocean side, the base rendering just has the normal ocean coloring.

There are a number of techniques that artists use to embellish the ocean side of the coastline.  The most common technique is illustrated in this example from the previous posting:
The artists adds a series of areas around the coast in gradually darkening ocean colors.  These areas may (or may not) be outlined in a darker color.  Often the areas also get wider as they get darker and farther away from the coastline.

Creating this embellishment seems daunting.  Each succeeding line is an expanded version of the coastline, so at first glance, it looks like you need to repeatedly dilate (or expand) the coastline.  And expanding (or contracting) a polygon is a decidedly non-trivial problem.  It's complicated for convex polygons and worse for concave polygons.  There's also the nasty problem of intersecting polygons, as with islands near the shore.

Fortunately, there's an easier way to get this effect (at least in SVG).  The key idea is to repeatedly draw the coastline with different size "pens" (some very big!) and different colors, and overlap them to create this effect:
How this works may be more obvious if I turn off everything other than the coastline embellishment:
Here the coastline is drawn first in the darkest and biggest pen, then the next lightest and next smallest pen, and so on.  Slightly smaller and darker pens are interspersed to create the dark borders for each region.  It culminates in a narrow white line.  Half of this is then hidden underneath the rendering of the land.

As the pen gets bigger, the edge of the drawn area tends to naturally smooth out, but as you can see in the above animation, when you move a large circular pen along a path you tend to get a lot of regular circles.  That shows up on the map as smooth circular bumps, as in these areas:
That looks a bit mechanical.  To address this, I apply some smoothing to the bigger pens.  I have to be careful to keep the smoothing consistent between the main pen and the outline pen, and not to smooth near the coast (which would cause problems):
Taking a step back, then, this embellishment is created by drawing a sequence of coastlines from widest to smallest, varying the luminosities of the lines to create a series of gradually brighter regions separated by small darker lines.  Inside the program, I have an array of lines to draw -- for each line I have the width of the line, the color of the line, and how much to relax the path.

I'm using a pretty bright sequence of luminosities (I told you that routine would come in handy) for the coastal highlights, but of course this is adjustable.  Here's a map where I've made the decoration more subtle:
Here's a map with a common variant of this embellishment:
In this example, instead of varying the color of the sea between the embellishment lines, the sea is kept the same and the lines fade until they match the color of the sea.  This is just a different sequence of pens -- all the fat regions are given the color of the sea, and the thin regions are given progressively darker colors as they approach the shore.  So we can draw it exactly as we did the original embellishment, just using a different sequence of colors:
One drawback of this implementation is that if the sea has any kind of variable coloration (such as mottling) this will not be reproduced within the embellishment, because the embellishment is created by drawing an SVG path and those paths are a single color.  This map illustrates the problem:
You can see that the sea color seems to shift around the blob of land in the center-right of the map. Around 6 o'clock on the blob, the sea has been mottled to a lighter color, but the color in the embellishment doesn't change.  In general, it's best to use this style of embellishment on a map with a flat sea color.

Here's another interesting variant of this embellishment:
Here the mapmaker has repeated the coast lines until the entire sea was filled.  The endless repetition ends up creating a sort of texture in the sea area.  To do this in Dragons Abound I just need to add lots of  lines.
This looks subtly better if I vary the distance between the lines slightly.
I'm not sure I like this, but it's an interesting effect.

Finally, it's always fun for me to see how close Dragons Abound can get to my example maps, so here's a render using colors and line sizes (and some additional noise) to match the first example map, in a side-by-side comparison:
Not an exact match (and the example map has some lovely land details that I can't yet recreate) but I think the sea at least looks pretty close.

Next time I'll look at another common coastline decoration.