Tools for the procedural modelling of buildings
Project description
Procedural Generation of Buildings
Welcome to my third year university project on the procedural generation of buildings!
There are two main goals for this project:
- Design a grammar language that can be used to describe buildings with sets of procedural rules, which can then be transformed into a 3D models
- Given an example set of 3D buildings, attempt to reverse engineer a grammar from the given buildings, which could then be used to create more buidings similar to the examples
To discover how I achieved the above, I encourage you to read (or perhaps just flick through!) my project report. The report also teaches you how to write your own grammars and demonstrates some of my own architectural creations.
If you want to have a go at writing your own grammars and generating your own buildings, read on!
Installation (using Pip)
This project is packaged and available on PyPi and can be installed (or updated) with the following:
python -m pip install --upgrade procedural-buildings
Basic usage
Writing your first grammar
If you want to learn the ins and outs of writing a grammar, read my report. Here we'll learn by example and leave the rest to intuition!
A grammar is run on an initial scope (a 3D bounding box) and consists of a set of rules, one of which is a start rule. By default, the start rule is plot
but you can specify a different name if you'd prefer. The following grammar takes the initial scope and splits it in half along the x-axis into two cuboids:
plot --> split(x){~1 : I(rect) | ~1 : I(rect)}
Save the above to a new file called split_grammar
(make sure to include a newline at the end as above). We can then generate a .obj
file from the grammar using the following on the command line:
python -m procedural_buildings -i split_grammar -o split.obj
This will create a 3D model in split.obj
. Open this in your favourite 3D model viewer (I recommend Blender), noting that the positive z-axis corresponds to upward and the positive y-axis corresponds to foward. Blender lets you specify these axis directions when you import an object. You should see a 10x10x10 cube which is cut in half along the x-axis. To change the initial scope (which defaults to the 10x10x10 cube you see), use the -s
(or --start-scope
) option. To see a full list of options, use -h
:
python -m procedural_buildings -i split_grammar -o split.obj -s 2,2,0,10,5,20
Play around with different start scopes and check out the results.
Creating a house
Now lets look at a slightly more interesting example - a house with a garage. Copy the following grammar into a new file called house_grammar
. Once again, don't forget the newline (I really ought to change that "feature"!):
plot --> split(x){~2 : house | ~1 : garage}
house --> split(z){~2 : I(rect) | ~1 : I(triangle)}
garage --> split(z){~1 : I(rect) | ~2 : nil}
Now generate the buildings with:
python -m procedural_buildings -i house_grammar -o house.obj
Take a look at house.obj
and try and understand how it's been generated by the grammar we wrote. Play around with some numbers in the grammar to see how it affects the result.
As a final example, let's adapt house_grammar
so it has some randomness. Copy the below into a new file called house2_grammar
:
plot --> split(x){~2 : house | ~1 : garage} : 0.5
plot --> split(x){~1 : garage | ~2 : house} : 0.5
house --> split(z){~2 : I(rect) | ~1 : I(triangle)}
garage --> split(z){~(rand(0.75,1.25)) : I(rect) | ~2 : nil}
See if you can figure out what the result will look like then generate a building:
python -m procedural_buildings -i house2_grammar -o house2.obj
Notice that if you run the above command a few times, the result will be different each time.
To generate many buildings from our grammar, we can use the following options:
-n
(or--num_buildings
) (default 1) specifies the number of buildings to generate from the grammar-d
(or--separation
) (default 10) specifies the distance between buldings.-f
(of--file_per_obj
) specifies whether to use a separate file for each building. In this case the-d
option will be ignored and the given output file name will be used as the file prefix to use for the output files.
Let's create 10 buildings each 2 units apart. We'll stick to one output file for now:
python -m procedural_buildings -i house2_grammar -o house2.obj -n 10 -d 2
How about backwards?
To create a grammar from a given buildings, we can use the -r
(or --reverse
) flag. Now, our input file is the .obj
file and the output is a grammar file. Let's try and reverse engineer the grammar we used to create the first house:
python -m procedural_buildings -i house.obj -o house_engineered_grammar -r
Take a look at house_engineered_grammar
and you should see its equivalence to the original house_grammar
.
Now lets try and engineer a grammar from mutliple example buildings. First create 10 example buildings using house2_grammar
. We'll put them in separate files this time by using the -f
flag. The output file name example
will be used as the prefix for the 10 output files so we'll get example0.obj
, example1.obj
, ... , example9
:
python -m procedural_buildings -i house2_grammar -o example -n 10 -f
Now we can create a grammar from the example buildings. Create a new file called examples
and enter the file names of the example buildings:
example0.obj
example1.obj
example2.obj
example3.obj
example4.obj
example5.obj
example6.obj
example7.obj
example8.obj
example9.obj
Now, create a grammar from the buildings. The input file will be the file containing the file names (it knows it's a list of file names rather than a single object input by checking for a .obj
extension):
python -m procedural_buildings -i examples -o house2_engineered_grammar -r
Take a look at the engineered grammar. You should be able to see the similarity to the original house2_grammar
.
We can now use our engineered grammar to create more buildings. Note that we'll have to specify that the start rule for this grammar is rule0
:
python -m procedural_buildings -i house2_engineered_grammar -o more_houses.obj -n 10 -R rule0
You've now generated 10 buildings similar to the 10 examples.
To see some more complex examples, check out my report or create your own buildings!
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
File details
Details for the file procedural-buildings-1.0.1.tar.gz
.
File metadata
- Download URL: procedural-buildings-1.0.1.tar.gz
- Upload date:
- Size: 110.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/3.2.0 pkginfo/1.5.0.1 requests/2.24.0 setuptools/50.3.0 requests-toolbelt/0.9.1 tqdm/4.50.2 CPython/3.9.0
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | cd64043575ed3070b513b1df41aa31b5718bc4488941a887b19544ca7c8983b2 |
|
MD5 | d715579027c3dd54b7fdab1ad08eb93f |
|
BLAKE2b-256 | 62b2c73a3105a19b5b1fde14eb03855c9449761f6f975f29f6ac87fa2a8f2036 |
File details
Details for the file procedural_buildings-1.0.1-py3-none-any.whl
.
File metadata
- Download URL: procedural_buildings-1.0.1-py3-none-any.whl
- Upload date:
- Size: 115.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/3.2.0 pkginfo/1.5.0.1 requests/2.24.0 setuptools/50.3.0 requests-toolbelt/0.9.1 tqdm/4.50.2 CPython/3.9.0
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 40dffa1b54ba899f0cc3567c5341aa3f11ca0827e5d80f61ba33cd47ba4fd34d |
|
MD5 | 225fc780ec4e20085f7cc9aff2fde632 |
|
BLAKE2b-256 | 54b3f25eaad3c1cb97cdc4a5b5d4189606a1fe5f4263bd17239c8be00a263647 |