Sunday, December 17, 2017

City Symbols (Part 4): Faux 3D for Simple Houses

As of the last posting I had developed simple houses in a number of different styles.
Now I want to look at some 3D effects, such as seen in these city icons from the Western Torfani map:
In the Karambo city icon, you can see that some cylindrical buildings and the domed roofs have been shaded to give them a more 3D look.  And in the right city, you can see cast shadows on the ground and within the city itself.  These sorts of effects are called "Faux 3D" in Dragons Abound.

Let me start with the shading for cylindrical buildings.  At a minimum, that's just putting a dark band along the left side of the house.  I can create the shading band from the fill color of the house by reducing the luminance, although I don't want to use the same shade I'm using for the doors and windows.
You can see this is pretty crude, but at the map scale it's barely noticeable.  I can improve things with a little more elaboration.

Shrunken down to map size that looks pretty good.  SVG also offers linear gradients, so maybe I could take advantage of that.   We need a left-to-right gradient that mimics the layout we have above:

That actually looks pretty good.  I thought the linear gradient wouldn't work at the map scale, but it looks fine.  The colors are a little faded out to my eye, but not enough (at map scale) to worry about correcting.

(Note:  I later realized that the was a problem with the colors in the gradients and corrected this problem.)

Now let's see about giving the roofs a 3D effect.  Unfortunately, SVG doesn't offer exactly the right sorts of gradients to do this easily, but for domed roofs I can probably get by with using a radial gradient and treating the dome as a half of a sphere.

That doesn't look exactly right to my eye, but at the map scale it's certainly close enough.  

The peaked and flat roof styles look strange when combined with a cylindrical building, so I won't use those combinations.  But the eaved roof style (above) looks like a conical roof and I would like to be able to use it.  The gradient I need to do a conical roof correctly is a kind of "sunburst" gradient that pinches a linear gradient to the point at the top of the roof.  I don't think there's any way to do exactly that in SVG (let me know if I'm wrong about that), but I can do a crude approximation using a linear gradient that has been rotated to approximately the pitch of the roof.
I've used some artistic license here in not matching up the gradients exactly, because when I do that the roof and the building blend together too much.  At any rate, I think this is "good enough" at the map scale.

