Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
node_modules
npm-debug.log
114 changes: 80 additions & 34 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,45 +1,91 @@


# Project 4: Shape Grammar

For this assignment you'll be building directly off of Project 3. To make things easier to keep track of, please fork and clone this repository [https://github.com/CIS700-Procedural-Graphics/Project4-Shape-Grammar](https://github.com/CIS700-Procedural-Graphics/Project4-Shape-Grammar) and copy your Project 3 code to start.
I built a suburban neighborhood. The final product can be found at https://tabathah.github.io/Project4-Shape-Grammar.
The following as an overview of how I completed this projet. Some pictures of the final product from above and from a side view are here:

![](./progShots/final-from-above.PNG)

![](./progShots/final-from-side.PNG)

**Creating the Homes**

Each of the homes in this neighborhood was procedurally generated using a shape grammar. I started with one initial shape and that shape was subdivided or rotated based on random probability in order to get a fairly realistic looking suburban home.

The shapes were represented by a Shape class that had the following information: a character symbol representing what time of shape it was so that following transformations and rendering of the shape would be done properly, the position, rotation, and scale of the shape, used to create the mesh that appears on screen, the material of the shape so that through each of the iterations of the shapes changing they would all remain the same colors, vectors representing the local x and z axes of the shape so that when new positions were calculated, they would be moved in relation to the shapes current orientation, and finally a boolean representing whether this shape should have a door.

My initial shape was a simple house shape with a rectangular box and triangular prism on top, which I created in Maya and imported as an OBJ file. The initial OBJ is depicted below:

![](./progShots/original-house-geo.PNG)

I wrote shaders for the texturing of the houses. One of two roof colors and one of three wall colors was randomly chosen and sent into the shader. In the fragment shader, the normal at that point was checked for a non-zero y-component. If the y was non-zero, it had to be a part of the roof so it was colored with the input roof color, otherwise it was part of a wall so it was colored with the input wall color. Here is the result:

![](./progShots/house-shader.PNG)

At the first iteration of executing the grammar, the house always subdivides along its z axis in half. Then one of three configurations can happen with some probability. In the first possible configuration, the front half of house resulting from the subdivision is scaled down by half in the z direction and moved to either the left or right side of the house. In the second configuration, the front half from the subdivision is discarded and two house shapes of depth equal to half the back half from the subdivision's width are rotated 90 degrees and placed in the front of the house. In the third and final configuration, a similar operation is done as the second configuration, except three house shapes of depth equal to a third of the back half's width are placced in the front of the house. Here are pictures of the first, second, and third configurations, respectively:

![](./progShots/config1.PNG)

![](./progShots/config2.PNG)

![](./progShots/config3.PNG)

At the second iteration of executing the grammar, the shapes are slightly modified and detail additions are made. In the case of the first configuration, another scaled down shape is added to the inner side of the front shape, as depicted below:

![](./progShots/config1Add.PNG)

In the case of the second and third conifgurations, the rotated shapes in the front are modified in the following way. Either the shape is deleted entirely, unchanged, its height is scaled by 1.25, or its height is scaled by 1.5. Here is a picture of a house with fronts of all diferrent heights.

![](./progShots/c-builds-modif.PNG)

Finally, at the second iteration, I modified the back half of the houses, which was in all three configurations. Firstly, with some probability I had the height scale up by 1.5. This is the first picture below. Secondly, I added a chimney to either the right or left side of the back of the house. I shaded this chimney with the same shader on the house. A chminey is shown in the second picture below:

![](./progShots/back-half-height.PNG)

![](./progShots/chimney.PNG)

For both the height modification of the back half and the rotated fron house shapes, I increased the probability of the height scaling up in relation to the z coordinate of the shapes position. This way, on one side of the nieghborhood the houses tend to be taller than on the other side, formins some sort of class division if you will.

