About CityEngine Blog


CityEngine is a great tool that is able to create large scale models, mainly of cityscapes, quickly, and with the ability to make adjustments based on a rule file in a procedural manner.

I hope to show you some of the work I have done with CityEngine creating a variety of models across a range of projects. I have mainly used the software for planning applications but have learnt a great deal of the potential for other applications.

I want to concentrate on the writing of rule files which is the core use of CityEngine. Without rule files no 3D content can be generated and this is very important to understand. I will also strive to bring news and updates regarding CityEngine as well.

I hope you find what I share useful and please feel free to share and contribute your thoughts and experience.


Friday, 17 October 2014

TikiTown 6 - Visualisation Options

There are a plethora of tools that can be used to generate screen shots, high quality renders and animations using data output from CityEngine. CityEngine currently (as of CityEngine 2013) has the ability to export 3D models to the following formats:
  • Keyhole Markup Language (.kml)
  • Collada (.dae)
  • Wavefront OBJ (.obj)
  • Autodesk FBX (.fbx)
  • E-On Software Vue (.vob)
  • Pixer RenderMan (.rib?)
  • Esri FGDB
  • CityEngine WebScene (.3ws)
To visualise the models generated for TikiTown I wanted to have a go at using a few of these and see which is easiest or produces the best results. I am by no means a visualisation expert and the work I carried out to visualise TikiTown were basic at best. I use CityEngine to generate data and would prefer to leave the visualisation, which is another specialisation in its own right, to a specialist.  

I shall quickly present the three options that I explored and the outcomes

Bentley Microstation

The Luxology render engine that is offered within Microstation was chosen simply because I have access to this software and have had a small amount of experience in using the tools and was able to build on previous knowledge. It seemed to me that the number of options to set up lighting, environment, cameras etc, etc was hugely complex and would take a great deal of time to find out exactly how to best visualise the models.

Thankfully I had some help in finding some reasonably good settings and was able to produce some high quality renders. Each of these images took around 10 minutes to produce.











LumenRT

Creating an animation in Bentley certainly seemed more trouble than its worth and so I sought an easier route to producing one. LumenRT is a tool that can directly import the E-On Software Vue files. The free LumenRT trial version has some very simple functionality which provided the ability to generate a simple but very nice output video. The background textures that come enabled with the trial were very limited and so I had to swap my idea of a water background for grass.

The software works much like others of its kind where camera points are set up like bookmarks. The software does the hard work of interpolating the additional camera points and captures the high resolution images as per the frames per minute/second requirements. Once the images have been captured, LumenRT wraps them up into an .avi file. There were a number of options that can be played with such as quality, lighting etc but the trial version was fairly (and thankfully) limited.

Importing the file in the .vob format was extremely simple and of course the software dealt with this format very well - even considering the size of the file (368Mb). To me, a file of this size isn't all that big but Bentley certainly had difficulties in handling a file of this size so I was impressed with the performance that LumenRT offered. Setting the scene to capture the .avi was pretty simple, probably due to the limitations offered in the trial version, but it all still felt simple with easy to understand settings and controls. The output video took around 10hrs to export for a video of 40 seconds. The camera swings a little wildly at some points, due to my placing of camera points, and towards the end the scene flickers, but overall I consider this to be a great result and I'd recommend using LumenRT for similar visual outputs.

If anyone has any other suggestions for high level visualisation of CityEngine outputs I'd like to hear them!




CityEngine WebScene

The final visualisation option I explored was of course the 3D WebScene that CityEngine has brought out in the last year or so. I have created a number of WebScenes and customers and colleagues are always impressed with what they can offer but I'd say that they are extremely limited. Of course this is no complaint because they are a very easy way in which to deliver 3D scenes to people that require no additional software deployed to a machine - which is very handy in a corporate environment where all technology is locked down to the user.

