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!