One last extra detail was the doors. If the house went into the first configuration at the first iteration, the door ended up on the inner house shape that gets added in the second iteration. If the house went into one of the other two configurations, one of the two or three front rotated shapes was randomly chosen to have a door on it. If that shape was not detroyed in the second iteration, the door was placed in the front of it, otherwise it was placed on the back half of the house. Two examples of doors are shown below:

![](./progShots/doors2.PNG)

![](./progShots/doors.PNG)

**Forming the Neighborhood Layout**

I first started with two straight main streets on either side of my neighborhood, shaded grey:

![](./progShots/two-side-roads.PNG)

I then created the roads that my houses would be situated on. I created 5 three.js CatmullRom curves by making points out of equally spaced x values and z values that had some random offset between -6 and 6. I then added road squares to points on the curve to display the curves.

![](./progShots/add-road-splines.PNG)

Now it was time to add houses onto the roads. At evenly spaced points on the curve I put homes and rotated them so they would be parallel to the tangent of the curve at that point. I also offset them a bit away from the curve in the z direction so they would be next to the road rather than on it.

Here is a picture of houses on one side of the road:

![](./progShots/place-homes-on-road.PNG)

And here is a picture of houses on both sides (the houses were rotated so that they would be facing the road):

![](./progShots/houses-on-both-sides.PNG)

**Goal:** to model an urban environment using a shape grammar.
**Adding Details**

**Note:** We’re well aware that a nice-looking procedural city is a lot of work for a single week. Focus on designing a nice building grammar. The city layout strategies outlined in class (the extended l-systems) are complex and not expected. We will be satisfied with something reasonably simple, just not a uniform grid!
The first detail I added was driveways. I simply added a road square in the same positions where houses were added, offset from the road slightly less than the houses were to create a semblance of a driveway.

## Symbol Node (5 points)
Modify your symbol node class to include attributes necessary for rendering, such as
- Associated geometry instance
- Position
- Scale
- Anything else you may need
![](./progShots/driveways.PNG)

## Grammar design (55 points)
- Design at least five shape grammar rules for producing procedural buildings. Your buildings should vary in geometry and decorative features (beyond just differently-scaled cubes!). At least some of your rules should create child geometry that is in some way dependent on its parent’s state. (20 points)
- Eg. A building may be subdivided along the x, y, or z axis into two smaller buildings
- Some of your rules must be designed to use some property about its location. (10 points)
- Your grammar should have some element of variation so your buildings are non-deterministic. Eg. your buildings sometimes subdivide along the x axis, and sometimes the y. (10 points)
- Write a renderer that will interpret the results of your shape grammar parser and adds the appropriate geometry to your scene for each symbol in your set. (10 points)
Next I decided to make trees. Again I created my own model in Maya and imported it as an OBJ. I shaded them the same way I shaded houses, as again any normals with non-zero y-components corresponded to leaves and the others were part of the trunk. I wanted the trees to populate the empty space between the roads my houses were on. To do this, I found the difference between the z coordinates of points on two consecutive roads and added trees in the space where they wouldnt overlap the houses or roads. At every point where a tree could be placed I added it with a 50% chance. I also offset them in the x and z randomly to give the semblance of realistic tree populating. The result was the following:

## Create a city (30 points)
- Add a ground plane or some other base terrain to your scene (0 points, come on now)
- Using any strategy you’d like, procedurally generate features that demarcate your city into different areas in an interesting and plausible way (Just a uniform grid is neither interesting nor plausible). (20 points)
- Suggestions: roads, rivers, lakes, parks, high-population density
- Note, these features don’t have to be directly visible, like high-population density, but they should somehow be visible in the appearance or arrangement of your buildings. Eg. High population density is more likely to generate taller buildings
- Generate buildings throughout your city, using information about your city’s features. Color your buildings with a method that uses some aspect of its state. Eg. Color buildings by height, by population density, by number of rules used to generate it. (5 points)
- Document your grammar rules and general approach in the readme. (5 points)
- ???
- Profit.
![](./progShots/trees-birds-eye.PNG)