I find that you really do need to limit the amount of data that you put into the scenes simply because the file created needs to be downloaded by the end user. Most people want the scene to open instantly and so waiting for a large file to download will often put someone off. Another reason for keeping the file size small is the limit to what a scene can handle. I don't believe there are hard guidelines regarding a file size but judge it on the performance that you get out of scenes you export. I generally find that any file over 100Mb (after unpacking) tends to be a little tricky to play with.

For final visual output I have exported to a CityEngine WebScene and have uploaded to ArcGIS Online. This gives me the ability to share the scene.

The output is obviously not a fully rendered output like those produced in Bentley or LumenRT, however it gives the user the ability to fly, pan, zoom around the model and to inspect information (if any provided). Its an amazing tool and one which I'll certainly be continuing to produce. Hopefully I'll get the chance to showcase in another blog entry some of the scenes I have produced so far.

Project Wrap up

I think that providing some ratings based on ease of use, time and output quality is a good idea to finalise what I thought of each option.

Bentley Microstation V8i
Ease of Use: 4/10 - Had trouble dealing with file sizes and has a complex and hard to understand configuration for video and image export for non-expert users
Time: 6/10 - The time taken to produce anything half decent took a considerable amount of time but I'm sure if I knew what I was doing this could quite easily be made more efficient
Output Quality: 9/10 - Once some settings had been found that suited what I wanted the outputs were very good, in my opinion better than an of the other options shown here.

Overall: 6/10 - Ideally I'd like to produce this level of output and better but I'd really need to hand the model over to an expert rather than do these myself (of course I could learn from the expert)

LumenRT (Trial Version)
Ease of Use: 9/10 - This is based on the trail software and I'm sure the Pro version is far more complex but compared to the Luxology render configuration in Bentley this just seemed all so easy.
Time: 7/10 - Learning how to set up a scene was very quick plus there were no file import issues due to compatibility so again it was very easy. The time to export the video was fairly long but it was fine because of the quality
Output Quality: 7/10 - Generally a very high quality output that just has a few teething problems. I'm sure if I'd given it more time then the output could have been better but again ideally I'd hand over the model to an expert.

Overall: 8/10 - Easy to use, simple and a high quality output... what's not to like! Very impressed with the trial version and will seriously look at the Pro version for potential future requests for animations or high quality render outputs.

CityEngine WebScene
Ease of Use: 8/10 - quick to export, few issues. Its just the file size that puts a limitation on its ease of use as it means that you constantly think of how to keep the file size down (maybe this should be best practise anyway?)
Time: 8/10 - Again very easy to create an exported file and upload to ArcGIS, it's about as easy as it gets.
Output Quality: 5/10 - The output quality is good but compared to the fully rendered options it comes up short. The power in this tool is to be able to offer a user the ability to use the model themselves

Overall: 7/10 - All in all its a great tool that probably is the first choice of output because of the compatibility, quality and ease of provision to customers. Its not the best visual tool but I think that I will in future go for an option that looks at delivering both the LumenRT and CityEngine WebsScene outputs. Both are easy to create and are good at different things, both of which I think my customers want.

I completed pretty much every that I wanted to during this project. Although the outputs fell short of the quality that Fold 7 produced with their Ministry Of Sound advert, I was happy with the level produced here and in the right hands I'm sure that a 3D artist (?) could take the TikiTown model produced in CityEngine and create something truly awesome.


Monday, 2 June 2014

TikiTown 5 - The final piece of the Tiki

I wanted to do something a little bit different for the main body of the Tiki - called suburbia, and also the area that I've very lazily (or incorrectly) called the helmet. Terminology aside, I wanted to try some new techniques including creating a rule specifically for one input shape. This is a general change to how I had used CityEngine before as all other CGA scripts I had written were aimed to be used on multiple, often hundreds, if not thousands, of input shapes. I also wanted to try and vary the shape of houses a little bit more than I had up to this point.

Suburbia

The suburbia start rule is pretty crude and was developed pretty quickly because I wanted to keep the focus of  the TikiTown model on the head. However, bored as I was of creating simple residential footprints, I wanted to give importing some prepared footprints a go. This would allow much more variety in the footprint shape, providing a more realistic birds eye view of a suburban area.