Unfortunately, now that I've added 3D effects to the round houses, the standard flat style doesn't look very good in comparison.  Which means that if I want to use 3D effects, I'll be limited to just round houses.  That doesn't seem acceptable, so let me go back and "3D" the standard houses.  An approach to doing this is illustrated in these icons from the Western Torfani map:
(I've blown this up to make the details more visible.)  In these examples, the foreshortened side of the house and the roof have been added. 

The house side is not too difficult.  I'm not bothering to do real perspective, so this is just a short parallelogram off the left side of the house.

And since this is the shadowed side of the house, it should be in the shadow color.  And for this type of roof ("peaked") the roof side is another parallelogram.
The "eaved" style of roof in 2D looks like this:
For 3D I'm going to make this into a pyramidal roof.  This is basically like the eaved roof above, except the roof side comes to the top center.
Since this roof overhangs the house, I'll add a shadow under the eaves.
The pagoda style roof is much the same, except with curved roof sides.
Now I want to add a shadow to the house.  I'm already doing shadows of this sort for mountains by reusing the outline of the mountain for the shadow but skewing it and filling it with a shadow color.  Unfortunately in this case I don't have the whole outline, but since the house is basically the roof and the body of the house I'll reuse those.

Transformations in SVG are always problematic for me because they are applied to the entire coordinate system, so skewing an object also moves it.  With mountains, I drew them at the origin of the coordinate system, which made transforming them easier but then required me to translate them afterwards.  For houses, I'm drawing where I want them, so the transformations are different.  After reading and re-reading some basic material, I eventually get the right incantation to skew and scale the shadow.  I also reduce the opacity and add some blur:


Here's what they look like on a map:
Next time I'll look at doing some larger buildings.

Monday, December 11, 2017

City Symbols (Part 3): Some Styles for Simple Houses

In the last posting I implemented simple houses to use for city icons:
One basic element I didn't get around to adding last time was a chimney.  This is just a rectangle sticking up off the roof line:
For these to look good at the map scale they have to be pretty sizable and have good separation from the roof peak.
It looks a little odd in a group like that, but of course normally I won't have a chimney on every house.
Here's a quick look at using these on the map to represent a small village:
Looks pretty good so far.  One thing I notice here is that it looks odd to have a house symbol overlapping the ocean (where the circle looks okay, compare Liel Luu above), so that's something I will have to address at some point.

These houses have some variation in things like the roof height, size and number of windows, etc., but they're basically all the same "style".  But I'd like to have houses of different styles, so that (for example) I can use different style city icons for different countries to visually hint at different cultures.

The first style variant I'll implement is pretty simple:  Adding eaves to the roof lines.  These are just little extra lines coming down from the roof:
These might look a little exaggerated but they're still only barely visible in the map view:
So maybe not a very effective styling, but at least easy to implement.  It might be better to fill in the eaves, like so:
This is more obvious than the other eaves style at map scale:
Another variation of peaked roofs is the "pagoda" style roof where the roof line is notably concave.  I'm doing semi-circles and arcs for a number of other things in Dragons Abound (such as labels and mountains) so it's pretty straightforward to replace the roof sides with arcs:
Notice that the arc has to be pretty exaggerated to be visible at the map scale.

Peaked roofs are an artifact of northern cultures where snow buildup is a problem.  In the Middle East and other climes where snow is rare flat or domed roofs are also common.   Since flat roofs are a little easier, I'll do those first.
The flat roof needs to have more thickness than the house outline so that it shows up at the map scale. 
A domed roof is created like the pagoda roof, but in this case using arcs that go outward:
Those roofs look a little crude because I'm only using 6 segments to render them.  But at the scale they'll be used in the map, this looks fine:
The tallest domed roofs start to look a bit like peaked roofs, so when using this style I'll probably reduce the possible height range of the roofs.

With domed roofs we should also have domed doors:
Unfortunately, these aren't really visible at the map scale (at least to my old eyes, YMMV):
Finally, domed roofs really should go on circular (cylindrical) houses.  This is mostly just a matter of changing the baseline of the house to be a curve.  This is surprisingly easy to do, since I already have the same code working to do the domes for the roof and the door.
You can see there are a couple of problems, though.  First, the door is floating because it still thinks it's on a straight baseline between the corners of the house.  Second, the flat line for the dome roof now looks wrong.  The windows should probably also lie along a curved arc, but I'm hoping this won't be necessary at map scale.

Fixing the door is a bit complicated but not too bad.  I need to extend the door downward and find the two points on the baseline where the door would hit. If I'm lucky, I'll be able to connect straight across those two points.  If I'm not lucky, I'll have to recreate the baseline curve between those two points.  Let's see if I'm lucky:
Looks fine, so I guess I'm lucky this time.  (Even if it didn't look good at this scale, it might have been fine at map scale.)  Now I need to do the same thing with the bottom part of the dome roof.  It's probably not necessary, but if we reduce the curvature along the top line it will make the perspective look more correct.
That improves things a lot, but now the straight line of windows does stand out.  Let's see how it looks at map scale:
It's not glaring but it does look odd on the houses with multiple windows.  In for a penny, in for a pound, as they say.  To fix the windows I need to offset them from the corresponding spot on the baseline, so this works something like fixing the door.
Well, it's not what I'd call fine art but it's serviceable.  Let's see what it looks like at scale:
To be honest, I'm not sure that's a significant improvement but maybe it helps a bit.

