Monday, 29 August 2016
Sunday, 21 August 2016
A key consequence of the Apparance detail management system is that each stage of refinement must be possible independently from any other. The upshot of this is that the content within a block (in a particular tier) must only depend on the content of its parent (higher tier) block. It can't depend on the content of any neighbouring blocks. If this were allowed, then you introduce many cases where long chain dependencies and circular dependencies occur causing no end of problems. It is also easy to see that approaching a block from one direction leads to neighbouring blocks being refined in a different order to approaching from another direction, again causing problems if you depend on them.
|Vertical (downwards) dependency = Good :)|
Horizontal (sibling) dependency = Bad :(
Circular dependency = Really Bad :( :(
The Price We Pay
For a lot of structures and models we may want to build, this constraint isn't a problem. For example, refining a wall into individual bricks is straightforward as the bricks and their positions can be generated deterministically from the more general wall shape representation above. There are however many cases where we cannot model in this way, for example; building a dungeon of interconnected rooms and corridors. Many procedural dungeon generators are effectively image processing systems, applying several passes to the dungeon 'image' (cells or otherwise) to build up, interconnect, and validate the space. This is illustrated well in this nice dungeon generation write-up. Since Apparance doesn't have any image processing (yet) with which to drive this sort of generation, and is effectively a purely functional programming system, we have to use the sub-division approach and work out how to circumvent the horizontal inter-dependencies we meet when neighbouring rooms need to be connected. More on this later/next time.
As an initial starting point I think a 10 km x 10 km* city is a good mixture of being both an impressive size and suitable technology show-case. Since we are always sub-dividing, we also need to start with an outer frame for the city that is big enough to house the tallest building we want. To put this another way; setting the starting height of the city frame defines what the maximum height a building can be. (It's a mindset that we need to really get into to). A height of 200 m* is a good starting point; here's what it looks like:
|Bounds of our 10 km x 10 km x 200 m city|
*The engine is generally unit agnostic but I am going to stick to 1 Unit = 1 m for sanity's sake.
As stated previously, we are limited to rectangular sub-division of the city at the moment so it will all be a bit angular, but hopefully arbitrary splitting and plenty of adjacent zones with the same type will create interesting shapes none-the-less.
An algorithm I've used before to divide up a rectangular area is as follows:
- If too small to subdivide, instance a zone and return.
- If we aren't forced to subdivide (because we are too big), optionally instance a zone and return.
- If we are too small in one direction then subdivide in the other direction, otherwise choose a direction.
- Choose a split point such that no sub-regions are too small to instance.
- Split into two parts and recurse into each part in turn.
This works well and was basically what was used in some early dungeon generation experiments.
Here is this algorithm implemented as a procedure in the Apparance Editor:
|Recursive city zone subdivision procedure|
Setting up the content procedure to just render a randomly coloured inside-out box and choosing suitable minimum and maximum zone sizes gives us a nice visualisation of the resulting zone layout.
To model an interesting city layout I decided that some familiar planning approaches should be used. We will start with some basic city district types and a mechanism for loosely specifying where they should be located in the overall city. This can then be used to drive the classification of each zone as we divide up the city.
- 1 business zone (offices, skyscrapers)
- 1 commercial zone (shops, restaurants, tourist attractions)
- 1 industrial zone (chimneys, factories, and storage facilities)
- 1 space port zone (space ship docking and handling)
- Leisure zones (parks, monuments, and recreation areas)
- Residential zones (housing)
The last two are to be used to in-fill the remainder of the map and don't have any specific location.
Zones are going to form the highest level of city structure, and eventually each one will have many buildings and areas within it (probably called 'blocks', like city blocks). For now, we are laying out the general plan.
For each instanced zone, we need to weigh up the various factors that affect what it could be:
- Distance from each district centre.
- Size of each district.
- Weightings of the non-centralised district types.
- A random factor to introduce variation and avoid clean district boundaries.
This is embodied in the following procedure:
|Main zone type calculation procedure|
I've found it useful to group design-time constants into their own procedures. These are effectively global variables, but with the option of making them parameterised later too. Doing this makes it easy to find major control points by just looking for procedures named 'Design' in the procedure browser when it comes to tweaking the project later on.
|Zone design parameters wrapped in their own procedure|
This is a fairly simple procedure that just takes a zone location and a district definition (labelled Zone Centre & Size here) and generates a weighting value. The convention here is that you get a weight of 1 at the centre and a weight of zero at a distance of 'Size' from the centre. This will generate negative values outside of that but this doesn't affect the weighted selection process.
The distribution process is a general one and hence the procedure was created under the 'Maths' category (for want of a better location). This is implemented as a chain of tests to see if each weighting value should replace the previous one.
|Distribution evaluation via chained tests|
|Individual distribution test procedure|
Updating the Content procedure to colourise the zone according to district type and putting all the above procedures into action produces the following, rather satisfying, result:
|City zones classified into district types|
As the procedures were constructed, any element of random choice is driven from seed values passed down through each procedure. This means that the seed value passed into the root procedure can be changed to affect the whole city. Here are a series of district layouts from a series of seed values:
|Varying the seed to produce different cities with similar structure|
NextThe next step is to look at how these zones are going to be connected, what sort of interfaces there will be (free travel, steps, ramps, barriers, etc.), and how we are going to break these blocks up further and start to introduce actual buildings.
Sunday, 14 August 2016
I've reached the point where the technology needs a decent sized scene to stretch and test the features and it is also time to start working towards something stand-alone to show off the technology to the world.
The development of Apparance is an on-going timeline of features for which the term 'finished' has no real meaning. I need milestones though, points along the way to take stock, gather what we have learned/achieved, and show it off properly. To this ends I have had a 'Demo #1' entry in my planner for a while, which we have now reached.
|We are now at Demo #1|
Playing To Your Strengths
During my recent time off I decided to apply my thoughts to what form this demo project will take, what I hope to achieve, what technical adjustments, improvements, and indeed features it will need. I spent some time thinking about the look and the style of the demo, as well as all the assets, effects, shaders, procedures, and techniques I will need to build it.
As a developing technology, the demo must play to the strengths of the engine, showing them off, whilst avoiding missing or weak areas. I'd loosely list the key features (or lack thereof), and some of their implications, like this:
- Variable detail levels
- Distant and close objects (requires a large world)
- Get more detailed as you approach (show off detail blending)
- Large scale objects (show off dynamic range)
- Small set of primitives
- Basic surface shapes, e.g. cube, cylinder, sphere
- Angular objects and structures will be easiest to produce.
- May need to implement a few new ones
- Frame based space sub-division
- No support for polygon outlines/regions/sub-div yet.
- Rectangular layout of world, e.g. regular rooms only, lots of right angles
- Procedural generation/parameterisation
- Scene can be unique per view (shows off dynamic nature of engine)
- Could incorporate external input (shows off dynamic nature again)
- Huge variety of content needs to be shown (shows off parameterisation)
- Need a lot to explore/see (scene needs to be large)
- View needs to move round the scene.
- No texture support yet
- Flat surfaces for most of the world
- Have to use geometry to add surface detail (plays to engine strength)
- Pixel shader based surface detail can be used
- No shadow support yet
- Harsh lighting will show this up badly.
- A 'light and airy' scene would work best.
- No lighting support yet
- This is going to limit what will look good a lot.
- I'd like to explore static lighting techniques for local lighting effects (this would open up all sorts of possibilities and potentially be less work than a proper dynamic lighting system)
- No AI or scripting yet
- Will need to be a non-interactive experience.
- Need to hard code some temporary fly-through logic (needs to be dynamic to support variety of scenes)
- Will perhaps make a good screen-saver?
- No transparency yet
- I'd really like to get this in as glass allows transitions into interiors (showing off detail levels attainable)
- Combined with pixel shader effects this would also allow simple water features to be added to the scene.
- Implies a level of reflectivity though so would need to think about how much to support this (probably just single general cube-map reflection or specular rather than captured or true reflection. May need basic texture support.)
- No fog support yet
- This will be needed to add depth to the scene, but is largely a shader based effect so something we can add relatively easily.
- Sky box
- Not really a technology feature as this can be implemented as geometry or shaders.
- Sun/moon can be shader generated to represent major light source direction.
Given all this, combined with my love of science fiction, I decided that a utopian science-fiction city would be a good choice of subject. It is something that aligns with the limitations above:
- Regular (buildings are often angular and regular)
- Large scale (from skyscrapers to industrial zones to residential to space ports, all can be large and small)
- Bright (the utopian aesthetic lends itself well to shadow-less implementation)
- Roads (whilst roads are a nice feature of a city, I fancied avoiding them and making the building interconnections more futuristic, for pedestrians or flying vehicles)
- Surfaces (futuristic, high-tech structures are likely to be clean and smooth, the need for texturing reduced)
- Transparency (glass facades and water features really say 'futuristic' and 'utopia' to me)
- Shaders (general shader support would allow all sorts of polish like fog/sky/sun to be added as well as some simple water surface effects and procedural texturing)
Cities are popular choice when showing off procedural techniques and there are several sources of inspiration that have led me here, these are described below:
It's worth drawing attention to two significant city based works of procedural generation that really excite me:
I fell in love with Pixel City the moment I saw it. A brilliantly executed exercise in procedural generation. More pictures and information here:
- Video: Pixel City - Procedurally generated city
- Blog documenting its development: http://www.shamusyoung.com/twentysidedtale/?p=2940
Also; There has been some fairly sophisticated procedural modelling tools and tech being built for "Project Sprawl", a cyberpunk role-playing simulation, again an inspiration:
- City generation video: https://twitter.com/delacian/status/698922063675969537
- Scrap-book on tumblr: http://delacian.tumblr.com/
Just searching online for Procedural Cities yields lots of other projects in this vein. I don't think another one is likely to hurt, and it gives me a good benchmark to aim for.
I've started to collect reference material on a Sci-fi Cities Pinterest page as a 'mood board' and ideas page.
I have previously been using skyscrapers as a test case and thinking about what structural components could appear on them in a traditional large city:
|Sketching elements of contemporary skyscrapers|
Whilst I was on holiday (sitting in the sun by the pool) I spent some time sketching ideas for more futuristic city elements too.
|Sketching elements of a futuristic city|
Whilst we were in France we took a day to visit the Futuroscope theme park which was full of examples of all sorts of futuristic buildings, technology, and experiences. It had some really quite interesting landscaping and architecture:
|Walkways and water features at Futuroscope|
|Interesting buildings at Futuroscope|
|Fantastical architecture at Futuroscope|
Some features I'd like to see in the city include:
- Non-conventional skyscrapers
- Lots of 'sci-fi' surface detail
- Open plazas with angular water features
- Docked spacecraft
- Multi-level public spaces, stairs
- Monuments and arenas
- Glass facades revealing interior spaces
- Distant mountain ranges
- Variable time of day/night (static)
- Lots of technology; aerial masts, industrial complexes
- Names in lights on buildings
- Street and window lighting
- Automatic fly-through for use as screen-saver
- Manual control for exploration (fly-cam)
As part of 'Future City' demo development I'd like to gather thoughts and ideas from you. No matter how long ago this was posted, comments are welcome, please contribute ideas in the comments below. I look forward to your thoughts :)