I am fortunate enough to access to a wide range of geospatial data and in this case footprints for existing buildings came in very handy. I simply imported 25 building footprints from a geodatabase into CityEngine and exported them as a Collada file without doing a single thing to them. The files that exported from CityEngine still had the original orientation and so I brought them into Sketch Up where I simple re-orientated them so that they were all aligned in the same manner.

There is nothing extraordinary about the rule for the suburbia area and I've not attempted to do anything creative with the footprints after they have been inserted as a model but the trick works quite nicely. The footprints do not necessarily have to be taken from real world data - although it was very easy simply selecting 25 out of the hundreds of thousands on offer, they could simply be created from scratch in Sketch Up. The building footprints that I've used meet the New Zealand style I wanted but if I were creating a different style of city then possibly I'd look to create or extract others. Open Street Map might be a good source for similar data for other areas of the globe, or other local sources of geospatial data.



One Shape, One Rule

The Tiki Helmet provided an opportunity to forget the whole building / city thing and just create a model that made a cool backdrop to the rest of the city. On another project I had created a rule for a single shape that looked at making a long building into a wave style shape. Of course we could just drop in a building that has already been modelled as an insertion but where is the fun in that? Here I wanted to produce a model that resembled a building, or buildings but that are very tall and thin with heights that vary according to their place within the model. I wanted the buildings at the back to be taller and gradually decrease in height both as they came closer to the front and to the centre of the model. It gives the impression of the focus being pulled into the centre of the TikiHead towards the TikiSpike.

After the base had been built the shape is split into 20 sections along the longest axis - which in this case is scope.sy. As much as I attempted to re-align the scope with these shapes they never played nice - obviously the scope.sx should be the longest scope but sometimes you just have to go with the flow. Keep that in mind when you follow the code below. Next the shapes were split into 10m sections to create a rough grid pattern. In each of the splits that had just been carried out, both the index and total values had been passed on. The piece of code called Helmet3 takes these values and gives them to hidden attributes so I could use these to give the individual sections their heights.

A small setback is applied to create separate blocks which are then extruded using a fluffy calculation. The TikiHelmet will actually be applied to two shapes - one either side of the TikiSpike. The left hand side is considered the base shape and the one on the right is the reverse. When it comes to splitting, the reverse side it is done in the opposite direction to that of the base and therefore to get the correct extrusion I need to carry out a slightly different fluffy calculation to work out the extrusion height. The image below shows the base shape after the extrusion has been applied. Its extrusion works by dividing the original split total (20) by two, adding the index value of the individual block plus the 2nd index value. The calculation includes some values by which these are multiplied by, simply to give a height that seems realistic (hence the fluffiness).



The reverse shape is subject to a similar extrusion calculation but it also includes the addition of the 2nd total value. The rest of the rule concerns the pretty simplistic look of the 'building' model. As each model here is made of many buildings the number of polygons can get out of control pretty quickly and so the inclusion of elaborate windows etc. is a bit of a no go, but in this case I did model up some simple frames. The mass of each individual block has been modelled in the same fashion as the decreasing mass buildings shown in an earlier post.