## Make it interesting (10)
Experiment! Make your city a work of art.
![](./progShots/trees-low-view.PNG)

The last detail I added was lamp posts. I created my own, very crude geometry in Maya. I added them on either side of both the main side roads and the roads the houses resided on. A closeup is depicted here:

![](./progShots/lampposts-closeup.PNG)

## Warnings:
You can very easily blow up three.js with this assignment. With a very simple grammar, our medium quality machine was able to handle 100 buildings with 6 generations each, but be careful if you’re doing this all CPU-side.

## Suggestions for the overachievers:
Go for a very high level of decorative detail!
Place buildings with a strategy such that buildings have doors and windows that are always accessible.
Generate buildings with coherent interiors
If dividing your city into lots, generate odd-shaped lots and create building meshes that match their shape ie. rather than working with cubes, extrude upwards from the building footprints you find to generate a starting mesh to subdivide rather than starting with platonic geometry.
Binary file added Sky-Blue-Sky.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
38 changes: 38 additions & 0 deletions deploy.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
var colors = require('colors');
var path = require('path');
var git = require('simple-git')(__dirname);
var deploy = require('gh-pages-deploy');
var packageJSON = require('require-module')('./package.json');

var success = 1;
git.fetch('origin', 'master', function(err) {
if (err) throw err;
git.status(function(err, status) {
if (err) throw err;
if (!status.isClean()) {
success = 0;
console.error('Error: You have uncommitted changes! Please commit them first'.red);
}

if (status.current !== 'master') {
success = 0;
console.warn('Warning: Please deploy from the master branch!'.yellow)
}

git.diffSummary(['origin/master'], function(err, diff) {
if (err) throw err;

if (diff.files.length || diff.insertions || diff.deletions) {
success = 0;
console.error('Error: Current branch is different from origin/master! Please push all changes first'.red)
}

if (success) {
var cfg = packageJSON['gh-pages-deploy'] || {};
var buildCmd = deploy.getFullCmd(cfg);
deploy.displayCmds(deploy.getFullCmd(cfg));
deploy.execBuild(buildCmd, cfg);
}
})
})
})
Binary file added house.mb
Binary file not shown.
6 changes: 6 additions & 0 deletions house.mtl
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
newmtl initialShadingGroup
illum 4
Kd 0.50 0.50 0.50
Ka 0.00 0.00 0.00
Tf 1.00 1.00 1.00
Ni 1.00
111 changes: 111 additions & 0 deletions house.obj
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
# This file uses centimeters as units for non-parametric coordinates.

