About CityEngine Blog
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.
Sunday, 29 September 2013
Uses and users of CityEngine and CityEngine 2013
A recent article on Computer World outlined the use that had been made of CityEngine across a number of different industries. Recently, according to the article, the entertainment industry has used CityEngine to produce a number of cityscapes for films such as the latest reincarnation of Superman - Man of Steel, Cars 2 and Total Recall. Now, the pipeline for city generation should be made more efficient for this industry with the upcoming release of CityEngine 2013.
CityEngine 2013 sees the additon of an SDK (Software Development Kit) that will allow users of software such as Maya to procedurally generate models inside this software, instead of in CityEngine. The entertainment industry especially has pretty high standards when it comes to the quality of the visual output of CityEngine. Being able to marry up the procedural power of CityEngine and a high end graphics package like Maya we should be looking at some seriously awesome work.
The SDK is just one of a few small hints that Esri have released regarding CityEngine 2013. I have in the last week or so watched a few webinars through Directions Magazine. People such as Geoff Taylor and Eric Wittner have been bringing some of the latest information to the geospatial masses. There seems to be quite a few updates in the upcoming version but I've yet to see a clearly defined list of what's new.
It is obvious that Esri are having to service a number of different industries and so far the integration with the geospatial world has been steady. Obviously the SDK is made to service the entertainment industry. This got me thinking what industries would be the main users of CityEngine:
1. Government - Planning, Engineering, Architecture, Urban Design
2. Entertainment - Films, Advertising, Gaming
3. Military - Simulation
I'm pretty sure that there could be a wide range of other uses too. CityEngine is by name a city generation tool. However, many of the operations could be used to create all kinds of models based on any kind of input geometry. Making the operations work on a project that isn't city based could be a good way of showing the potential of other industries also using the software. I'll have to have a think about that and come up with something that is fun, will teach me some new techniques and that could be applicable to an industry.
Getting back to the Computer World article, Gert van Maren mentions some of the work that Auckland Council have done regarding a land resource document called the Unitary Plan. This is one of the major projects that I've been lucky enough to work on and I'll be reporting on some of the things I learnt in carrying out this project in upcoming posts.
Thursday, 26 September 2013
(Re)Tweet City - A great use of CityEngine from en-topia
Please take a look at the outstanding blog post here from en-topia. They have even been kind enough to provide sample rules and instructions through GitHub
If you're not into the developer world or like me just getting into it, the number of API's seems to increase ten-fold by the day into a dizzying array of wonderful tools that allow access to all kinds of exciting data. One of these API's is the Twitter API. My very shallow knowledge of the API is that it can be used to carry out a search of tweets, providing back a list that, if geotagged, can be mapped.
The guys at en-topia have taken the simple 2D mapping of Twitter data another step forward by applying geotagged tweets to buildings. The 2D building data is plugged into CityEngine and a rule file is applied giving the building an extrusion based on the number of tweets located in or around that building. From what I can take from their article they are able to take live feeds from Twitter (or a search result over a given period of time) and feed this into CityEngine, outputting a time-lapse style video. Of course the tweets can be applied to any 2D data you wish, in another example they show the data applied to a 1km grid instead of buildings. Depending on the scale of the area you wish to show this is a great example of how easily CityEngine can be used to create the same type of output but for different inputs but based on the same attributes.
I guess the next step, which is in the hands of Esri, would be to make it possible to create a 3D Web Scene that itself can handle ongoing updates and show 'live' data that is supplied by a pipeline of (Python?) processes.
This is such a great use of CityEngine, I think anyone who sees this and understands the power of the Twitter API and/or CityEngine instantly sees the potential to make something similar for their area of expertise.
Tuesday, 17 September 2013
CityEngine Starter Project 7 - Lessons learnt and the full rule file
Lessons learnt
As a result of this project I had learnt a number of things regarding rule file creation:
- How to structure the rule file
- How to create attributes and give them additional information such as a range
- How to create functions and loops within the rule file
- How to create a conditional (case) statement
Within the rule file I also was able to understand and use a number of CityEngine operations including:
- Split
- Extrude
- Comp
- Align
- Set
- Report
- Setback
- Roof operations
- Translate
Looking back at what I intended to achieve a result of the project, I think I covered everything pretty well. I created a basic street and parcel network, however, I think that maybe some of the parcels are either to big and / or I could have added more streets. I created a rule file that included some very basic planning rules, I will of course include more rules in future but this will also require me to understand what the planning rules are, what they intend to allow or not allow to happen on a zone and how this can be translated into a rule file. I also created an output visualisation, this step was by far the easiest and using the Web Scene technology is something that I very much look forward to utilising again in future.
Below is the full rule file created for this project:
/**
* File:
StarterProject.cga
* Created: 01 Jan 2013 01:02:07 GMT
* Author:
ellawayc
*/
version "2012.1"
## Hidden Attributes ##
@Hidden
attr ParcelArea = 0
@Hidden
attr FootprintNeeded = 0
@Hidden
attr Length = 0
@Hidden
attr Width = 0
## Attributes ##
@Range("Residential","Commercial")
attr ZONETYPE = "Residential"
@Range(0,5)
attr YARD = 2.5
@Range(25,100)
attr COVERAGE = 30
## Functions ##
getHeight =
25%
: 8.5
50%
: 12.5
else : 16.5
## Constants ##
## Assets ##
## Rules
@startRule
Lot -->
alignScopeToGeometry(yUp, auto)
set(ParcelArea, geometry.area)
report("A Parcel
Area (m2)", ParcelArea)
Lot1
Lot1 -->
case ZONETYPE == "Residential" : ResidentialLot
else : CommercialLot
##### Residential Zone #####
ResidentialLot -->
setback(YARD) {street.front
: NIL | remainder : ResidentialLot2}
ResidentialLot2 -->
innerRect
shapeL(scope.sz*0.75,scope.sx*0.75) {shape : ResidentialLot3 | remainder : NIL}
ResidentialLot3 -->
set(FootprintNeeded, (ParcelArea/100)*COVERAGE)
report("B
Footprint Needed (m2)", FootprintNeeded)
ResidentialLot4
ResidentialLot4 -->
case geometry.area > FootprintNeeded : s('0.99,0,'0.99) center(xz) ResidentialLot4
else : ResidentialLot5
ResidentialLot5 -->
extrude(world.y, 5)
split(y){~0.25 : ResidentialLot6 BaseKeeper | 5 : NIL}
ResidentialLot6 -->
comp(f){top : alignScopeToGeometry(yUp, auto) ResidentialLot7}
ResidentialLot7 -->
extrude(5.5)
comp(f){top : Roof | all : ResidentialLot8}
Roof -->
roofHip(18.5, 0.4)
##### Commercial Zone #####
CommercialLot -->
innerRect
alignScopeToGeometry(yUp, 0,
longest)
set(Length, scope.sx)
set(Width, scope.sz)
report("B Length
(m)", Length)
report("C Width
(m)", Width)
CommercialLot1
CommercialLot1 -->
20%
: CommercialLot3
else :
case ParcelArea < 500 : CommercialLot3
case Width < 15 :
50%
: setback(4){street.left
: NIL | remainder : CommercialLot2}
else : setback(4){street.right : NIL | remainder : CommercialLot2}
else :
50%
: setback(scope.sz*0.2){street.left
: NIL | remainder : CommercialLot2}
else : setback(scope.sz*0.2){street.right
: NIL | remainder : CommercialLot2}
CommercialLot2 -->
20%
: CommercialLot3
else :
case Length > 30 : setback(scope.sx*0.3){street.back
: NIL | remainder : CommercialLot3}
else :
50%
: setback(4){street.back
: NIL | remainder : CommercialLot3}
else : CommercialLot3
CommercialLot3 -->
extrude(world.y, 5)
split(y){~0.25 : CommercialLot4 BaseKeeper | 5 : NIL}
CommercialLot4 -->
comp(f){top : alignScopeToGeometry(yUp, auto) CommercialLot5}
CommercialLot5 -->
extrude(getHeight)
split(y){4.5 : GroundFloor | {~4 : UpperFloor(split.index, split.total)}*}
GroundFloor -->
comp(f){side: GroundFloor1}
GroundFloor1 -->
split(x){0.5 : Wall | ~5 : LargeWindow | 3 : Entrance | {~5 : LargeWindow}* | 0.5 : Wall}
UpperFloor(idx,n) -->
case idx == n-1 : TopFloor UpperFloor1
else : UpperFloor1
UpperFloor1 -->
comp(f){side: UpperFloor2}
UpperFloor2 -->
split(x){0.5 : Wall | {~2.5 : Window}* | 0.5 : Wall}
LargeWindow -->
split(x){0.25 : SolidWall | ~5 : split(y){0.50 : SolidWall | ~1 : LargeWindow1 | 0.25 : SolidWall} | 0.25 : SolidWall}
LargeWindow1 -->
t(0,0,-0.4)
Window -->
split(x){0.2 : SolidWall | ~2.5 : split(y){0.2 : SolidWall | ~1 : Window1 | 0.2 : SolidWall} | 0.2 : SolidWall}
Window1 -->
t(0,0,-0.2)
Entrance -->
split(x){0.2 : SolidWall | ~2.5 : split(y){~1 : Entrance1 | 0.35 : SolidWall} | 0.2 : SolidWall}
Entrance1 -->
t(0,0,-0.4)
SolidWall -->
extrude(0.4)
t(0,-0.4,0)
TopFloor -->
comp(f){top : CommercialRoof}
CommercialRoof -->
extrude(0.15)
comp(f){top : CommercialRoof1 RoofKeeper | all : RoofKeeper }
CommercialRoof1 -->
setback(0.4){all : CommercialRoof2}
CommercialRoof2 -->
extrude(0.4)
Subscribe to:
Posts (Atom)