Apart from an attempt to play with the colours in the same way as the extrusion (which I didn't dedicate much thought to) the models were pretty much complete and the Tiki finished. Now I could move on to the the final step of visualisation...




@startRule
Suburbia -->
      extrude(world.y, 2)
      color("#C0C0C0")
      SuburbiaBase
      Suburbia1

Suburbia1 -->
      comp(f){top : setback(2){all : NIL | remainder : alignScopeToGeometry(yUp, auto) Suburbia2}}
           
Suburbia2 -->          
      case geometry.area < 80 : NIL
      else : innerRect Suburbia3
     
Suburbia3 -->
      15% : s('0.5,'1,'0.5) center(xz) i(fileRandom("assets/DAE_FloorPlates_Realigned/*.dae")) comp(f){top : Suburbia4}
      30% : s('0.8,'1,'0.75) center(xz) i(fileRandom("assets/DAE_FloorPlates_Realigned/*.dae")) comp(f){top : Suburbia4}
      30% : s('0.65,'1,'0.80) center(xz) i(fileRandom("assets/DAE_FloorPlates_Realigned/*.dae")) comp(f){top : Suburbia4}
      else : s('0.65,'1,'0.80) center(xz) i(fileRandom("assets/DAE_FloorPlates_Realigned/*.dae")) comp(f){top : Suburbia4}
     
Suburbia4 -->
      case geometry.area < 55 : NIL
      else :
            25% : extrude(5.5) Suburbia5
            else : extrude(3) Suburbia5
           
Suburbia5 -->
      split(y){3 : SuburbiaFloors(split.index,split.total) | 2.5 : SuburbiaFloors(split.index,split.total)}


SuburbiaFloors(idx,n) -->
      case idx == n-1 : comp(f){top : alignScopeToGeometry(yUp, auto) SuburbiaRoof | side : SuburbiaFacade | all :  SuburbiaFinish}
      else :      comp(f){side : SuburbiaFacade | all :  SuburbiaFinish}

SuburbiaRoof -->
      75% :roofHip(22,0.3) SuburbiaRoof1       
      else : roofGable(22, 0.3) SuburbiaRoof1  
     
SuburbiaRoof1 -->
      comp(f){vertical : SuburbiaFacade | aslant : alignScopeToGeometry(yUp, auto) SuburbiaRoof2}
     
SuburbiaRoof2 -->
      setupProjection(0, scope.xy, 4, 2)
      projectUV(0)
      texture("IronRoof2.jpg")     
      color(getSteelRoofColour)
     
SuburbiaFacade -->
      setupProjection(0, scope.xy, 1, 1.25)
      projectUV(0)
      texture("Weatherboard.jpg")  
      color(getWeatherboardColour)
     
SuburbiaBase -->
      comp(f){top : SuburbiaBase1 | all : SuburbiaBase2}
     
SuburbiaBase1 -->
      setupProjection(0, scope.xy, ~2, ~2)
      projectUV(0)

      texture("lawn2.jpg")




@startRule
Helmet -->
      alignScopeToGeometry(yUp, auto)
      extrude(2)
      comp(f){top : Helmet1 HelmetBaseTop  | all : Base.}
     
Helmet1 -->
      split(y){scope.sy/20 : Helmet2(split.index,split.total)}*  
     
Helmet2(idx,n) -->
      split(x){~10 : Helmet3(idx,n,split.index,split.total)}*
     
Helmet3(idx,n,idd,m) -->     
      set (HelmetIndex1, idx)
      set (HelmetTotal1, n)
      set (HelmetIndex2, idd)
      set (HelmetTotal2, m)
      setback(1){all : NIL | remainder : Helmet4(idx,n,idd,m)}
     
Helmet4(idx,n,idd,m) -->
      case Reverse == "True" : extrude(HelmetTotal1/2+HelmetIndex1*5+(HelmetTotal2-HelmetIndex2)*3) Helmet5
      else : extrude(HelmetTotal1/2+HelmetIndex1*5+HelmetIndex2*3) Helmet5
           
Helmet5 -->
      split(y){~4 : Helmet6(split.index,split.total)}*
     
Helmet6(idx,n) -->
      s((scope.sx*(1-((idx-1)/n)/2)), '1,(scope.sz*(1-((idx-1)/n)/2)))center(xz) Helmet7(idx,n)
     
Helmet7(idx,n) -->
      comp(f){side : HelmetFacade | top : HelmetRoof | all : HelmetKeeper}   
     
HelmetFacade -->
      setback(0.2){all : HelmetFrame | remainder : HelmetWindow
     
HelmetFrame -->
      extrude(0.3)
      t(0,-0.3,0)
      color("#808080"
           
HelmetRoof -->   
      color("#808080"
     
HelmetWindow -->
      t(0,0,-0.3)      
      set(material.color.r, 0)
      set(material.color.g, 0)
      set(material.color.b, 1 - ((255/(HelmetTotal1-HelmetIndex1))/100) - (255/(HelmetTotal1-HelmetIndex2)/100))
      set(material.opacity, 0.90)
     
     
HelmetBaseTop -->
      setupProjection(0, scope.xy, 2, 2)
      projectUV(0)
      texture("pavement.jpg")


Sunday, 18 May 2014

TikiTown 4 - CGA Creation - Tiki Head

The 'head'of the Tiki contains the main part of the city and as such I wanted this part to look just like a stereotypical city skyline with many tall buildings in different shapes and colours. I wanted to have a bit of a play in designing some basic building shapes, coded so that differences to a floor, or groups of floors would impact the building form.  

Setting up

The first part of the code includes the building of the base but also the setting of window colours. I will apply the window colour much further down in the code but it must be set now, before any floors have been split, otherwise the randomness in the code will assign a different value to each floor of a building. Whilst the randomness coulld be used in a number of other applications, in this case I actually want each floor to be the same.

The section of code 'Head1' includes the setting of two hidden attributes - RegularParcelArea and ParcelRegularity. These two values allow simple analysis of a parcel and some judgement whether the parcel is regular or not. With parcels generated in CityEngine - usually off the back of the Grow Streets tool, the parcels tend to be very regular in shape and so are very easy to deal with. Often, when importing parcels from real world data, there are wildly varying shapes and sizes. Creating code that is able to deal with a wide variety of shapes is very important  and I've found that coding up a simple tool that outputs a value between 0 and 100 provides at least an idea of the regularity. The closer the value to 100 the more regular the parcel shape. The tool works by calculating the regular parcel area for the selected parcel. This takes the bounded length (scope.sx) and multiplies it by the bounded width (scope.sz). If the parcel is 100% regular then the actual length and width will be the same as the bounded (scope) values. Parcel Regularity is then calculated by dividing 100 by the RegularParcelArea, times the actual geometry area. The extremely simple image below shows an example parcel with a regularity value of 86.

Once this value has been calculated for a number of parcels, a better idea of what would be considered an 'easy' parcel to work with can be found.

Building Types

After carrying out this simple check, I use the value to tidy up any slightly irregular blocks by performing an innerRect operation whilst leaving all other parcels as they were (this actually means leaving the most irregular parcels alone)

At this point the buildings are given a type and are then extruded and split in the vertical direction to create a number of floors - carrying the index and total values. The section of code 'Head2' contains the crux of the TikiHead code and gives an idea of the coding necessary to create different building forms based on floor splits. This piece of code contains quite a few stochastic rules, just so that every time the models are generated a different result is generated.

The code contains 6 different building forms:



It is important to see these buildings in terms of individual floors rather than the building as a whole. Constructing buildings in this way allows for interesting and creative results, however, texturing this type of style could prove to be an issue.

I'll run through one of the building types - the Staggered Decreasing Mass. This is a pretty stereotypical building shape and the code produces a nice building form. In this case the bottommost 33% of floors are left as they are, the bottommost 66% (not including the bottommost 33%) are resized so that the scope.sz and scope.sz are reduced to 85% of the original size and centred. The remaining floors (the topmost 33%) are reduced to 65% of the original size and are also centred. This building type could be varied so that different percentages of floors are chosen and/or different values or ways of reducing the size are carried out.

The creativity really is limitless and it comes down to the amount of time you want to spend coding up different designs for the particular output you have in mind. The code I have created here can be built on in other projects so the library of building forms can only be increased. Combinations of the above types would also provide some nice buildings forms...for another time.

Finishing Up

From here its just a case of splitting floors into tiles and applying colours to the building and windows. As previously mentioned, I wanted each building to have a single colour for each the walls and the windows. These colours can not be randomly applied once buildings have been split into floors as each floor would be treated differently, so its important to identify the point at which you wish the randomness to be applied. The wall colour in this case is applied from a constant - and therefore remains the same over the whole model. The final touch to the buildings is the inclusion of a few 'greebles' (look it up in a Google search for some stunning images) representing some little additional texture to buildings as ventilation blocks / stairwells or whatever takes your fancy.

The images below show the TikiHead with the TikiEyes and TikiSpike as an output visualisation created in Microstation. I'm most certainly not a visualisation specialist but even some simple rendering using Luxology produces some pretty awesome results.




##-----------------------------------------##
## Hidden Attributes ##
##-----------------------------------------##

@Hidden
attr EyeWindowColourR = 0

@Hidden
attr EyeWindowColourG = 0

@Hidden
attr EyeWindowColourB = 0

@Hidden
attr RegularParcelArea = 0

@Hidden
attr ParcelRegularity = 0


##-----------------------------------------##
## Functional Attributes ##
##-----------------------------------------##

@Range("A","B","C","D","E","F")
attr BuildingType = "A"


##-----------------------------------------##
## Functions ##
##-----------------------------------------##

getEyeColorR =
      (1/255)*EyeWindowColourR     
     
getEyeColorG =
      (1/255)*EyeWindowColourG
     
getEyeColorB =
      (1/255)*EyeWindowColourB


##-----------------------------------------##
## Constants ##
##-----------------------------------------##

const getRandTile = floor (rand(2,6))

## http://www.fillster.com/colorcodes/colorchart.html ##   
const getWallColour =
            10% : "#F0F8FF" #Alice Blue
            10% : "#CDC0B0" #Antique White 3
            10% : "#E0EEEE" #Azure1
            10% : "#C1CDCD" #Azure2
            10% : "#838B8B" #Azure3
            10% : "#CDC8B1" #Cornsilk2
            10% : "#8B8878" #Cornsilk3
            10% : "#4F4F4F" #Grey31
            10% : "#696969" #Grey41
            else : "#BEBEBE" #Grey
           
##-----------------------------------------##
## Assets ##
##-----------------------------------------##



##-----------------------------------------##
## Rules ##
##-----------------------------------------##

@startRule
Head -->   
      set(EyeWindowColourR, (ceil(rand(0,51))))
      set(EyeWindowColourG, (ceil(rand(0,25))))
      set(EyeWindowColourB, (ceil(rand(0,175))))
      extrude(2)
      comp(f){top : HeadA HeadBase | all : HeadBaseAll}
     
HeadA -->
      setback(2.5){all : NIL | remainder : Head1}

Head1 -->
      set(RegularParcelArea,scope.sx*scope.sz)
      set (ParcelRegularity,(100/RegularParcelArea)*geometry.area)
      report("ParcelRegularity", ParcelRegularity)
      Head1a
     
Head1a -->
      case ParcelRegularity > 85 : innerRect Head1b
      else : Head1b    

Head1b --> 
      15% : set(BuildingType, "A") Head2
      10% : set(BuildingType, "B") Head2
      15% : set(BuildingType, "C") Head2
      15% : set(BuildingType, "D") Head2
      5% : set(BuildingType, "E") Head2
      else : set(BuildingType, "F") Head2
           
Head2 -->
      85% : extrude(rand(30,60)) split(y){~3 : Head2(split.index,split.total)}*
      else : extrude(rand(45, 85)) split(y){~3 : Head2(split.index,split.total)}*
     
     
Head2(idx,n) --> 
      case BuildingType == "A" : HeadFloors1(idx,n) # Bulk Mass
      case BuildingType == "B" : s((scope.sx*(1-((idx-1)/n)/2)), '1,(scope.sz*(1-((idx-1)/n)/2)))center(xz) HeadFloors1(idx,n) #Decreasing Mass
      case BuildingType == "C" :
            case idx%2 == 1 : s(scope.sx*0.85,'1,scope.sz*0.85) center(xz) HeadFloors1(idx,n)
            else : HeadFloors1(idx,n) # Alternating Mass
      case BuildingType == "D" :
            case idx < n*0.33 : HeadFloors1(idx,n)
            case idx < n*0.66 : s(scope.sx*0.85,'1,scope.sz*0.85) center(xz) HeadFloors1(idx,n)
            else : s(scope.sx*0.65,'1,scope.sz*0.65) center(xz) HeadFloors1(idx,n) # Staggered Decreasing Mass
      case BuildingType == "E" :
            case idx < n*0.80 : HeadFloors1(idx,n)
            else : s((scope.sx*(1-((idx-1)/n)/1.5)), '1,(scope.sz*(1-((idx-1)/n)/1.5)))center(xz) HeadFloors1(idx,n) # Bulk Mass with Tower
      else :
            20% : HeadFloors1(idx,n) # Bulk Towers
            20% : s((scope.sx*(1-((idx-1)/n)/2)), '1,(scope.sz*(1-((idx-1)/n)/2)))center(xz) HeadFloors1(idx,n)
            20% :
                  case idx%2 == 1 : s(scope.sx*0.85,'1,scope.sz*0.85) center(xz) HeadFloors1(idx,n)
                  else : HeadFloors1(idx,n)
            20% :             case idx < n*0.33 : HeadFloors1(idx,n)
                  case idx < n*0.66 : s(scope.sx*0.85,'1,scope.sz*0.85) center(xz) HeadFloors1(idx,n)
                  else : s(scope.sx*0.65,'1,scope.sz*0.65) center(xz) HeadFloors1(idx,n)
            else :                  case idx < n*0.80 : HeadFloors1(idx,n)
                  else : s((scope.sx*(1-((idx-1)/n)/1.5)), '1,(scope.sz*(1-((idx-1)/n)/1.5)))center(xz) HeadFloors1(idx,n)


HeadFloors1(idx,n) -->
      case idx == n-1 : comp(f){side : HeadFacade | top : TopHeadRoof HeadRoof | all : Headkeeper}
      else : comp(f){side : HeadFacade | top : HeadRoof | all : Headkeeper}
     
HeadFacade -->
      case scope.sx > 5 : split(x){~0.5 : HeadWall | {~getRandTile : HeadTiles}* | ~0.5 : HeadWall}
      case scope.sx > 1.5 : HeadTiles1
      else : HeadWall
           
HeadTiles -->
      case scope.sx < 1.5 : HeadWall
      else : HeadTiles1

HeadTiles1 -->
      setback(0.2){all : HeadFrame | remainder : HeadWindow}
     
HeadWall -->
      color(getWallColour)

HeadFrame -->    
      extrude(0.25)
      t(0,-0.25,0)
      color(getWallColour)
     
HeadWindow -->
      t(0,0,-0.25)
      color(getEyeColorR, getEyeColorG, getEyeColorB)
      set(material.opacity, 0.95)

HeadRoof -->
      color(getWallColour)   

TopHeadRoof -->
      color(getWallColour)   
      alignScopeToGeometry(yUp, largest, 0)
      HeadGreeble

HeadGreeble -->
      setback(scope.sz*0.20){all : NIL | remainder : HeadGreeble1}
     
HeadGreeble1 -->
      case scope.sz < 2 : NIL
      else :
            innerRect
            split(x){~rand(2,4) : HeadGreeble2 | 1 : NIL}*
     
HeadGreeble2 -->
      case scope.sz < 2 : NIL
      else : split(z){~rand(2,4) : HeadGreeble3 | 1 : NIL}*
     
HeadGreeble3 -->
      comp(f){all : HeadGreeble4}
           
HeadGreeble4 -->
      50% : extrude(1)
      else : NIL 
     
HeadBase -->     
      setupProjection(0, scope.xy, 2, 2)
      projectUV(0)

      texture("pavement.jpg")