mtllib house.mtl
g default
v -1.351567 1.002031 2.587286
v 1.351567 1.002031 2.587286
v -0.126426 1.983041 1.975369
v 0.126426 1.983041 1.975369
v -0.126426 1.983041 -1.975369
v 0.126426 1.983041 -1.975369
v -1.351567 1.002031 -2.587286
v 1.351567 1.002031 -2.587286
v -1.208793 -1.024707 2.339137
v 1.208793 -1.024707 2.339137
v -1.208793 1.024707 2.339137
v 1.208793 1.024707 2.339137
v -1.208793 1.024707 -2.339137
v 1.208793 1.024707 -2.339137
v -1.208793 -1.024707 -2.339137
v 1.208793 -1.024707 -2.339137
vt 0.375000 0.000000
vt 0.625000 0.000000
vt 0.375000 0.250000
vt 0.625000 0.250000
vt 0.375000 0.500000
vt 0.625000 0.500000
vt 0.375000 0.750000
vt 0.625000 0.750000
vt 0.375000 1.000000
vt 0.625000 1.000000
vt 0.875000 0.000000
vt 0.875000 0.250000
vt 0.125000 0.000000
vt 0.125000 0.250000
vt 0.375000 0.000000
vt 0.625000 0.000000
vt 0.625000 0.250000
vt 0.375000 0.250000
vt 0.625000 0.500000
vt 0.375000 0.500000
vt 0.625000 0.750000
vt 0.375000 0.750000
vt 0.625000 1.000000
vt 0.375000 1.000000
vt 0.875000 0.000000
vt 0.875000 0.250000
vt 0.125000 0.000000
vt 0.125000 0.250000
vn 0.000000 0.529244 0.848470
vn 0.000000 0.529244 0.848470
vn 0.000000 0.529244 0.848470
vn 0.000000 0.529244 0.848470
vn 0.000000 1.000000 0.000000
vn 0.000000 1.000000 0.000000
vn 0.000000 1.000000 0.000000
vn 0.000000 1.000000 0.000000
vn 0.000000 0.529244 -0.848470
vn 0.000000 0.529244 -0.848470
vn 0.000000 0.529244 -0.848470
vn 0.000000 0.529244 -0.848470
vn 0.000000 -1.000000 0.000000
vn 0.000000 -1.000000 0.000000
vn 0.000000 -1.000000 0.000000
vn 0.000000 -1.000000 0.000000
vn 0.625043 0.780590 0.000000
vn 0.625043 0.780590 0.000000
vn 0.625043 0.780590 0.000000
vn 0.625043 0.780590 0.000000
vn -0.625043 0.780590 0.000000
vn -0.625043 0.780590 0.000000
vn -0.625043 0.780590 0.000000
vn -0.625043 0.780590 0.000000
vn 0.000000 0.000000 1.000000
vn 0.000000 0.000000 1.000000
vn 0.000000 0.000000 1.000000
vn 0.000000 0.000000 1.000000
vn 0.000000 1.000000 0.000000
vn 0.000000 1.000000 0.000000
vn 0.000000 1.000000 0.000000
vn 0.000000 1.000000 0.000000
vn 0.000000 0.000000 -1.000000
vn 0.000000 0.000000 -1.000000
vn 0.000000 0.000000 -1.000000
vn 0.000000 0.000000 -1.000000
vn 0.000000 -1.000000 0.000000
vn 0.000000 -1.000000 0.000000
vn 0.000000 -1.000000 0.000000
vn 0.000000 -1.000000 0.000000
vn 1.000000 0.000000 0.000000
vn 1.000000 0.000000 0.000000
vn 1.000000 0.000000 0.000000
vn 1.000000 0.000000 0.000000
vn -1.000000 0.000000 0.000000
vn -1.000000 0.000000 0.000000
vn -1.000000 0.000000 0.000000
vn -1.000000 0.000000 0.000000
s off
g pCube3
usemtl initialShadingGroup
f 1/1/1 2/2/2 4/4/3 3/3/4
f 3/3/5 4/4/6 6/6/7 5/5/8
f 5/5/9 6/6/10 8/8/11 7/7/12
f 7/7/13 8/8/14 2/10/15 1/9/16
f 2/2/17 8/11/18 6/12/19 4/4/20
f 7/13/21 1/1/22 3/3/23 5/14/24
f 9/15/25 10/16/26 12/17/27 11/18/28
f 11/18/29 12/17/30 14/19/31 13/20/32
f 13/20/33 14/19/34 16/21/35 15/22/36
f 15/22/37 16/21/38 10/23/39 9/24/40
f 10/16/41 16/25/42 14/26/43 12/17/44
f 15/27/45 9/15/46 11/18/47 13/28/48
19 changes: 19 additions & 0 deletions index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<!DOCTYPE html>
<html>
<head>
<title>HW2: LSystems</title>
<style>
html, body {
margin: 0;
overflow: hidden;
}
canvas {
width: 100%;
height: 100%;
}
</style>
</head>
<body>
<script src="bundle.js"></script>
</body>
</html>
Binary file added lamppost.mb
Binary file not shown.
6 changes: 6 additions & 0 deletions lamppost.mtl
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
newmtl initialShadingGroup
illum 4
Kd 0.50 0.50 0.50
Ka 0.00 0.00 0.00
Tf 1.00 1.00 1.00
Ni 1.00
Loading