Up to now I've been using a basic red and black theme for the houses.  That has a certain appeal, but in general I think I want a more muted color scheme with less stark contrast.  To do this, I'll pick a fill color for the houses and then create the colors for doors, windows and outlines from that color.  Here's what that looks like:
This isn't very "artistic" but by using colors that vary only in luminance, the color scheme is guaranteed to work together.  And it means I only have to pick one house color.  Picking a color in the same family as the land or forest will also help the symbols to fit in well with the rest of the map.
One thing I did with mountains and other elements of the map is to create a hand-drawn look by jittering lines and adding some other line variations.  While I can certainly add this effect to these small houses, it is mostly unnoticeable unless the jitter is large enough to interfere with the drawing: 
The one element that does seem to work somewhat is varying the width of the line, which even at the small scale can introduce some interesting variation.

Next time I'll look at giving the houses a 3D look.

Thursday, December 7, 2017

City Symbols (Part 2): Simple Houses

As mentioned last time, I'm now working on creating city icons in the style of little city pictures, like these examples:
To start with I'm going to try to generate a simple house:
Basically an outline with doors and windows.  Typically one or two of these little house icons is used for a small city (e.g., Maltina or Pahamo in the map above), and often fill in the spaces in a big city (e.g., Monterey or Gafemnoro in the map above).  These simple houses also have many of the elements used to draw bigger buildings like towers, i.e., a roof, windows, doors and so on.  One of the challenges will be to make these drawings look good at map scale.  The example maps above are higher resolution than Dragons Abound maps, and those icons are already small.  For my maps, the small buildings will be around 6 pixels wide at the default resolution.

Of course, I don't want to generate the same house over and over, so one thing that's worth thinking about up-front is how the procedural generation will vary the house, and which parts are constant and which can change.  The key constant element here is probably the height of the house, or more accurately the height of one story of building.  I can vary the width of the house, the height of the roof and the placement of the doors and windows, but it doesn't make sense to have buildings with different scales:
(Although I suppose if you had hobbits and giants living in the same city...)  I also want to limit the number of constants so that I can generate a nice variety of houses, but I also want the variable factors to stay reasonable.  One good way to do this is to generate the other variable factors based upon the constants, for example, by saying that the width of the house can vary from 1 to 2 times the height.  In this case, I'm going to try to base everything off the height.

The first step is to generate the basic outline, with some variation in the width of the house and the height of the roof:
At this point it occurs to me that it will probably be useful to separate the creation of the house from the drawing of the house.  My top-level code looks something like this:
function createSimpleHouse(world, mapParams, x, y, height) {
  const house = {}; 
  createHouseOutline(world, mapParams, house, x, y, height); 
  createHouseRoof(world, mapParams, house); 
  return house;    
};

function drawSimpleHouse(world, mapParams, svg, house) { 
  const allhouse = svg.append('g'); 
  drawHouseOutline(world, mapParams, allhouse, house); 
  drawHouseRoof(world, mapParams, allhouse, house); 
  return allhouse;
};
Creating houses with black roofs is now just a matter of making that an option in drawHouseRoof: 
Likewise, I need to fill the main part of the house, either to obscure the background or to make them a particular color, like the red icons in the example map above.
Now let's add doors and windows.  The door height and width are determined by the building height, and at least initially it can be anywhere along the front of the house, with a little buffer at either side.
And we need to be able to fill the doors in as well.
One interesting point about my example maps is that doors don't always appear on buildings (perhaps the door is on a different side).  So to accommodate that I'll put a random chance on a door appearing.
Now I need windows.  Windows can vary more than doors in terms of height and width, so I'll pick a size randomly and then fill in to either side of the door (if there is one).  The top of the window will be set to align with the top of the door.
And obviously I'll want the capability to fill in the windows as well.
One thing I learned in doing mountains is that scaling down doesn't always look good.  You need to generate graphics at the scale it will be used and tweak it to look good at that size.   So for the most part in this series of postings I'll be showing images at the tiny scale they'll be used.

So how does this look at map scale?
That's not too bad.  The details are clearly visible and it's easy to distinguish the different houses.