From c2b3a7c10022547ff870b4318375dada60730f67 Mon Sep 17 00:00:00 2001 From: eldu Date: Sun, 12 Feb 2017 20:10:33 -0500 Subject: [PATCH 01/16] Loaded project 3 --- .gitignore | 2 + deploy.js | 38 ++++++++ index.html | 19 ++++ package.json | 31 +++++++ src/framework.js | 72 ++++++++++++++++ src/linkedlist.js | 76 ++++++++++++++++ src/lsystem.js | 214 ++++++++++++++++++++++++++++++++++++++++++++++ src/main.js | 68 +++++++++++++++ src/turtle.js | 130 ++++++++++++++++++++++++++++ webpack.config.js | 28 ++++++ 10 files changed, 678 insertions(+) create mode 100644 .gitignore create mode 100644 deploy.js create mode 100644 index.html create mode 100644 package.json create mode 100644 src/framework.js create mode 100644 src/linkedlist.js create mode 100644 src/lsystem.js create mode 100644 src/main.js create mode 100644 src/turtle.js create mode 100644 webpack.config.js diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..5171c540 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +node_modules +npm-debug.log \ No newline at end of file diff --git a/deploy.js b/deploy.js new file mode 100644 index 00000000..9defe7c3 --- /dev/null +++ b/deploy.js @@ -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); + } + }) + }) +}) \ No newline at end of file diff --git a/index.html b/index.html new file mode 100644 index 00000000..e609adf4 --- /dev/null +++ b/index.html @@ -0,0 +1,19 @@ + + + + HW2: LSystems + + + + + + diff --git a/package.json b/package.json new file mode 100644 index 00000000..be683fcb --- /dev/null +++ b/package.json @@ -0,0 +1,31 @@ +{ + "scripts": { + "start": "webpack-dev-server --hot --inline", + "build": "webpack", + "deploy": "node deploy.js" + }, + "gh-pages-deploy": { + "prep": [ + "build" + ], + "noprompt": true + }, + "dependencies": { + "dat-gui": "^0.5.0", + "gl-matrix": "^2.3.2", + "stats-js": "^1.0.0-alpha1", + "three": "^0.82.1", + "three-orbit-controls": "^82.1.0" + }, + "devDependencies": { + "babel-core": "^6.18.2", + "babel-loader": "^6.2.8", + "babel-preset-es2015": "^6.18.0", + "colors": "^1.1.2", + "gh-pages-deploy": "^0.4.2", + "simple-git": "^1.65.0", + "webpack": "^1.13.3", + "webpack-dev-server": "^1.16.2", + "webpack-glsl-loader": "^1.0.1" + } +} diff --git a/src/framework.js b/src/framework.js new file mode 100644 index 00000000..76f901a5 --- /dev/null +++ b/src/framework.js @@ -0,0 +1,72 @@ + +const THREE = require('three'); +const OrbitControls = require('three-orbit-controls')(THREE) +import Stats from 'stats-js' +import DAT from 'dat-gui' + +// when the scene is done initializing, the function passed as `callback` will be executed +// then, every frame, the function passed as `update` will be executed +function init(callback, update) { + var stats = new Stats(); + stats.setMode(1); + stats.domElement.style.position = 'absolute'; + stats.domElement.style.left = '0px'; + stats.domElement.style.top = '0px'; + document.body.appendChild(stats.domElement); + + var gui = new DAT.GUI(); + + var framework = { + gui: gui, + stats: stats + }; + + // run this function after the window loads + window.addEventListener('load', function() { + + var scene = new THREE.Scene(); + var camera = new THREE.PerspectiveCamera( 75, window.innerWidth/window.innerHeight, 0.1, 1000 ); + var renderer = new THREE.WebGLRenderer( { antialias: true } ); + renderer.setPixelRatio(window.devicePixelRatio); + renderer.setSize(window.innerWidth, window.innerHeight); + renderer.setClearColor(0x020202, 0); + + var controls = new OrbitControls(camera, renderer.domElement); + controls.enableDamping = true; + controls.enableZoom = true; + controls.target.set(0, 0, 0); + controls.rotateSpeed = 0.3; + controls.zoomSpeed = 1.0; + controls.panSpeed = 2.0; + + document.body.appendChild(renderer.domElement); + + // resize the canvas when the window changes + window.addEventListener('resize', function() { + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + renderer.setSize(window.innerWidth, window.innerHeight); + }, false); + + // assign THREE.js objects to the object we will return + framework.scene = scene; + framework.camera = camera; + framework.renderer = renderer; + + // begin the animation loop + (function tick() { + stats.begin(); + update(framework); // perform any requested updates + renderer.render(scene, camera); // render the scene + stats.end(); + requestAnimationFrame(tick); // register to call this again when the browser renders a new frame + })(); + + // we will pass the scene, gui, renderer, camera, etc... to the callback function + return callback(framework); + }); +} + +export default { + init: init +} \ No newline at end of file diff --git a/src/linkedlist.js b/src/linkedlist.js new file mode 100644 index 00000000..6b8c4861 --- /dev/null +++ b/src/linkedlist.js @@ -0,0 +1,76 @@ +export default class LinkedList { + constructor() { + this.head = null; + this.tail = null; + }; + + // Pushes node with value into the LL + push(value) { + var node = { + value: value, + next: null, + prev: null + } + + if (this.head === null) { + // First element + this.head = node; + this.tail = node; + } else { + // Add to end of list + node.prev = this.tail; + this.tail.next = node; + this.tail = node; // Update tail + } + }; + + // Pops node off of the LL + pop() { + // 0 Elements + if (this.head === null) { + return null; + } + + // 1 Element + else if (this.tail === this.head) { + var node = this.head; + + this.head = null; + this.tail = null; + + return node; + } + + // 2+ Elements + else { + var node = this.tail; + this.tail = this.tail.prev; + this.tail.next = null; + + return node; + } + }; + + // Returns a string version of the LL + toString() { + if (this.head === null) { + return ''; + } else { + var curr = this.head; + var result = ''; + + while (curr !== null) { + result += curr.value; + curr = curr.next; + } + + return result; + } + }; + + // Clones the LL + clone() { + return JSON.parse(JSON.stringify(this)); + }; +} + diff --git a/src/lsystem.js b/src/lsystem.js new file mode 100644 index 00000000..d4bb59e6 --- /dev/null +++ b/src/lsystem.js @@ -0,0 +1,214 @@ +import LinkedList from './linkedlist.js' + +// A class that represents a symbol replacement rule to +// be used when expanding an L-system grammar. +function Rule(prob, str) { + this.probability = prob; // The probability that this Rule will be used when replacing a character in the grammar string + this.successorString = str; // The string that will replace the char that maps to this Rule +} + +// Implement a linked list class and its requisite functions +// as described in the homework writeup +// See linkedlist.js + +// Turn the string into linked list +export function stringToLinkedList(input_string) { + // ex. assuming input_string = "F+X" + // you should return a linked list where the head is + // at Node('F') and the tail is at Node('X') + var ll = new LinkedList(); + + for (var i = 0; i < input_string.length; i++) { + ll.push(input_string.charAt(i)); + } + + return ll; +} + +// Return a string form of the LinkedList +export function linkedListToString(linkedList) { + // ex. Node1("F")->Node2("X") should be "FX" + return linkedList.toString(); +} + +// Given the node to be replaced, +// insert a sub-linked-list that represents replacementString +// WASN'T SUPPOSED TO GO THROUGH THE ENTIRE LOOP I THINK. +// WHAT HAVE YOU DONE ELLEN LMAO. +// Returns the next node to work on +function replaceNode(linkedList, node, replacementString) { + if (linkedList === null || node === null) { + // If LL doesn't exist or is empty just return + return; + } + + // Replacement string is empty + // Basically remove node at evey appearance + if (!replacementString || replacementString.length == 0) { + // Delete the node at every appearance + + // 1 Element Case + if (linkedList.head == linkedList.tail && linkedList.head == node) { + linkedList.pop(); // remove + return linkedList.head; + } + + // Node is the head + else if (node == linkedList.head) { + linkedList.head = linkedList.head.next; + linkedList.head.prev = null; + return linkedList.head; + } + + // Node is the tail + else if (node == linkedList.tail) { + linkedList.tail = linkedList.tail.prev; + linkedList.next = null; + return null; + } + + // Node is a middle node + // Or doesn't exist in the linked list, but well hopefully the function + // is used properly. And I mean, I'm going to used it properly... + else { + var before = node.prev; + var after = node.next; + + // Drop reference to node + before.next = after; + after.prev = before; + + return after; + } + // ReplacementString is not empty + } else { + // Create LL of replacementString + var rsll = stringToLinkedList(replacementString); + + // 1 Element Case + if (linkedList.head == linkedList.tail && linkedList.head == node) { + // Replace LL with RSLL + linkedList.head = rsll.head; + linkedList.tail = rsll.tail; + return null; + } + + + // 2+ Element cases + // If node is the head + if (node == linkedList.head) { + var after = linkedList.head.next; + + // Attach copied RSLL, skipping head + rsll.tail.next = after; + after.prev = rsll.tail; // update prev + + // Update LL head + linkedList.head = rsll.head; // prev is already null + + return after; + } + + // If node is the tail + else if (node == linkedList.tail) { + var before = linkedList.tail.prev; + + // remove node (which is the tail) and add pointer to next + before.next = rsll.head; + rsll.head.prev = before; + + // Update tail pointer + linkedList.tail = rsll.tail; + + return null; + } + + // Node is a middle node + // Or doesn't exist in the linked list, but well hopefully the function + // is used properly. And I mean, I'm going to used it properly... + else { + // Replace + var before = node.prev; + var after = node.next; + + // rsll the replacementString LinkedList + rsll.head.prev = before; + rsll.tail.next = after; + + // update the pointers in the linked list + before.next = rsll.head; + after.prev = rsll.tail; + + return after; + } + } +} + +export default function Lsystem(axiom, grammar, iterations) { + // default LSystem + this.axiom = "F-F-F-F-F"; + this.grammar = { + 'F': [ new Rule(1.0, 'F-F++F+F-F-F') ], + '[': [ new Rule(1.0, '[') ], + ']': [ new Rule(1.0, ']') ], + '-': [ new Rule(1.0, '-') ], + '+': [ new Rule(1.0, '+') ] + }; + this.iterations = 0; + + // Set up the axiom string + if (typeof axiom !== "undefined") { + this.axiom = axiom; + } + + // Set up the grammar as a dictionary that + // maps a single character (symbol) to a Rule. + if (typeof grammar !== "undefined") { + this.grammar = Object.assign({}, grammar); + } + + // Set up iterations (the number of times you + // should expand the axiom in DoIterations) + if (typeof iterations !== "undefined") { + this.iterations = iterations; + } + + // A function to alter the axiom string stored + // in the L-system + this.updateAxiom = function(axiom) { + // Setup axiom + if (typeof axiom !== "undefined") { + this.axiom = axiom; + } + } + + // This function returns a linked list that is the result + // of expanding the L-system's axiom n times. + // The implementation we have provided you just returns a linked + // list of the axiom. + this.doIterations = function(n) { + // If there isn't an axiom, then just return + if (this.axiom == null || this.axiom.length <= 0) { + return; + } + + var lSystemLL = stringToLinkedList(this.axiom); + + // Iterate n times + for (var i = 0; i < n; i++) { + var curr = lSystemLL.head; + + while (curr != null) { + var curr_grammar = this.grammar[curr.value][0]; + + if (curr_grammar && Math.random() <= curr_grammar.probability) { + curr = replaceNode(lSystemLL, curr, curr_grammar.successorString); + } else { + curr = curr.next; + } + } + } + + return lSystemLL; + } +} \ No newline at end of file diff --git a/src/main.js b/src/main.js new file mode 100644 index 00000000..b24dc6cd --- /dev/null +++ b/src/main.js @@ -0,0 +1,68 @@ + +const THREE = require('three'); // older modules are imported like this. You shouldn't have to worry about this much +import Framework from './framework' +import Lsystem, {LinkedListToString} from './lsystem.js' +import Turtle from './turtle.js' + +var turtle; + +// called after the scene loads +function onLoad(framework) { + var scene = framework.scene; + var camera = framework.camera; + var renderer = framework.renderer; + var gui = framework.gui; + var stats = framework.stats; + + // initialize a simple box and material + var directionalLight = new THREE.DirectionalLight( 0xffffff, 1 ); + directionalLight.color.setHSL(0.1, 1, 0.95); + directionalLight.position.set(1, 3, 2); + directionalLight.position.multiplyScalar(10); + scene.add(directionalLight); + + // set camera position + camera.position.set(1, 1, 2); + camera.lookAt(new THREE.Vector3(0,0,0)); + + // initialize LSystem and a Turtle to draw + var lsys = new Lsystem(); + turtle = new Turtle(scene); + + gui.add(camera, 'fov', 0, 180).onChange(function(newVal) { + camera.updateProjectionMatrix(); + }); + + gui.add(lsys, 'axiom').onChange(function(newVal) { + lsys.updateAxiom(newVal); + doLsystem(lsys, lsys.iterations, turtle); + }); + + gui.add(lsys, 'iterations', 0, 12).step(1).onChange(function(newVal) { + clearScene(turtle); + doLsystem(lsys, newVal, turtle); + }); +} + +// clears the scene by removing all geometries added by turtle.js +function clearScene(turtle) { + var obj; + for( var i = turtle.scene.children.length - 1; i > 3; i--) { + obj = turtle.scene.children[i]; + turtle.scene.remove(obj); + } +} + +function doLsystem(lsystem, iterations, turtle) { + var result = lsystem.doIterations(iterations); + turtle.clear(); + turtle = new Turtle(turtle.scene); + turtle.renderSymbols(result); +} + +// called on frame updates +function onUpdate(framework) { +} + +// when the scene is done initializing, it will call onLoad, then on frame updates, call onUpdate +Framework.init(onLoad, onUpdate); diff --git a/src/turtle.js b/src/turtle.js new file mode 100644 index 00000000..b1f5aa0d --- /dev/null +++ b/src/turtle.js @@ -0,0 +1,130 @@ +const THREE = require('three') + +// A class used to encapsulate the state of a turtle at a given moment. +// The Turtle class contains one TurtleState member variable. +// You are free to add features to this state class, +// such as color or whimiscality +var TurtleState = function(pos, dir) { + return { + pos: new THREE.Vector3(pos.x, pos.y, pos.z), + dir: new THREE.Vector3(dir.x, dir.y, dir.z) + } +} + +export default class Turtle { + + constructor(scene, grammar) { + this.state = new TurtleState(new THREE.Vector3(0,0,0), new THREE.Vector3(0,1,0)); + this.scene = scene; + this.stateStack = []; + + // TODO: Start by adding rules for '[' and ']' then more! + // Make sure to implement the functions for the new rules inside Turtle + if (typeof grammar === "undefined") { + this.renderGrammar = { + '+' : this.rotateTurtle.bind(this, 72, 0, 0), + '-' : this.rotateTurtle.bind(this, -72, 0, 0), + 'F' : this.makeCylinder.bind(this, 2, 0.1), + '[' : this.pushState.bind(this), + ']' : this.popState.bind(this), + '|' : this.rotateTurtle.bind(this, 180, 0, 0) + }; + } else { + this.renderGrammar = grammar; + } + } + + // Resets the turtle's position to the origin + // and its orientation to the Y axis + clear() { + this.state = new TurtleState(new THREE.Vector3(0,0,0), new THREE.Vector3(0,1,0)); + } + + // A function to help you debug your turtle functions + // by printing out the turtle's current state. + printState() { + console.log(this.state.pos) + console.log(this.state.dir) + } + + // Rotate the turtle's _dir_ vector by each of the + // Euler angles indicated by the input. + rotateTurtle(x, y, z) { + var e = new THREE.Euler( + x * 3.14/180, + y * 3.14/180, + z * 3.14/180); + this.state.dir.applyEuler(e); + } + + // Translate the turtle along the input vector. + // Does NOT change the turtle's _dir_ vector + moveTurtle(x, y, z) { + var new_vec = THREE.Vector3(x, y, z); + this.state.pos.add(new_vec); + }; + + // Translate the turtle along its _dir_ vector by the distance indicated + moveForward(dist) { + var newVec = this.state.dir.multiplyScalar(dist); + this.state.pos.add(newVec); + }; + + // Make a cylinder of given length and width starting at turtle pos + // Moves turtle pos ahead to end of the new cylinder + makeCylinder(len, width) { + var geometry = new THREE.CylinderGeometry(width, width, len); + var material = new THREE.MeshBasicMaterial( {color: 0x00cccc} ); + var cylinder = new THREE.Mesh( geometry, material ); + this.scene.add( cylinder ); + + //Orient the cylinder to the turtle's current direction + var quat = new THREE.Quaternion(); + quat.setFromUnitVectors(new THREE.Vector3(0,1,0), this.state.dir); + var mat4 = new THREE.Matrix4(); + mat4.makeRotationFromQuaternion(quat); + cylinder.applyMatrix(mat4); + + + //Move the cylinder so its base rests at the turtle's current position + var mat5 = new THREE.Matrix4(); + var trans = this.state.pos.add(this.state.dir.multiplyScalar(0.5 * len)); + mat5.makeTranslation(trans.x, trans.y, trans.z); + cylinder.applyMatrix(mat5); + + //Scoot the turtle forward by len units + this.moveForward(len/2); + }; + + // Add state into the stack + pushState() { + this.stateStack.push(cloneState()); + }; + + // Restore state to the LIFO + popState() { + this.state = this.stateStack.pop(); + }; + + cloneState() { + return JSON.parse(JSON.stringify(this.state)); + }; + + // Call the function to which the input symbol is bound. + // Look in the Turtle's constructor for examples of how to bind + // functions to grammar symbols. + renderSymbol(symbolNode) { + var func = this.renderGrammar[symbolNode.value]; + if (func) { + func(); + } + }; + + // Invoke renderSymbol for every node in a linked list of grammar symbols. + renderSymbols(linkedList) { + var currentNode; + for(currentNode = linkedList.head; currentNode != null; currentNode = currentNode.next) { + this.renderSymbol(currentNode); + } + } +} \ No newline at end of file diff --git a/webpack.config.js b/webpack.config.js new file mode 100644 index 00000000..57dce485 --- /dev/null +++ b/webpack.config.js @@ -0,0 +1,28 @@ +const path = require('path'); + +module.exports = { + entry: path.join(__dirname, "src/main"), + output: { + filename: "./bundle.js" + }, + module: { + loaders: [ + { + test: /\.js$/, + exclude: /(node_modules|bower_components)/, + loader: 'babel', + query: { + presets: ['es2015'] + } + }, + { + test: /\.glsl$/, + loader: "webpack-glsl" + }, + ] + }, + devtool: 'source-map', + devServer: { + port: 7000 + } +} \ No newline at end of file From 58bcbfbf94756055ca2b98740d099c029c442eb7 Mon Sep 17 00:00:00 2001 From: eldu Date: Thu, 16 Feb 2017 13:25:13 -0500 Subject: [PATCH 02/16] Finished tree --- src/assets.js | 2 + src/linkedlist.js | 1 + src/lsystem.js | 214 --------------------------------------------- src/main.js | 90 +++++++++++++------ src/shape.js | 66 ++++++++++++++ src/shapesystem.js | 68 ++++++++++++++ src/turtle.js | 130 --------------------------- 7 files changed, 198 insertions(+), 373 deletions(-) create mode 100644 src/assets.js delete mode 100644 src/lsystem.js create mode 100644 src/shape.js create mode 100644 src/shapesystem.js delete mode 100644 src/turtle.js diff --git a/src/assets.js b/src/assets.js new file mode 100644 index 00000000..5a9abce0 --- /dev/null +++ b/src/assets.js @@ -0,0 +1,2 @@ +const THREE = require('three'); + diff --git a/src/linkedlist.js b/src/linkedlist.js index 6b8c4861..5a7444b2 100644 --- a/src/linkedlist.js +++ b/src/linkedlist.js @@ -52,6 +52,7 @@ export default class LinkedList { }; // Returns a string version of the LL + // Assuming that the value is a letter toString() { if (this.head === null) { return ''; diff --git a/src/lsystem.js b/src/lsystem.js deleted file mode 100644 index d4bb59e6..00000000 --- a/src/lsystem.js +++ /dev/null @@ -1,214 +0,0 @@ -import LinkedList from './linkedlist.js' - -// A class that represents a symbol replacement rule to -// be used when expanding an L-system grammar. -function Rule(prob, str) { - this.probability = prob; // The probability that this Rule will be used when replacing a character in the grammar string - this.successorString = str; // The string that will replace the char that maps to this Rule -} - -// Implement a linked list class and its requisite functions -// as described in the homework writeup -// See linkedlist.js - -// Turn the string into linked list -export function stringToLinkedList(input_string) { - // ex. assuming input_string = "F+X" - // you should return a linked list where the head is - // at Node('F') and the tail is at Node('X') - var ll = new LinkedList(); - - for (var i = 0; i < input_string.length; i++) { - ll.push(input_string.charAt(i)); - } - - return ll; -} - -// Return a string form of the LinkedList -export function linkedListToString(linkedList) { - // ex. Node1("F")->Node2("X") should be "FX" - return linkedList.toString(); -} - -// Given the node to be replaced, -// insert a sub-linked-list that represents replacementString -// WASN'T SUPPOSED TO GO THROUGH THE ENTIRE LOOP I THINK. -// WHAT HAVE YOU DONE ELLEN LMAO. -// Returns the next node to work on -function replaceNode(linkedList, node, replacementString) { - if (linkedList === null || node === null) { - // If LL doesn't exist or is empty just return - return; - } - - // Replacement string is empty - // Basically remove node at evey appearance - if (!replacementString || replacementString.length == 0) { - // Delete the node at every appearance - - // 1 Element Case - if (linkedList.head == linkedList.tail && linkedList.head == node) { - linkedList.pop(); // remove - return linkedList.head; - } - - // Node is the head - else if (node == linkedList.head) { - linkedList.head = linkedList.head.next; - linkedList.head.prev = null; - return linkedList.head; - } - - // Node is the tail - else if (node == linkedList.tail) { - linkedList.tail = linkedList.tail.prev; - linkedList.next = null; - return null; - } - - // Node is a middle node - // Or doesn't exist in the linked list, but well hopefully the function - // is used properly. And I mean, I'm going to used it properly... - else { - var before = node.prev; - var after = node.next; - - // Drop reference to node - before.next = after; - after.prev = before; - - return after; - } - // ReplacementString is not empty - } else { - // Create LL of replacementString - var rsll = stringToLinkedList(replacementString); - - // 1 Element Case - if (linkedList.head == linkedList.tail && linkedList.head == node) { - // Replace LL with RSLL - linkedList.head = rsll.head; - linkedList.tail = rsll.tail; - return null; - } - - - // 2+ Element cases - // If node is the head - if (node == linkedList.head) { - var after = linkedList.head.next; - - // Attach copied RSLL, skipping head - rsll.tail.next = after; - after.prev = rsll.tail; // update prev - - // Update LL head - linkedList.head = rsll.head; // prev is already null - - return after; - } - - // If node is the tail - else if (node == linkedList.tail) { - var before = linkedList.tail.prev; - - // remove node (which is the tail) and add pointer to next - before.next = rsll.head; - rsll.head.prev = before; - - // Update tail pointer - linkedList.tail = rsll.tail; - - return null; - } - - // Node is a middle node - // Or doesn't exist in the linked list, but well hopefully the function - // is used properly. And I mean, I'm going to used it properly... - else { - // Replace - var before = node.prev; - var after = node.next; - - // rsll the replacementString LinkedList - rsll.head.prev = before; - rsll.tail.next = after; - - // update the pointers in the linked list - before.next = rsll.head; - after.prev = rsll.tail; - - return after; - } - } -} - -export default function Lsystem(axiom, grammar, iterations) { - // default LSystem - this.axiom = "F-F-F-F-F"; - this.grammar = { - 'F': [ new Rule(1.0, 'F-F++F+F-F-F') ], - '[': [ new Rule(1.0, '[') ], - ']': [ new Rule(1.0, ']') ], - '-': [ new Rule(1.0, '-') ], - '+': [ new Rule(1.0, '+') ] - }; - this.iterations = 0; - - // Set up the axiom string - if (typeof axiom !== "undefined") { - this.axiom = axiom; - } - - // Set up the grammar as a dictionary that - // maps a single character (symbol) to a Rule. - if (typeof grammar !== "undefined") { - this.grammar = Object.assign({}, grammar); - } - - // Set up iterations (the number of times you - // should expand the axiom in DoIterations) - if (typeof iterations !== "undefined") { - this.iterations = iterations; - } - - // A function to alter the axiom string stored - // in the L-system - this.updateAxiom = function(axiom) { - // Setup axiom - if (typeof axiom !== "undefined") { - this.axiom = axiom; - } - } - - // This function returns a linked list that is the result - // of expanding the L-system's axiom n times. - // The implementation we have provided you just returns a linked - // list of the axiom. - this.doIterations = function(n) { - // If there isn't an axiom, then just return - if (this.axiom == null || this.axiom.length <= 0) { - return; - } - - var lSystemLL = stringToLinkedList(this.axiom); - - // Iterate n times - for (var i = 0; i < n; i++) { - var curr = lSystemLL.head; - - while (curr != null) { - var curr_grammar = this.grammar[curr.value][0]; - - if (curr_grammar && Math.random() <= curr_grammar.probability) { - curr = replaceNode(lSystemLL, curr, curr_grammar.successorString); - } else { - curr = curr.next; - } - } - } - - return lSystemLL; - } -} \ No newline at end of file diff --git a/src/main.js b/src/main.js index b24dc6cd..dae9c995 100644 --- a/src/main.js +++ b/src/main.js @@ -1,10 +1,18 @@ const THREE = require('three'); // older modules are imported like this. You shouldn't have to worry about this much import Framework from './framework' -import Lsystem, {LinkedListToString} from './lsystem.js' -import Turtle from './turtle.js' +import ShapeSystem from './shapesystem' +import Shape from './shape.js' -var turtle; + +// Materials +var lambertWhite = new THREE.MeshLambertMaterial( {color: 0xffffff} ); + +// Geometry +var boxGeo = new THREE.BoxGeometry( 1, 1, 1 ); + +// Mesh +var cubeMesh = new THREE.Mesh( boxGeo, lambertWhite ); // called after the scene loads function onLoad(framework) { @@ -22,44 +30,68 @@ function onLoad(framework) { scene.add(directionalLight); // set camera position - camera.position.set(1, 1, 2); + camera.position.set(50, 100, 200); camera.lookAt(new THREE.Vector3(0,0,0)); - // initialize LSystem and a Turtle to draw - var lsys = new Lsystem(); - turtle = new Turtle(scene); + var axiom = new Shape(); + var ss = new ShapeSystem(axiom, boxGeo, cubeMesh); gui.add(camera, 'fov', 0, 180).onChange(function(newVal) { camera.updateProjectionMatrix(); }); - gui.add(lsys, 'axiom').onChange(function(newVal) { - lsys.updateAxiom(newVal); - doLsystem(lsys, lsys.iterations, turtle); - }); + // gui.add(lsys, 'axiom').onChange(function(newVal) { + // lsys.updateAxiom(newVal); + // doLsystem(lsys, lsys.iterations, turtle); + // }); - gui.add(lsys, 'iterations', 0, 12).step(1).onChange(function(newVal) { - clearScene(turtle); - doLsystem(lsys, newVal, turtle); - }); -} + // gui.add(lsys, 'iterations', 0, 12).step(1).onChange(function(newVal) { + // clearScene(turtle); + // doLsystem(lsys, newVal, turtle); + // }); -// clears the scene by removing all geometries added by turtle.js -function clearScene(turtle) { - var obj; - for( var i = turtle.scene.children.length - 1; i > 3; i--) { - obj = turtle.scene.children[i]; - turtle.scene.remove(obj); - } -} -function doLsystem(lsystem, iterations, turtle) { - var result = lsystem.doIterations(iterations); - turtle.clear(); - turtle = new Turtle(turtle.scene); - turtle.renderSymbols(result); + // var obj = new THREE.Object3D(); + // var geometry = new THREE.BoxGeometry( 1, 1, 1 ); + // var material = new THREE.MeshBasicMaterial( {color: 0x00ff00} ); + // var cube = new THREE.Mesh( geometry, material ); + + // var a = new THREE.CylinderGeometry( 1, 1, 1); + // a.position = new THREE.Vector3(0, 0, 5); + // var cylinder = new THREE.Mesh(a, new THREE.MeshBasicMaterial( {color: 0x0000ff} ) ); + + // var mat5 = new THREE.Matrix4(); + // mat5.makeTranslation(5, 0, 0); + // cylinder.applyMatrix(mat5); + + // cube.add(cylinder); + // obj.add(cube); + // scene.add(obj); + // // scene.add(cylinder); + + // var ballGeo = new THREE.SphereGeometry(10,35,35); + // var material = new THREE.MeshLambertMaterial(); + // var ball = new THREE.Mesh(ballGeo, material); + + // var pendulumGeo = new THREE.CylinderGeometry(1, 1, 50, 16); + // ball.updateMatrix(); + // pendulumGeo.merge(ball.geometry, ball.matrix); + + // var pendulum = new THREE.Mesh(pendulumGeo, material); + // scene.add(pendulum); + + ss.traverse(scene); } +// // clears the scene by removing all geometries added by turtle.js +// function clearScene(turtle) { +// var obj; +// for( var i = turtle.scene.children.length - 1; i > 3; i--) { +// obj = turtle.scene.children[i]; +// turtle.scene.remove(obj); +// } +// } + // called on frame updates function onUpdate(framework) { } diff --git a/src/shape.js b/src/shape.js new file mode 100644 index 00000000..8349b695 --- /dev/null +++ b/src/shape.js @@ -0,0 +1,66 @@ + +const THREE = require('three'); // older modules are imported like this. You shouldn't have to worry about this much +import Framework from './framework' + +var lambertWhite = new THREE.MeshLambertMaterial( {color: 0xffffff} ); + +// Shape Node +// parent: parent of the node +// boundingbox: bounding box of the shape in world space +// geometry: geometry to render +// children +export default class Shape { + constructor(parent, mesh) { + if (arguments.length === 0) { + // Default empty + this.parent = null; + this.boundingBox = new THREE.BoxGeometry(10, 10, 10); + this.mesh = new THREE.Mesh(new THREE.BoxGeometry(10, 10, 10), + lambertWhite); + this.iteration = 0; + } else { + this.parent = parent; + this.boundingBox = boundingBox; + this.mesh = mesh; + this.iteration = this.parent.iteration + 1; + } + + this.children = []; + }; + + + // If there is any Z subdivision then + subdivide() { // 0 = x, 1 = y, 2 = z + // if (this.children.length === 0) { + // // subdivide + // var axis = 0; + + // if (axis == 0) { + // var s = this.parent.boundingBox + + // Shape a = new Shape(this, this.parent.boundingBox ) + // } else if (axis == 1) { + + // } else { + + // } + + + // } else { + // for(var i = 0; i < this.children.length; i++) { + // this.children[i].subdivide(); + // } + // } + }; + + draw(scene) { + scene.add(this.mesh); + }; + + drawBbox(scene) { + var geo = new THREE.EdgesGeometry( this.boundingBox ); + var mat = new THREE.LineBasicMaterial( { color: 0x00ffff, linewidth: 2 } ); + var wireframe = new THREE.LineSegments( geo, mat ); + scene.add( wireframe ); + }; +} \ No newline at end of file diff --git a/src/shapesystem.js b/src/shapesystem.js new file mode 100644 index 00000000..b499ba69 --- /dev/null +++ b/src/shapesystem.js @@ -0,0 +1,68 @@ +import Shape from './shape.js' +import Framework from './framework' + +function Rule(successor, probability) { + this.successor = sucessor; + this.probability = probability; +} + +export default function shapeSystem(axiom, grammar, scene) { + if (axiom instanceof Shape) { + this.axiom = axiom; + } else { + this.axiom = new Shape(); + } + + this.grammar = grammar; + this.iteration = 0; + this.scene = scene; + + // Set up the axiom string + if (typeof axiom !== "undefined") { + this.axiom = axiom; + } + + // Set up the grammar as a dictionary that + // maps a single character (symbol) to a Rule. + if (typeof grammar !== "undefined") { + this.grammar = Object.assign({}, grammar); + } + + // Set up iterations (the number of times you + // should expand the axiom in DoIterations) + if (typeof iterations !== "undefined") { + this.iterations = iterations; + } + + // A function to alter the axiom string stored + // in the L-system + this.updateAxiom = function(axiom) { + // Setup axiom + if (typeof axiom !== "undefined") { + this.axiom = axiom; + } + } + + + this.traverse = function(scene) { + axiom.draw(scene); + } + // This function returns a linked list that is the result + // of expanding the L-system's axiom n times. + // The implementation we have provided you just returns a linked + // list of the axiom. + // this.doIterations = function(n) { + // draw(i, scene) { + // if (i < this.iteration) { + // for(var i = 0; i < this.children.length; i++) { + // this.children.draw(i, scene); + // } + // } else if (i == this.iteration) { + // scene + // } else { + // return; + // } + // } + // } + +} \ No newline at end of file diff --git a/src/turtle.js b/src/turtle.js deleted file mode 100644 index b1f5aa0d..00000000 --- a/src/turtle.js +++ /dev/null @@ -1,130 +0,0 @@ -const THREE = require('three') - -// A class used to encapsulate the state of a turtle at a given moment. -// The Turtle class contains one TurtleState member variable. -// You are free to add features to this state class, -// such as color or whimiscality -var TurtleState = function(pos, dir) { - return { - pos: new THREE.Vector3(pos.x, pos.y, pos.z), - dir: new THREE.Vector3(dir.x, dir.y, dir.z) - } -} - -export default class Turtle { - - constructor(scene, grammar) { - this.state = new TurtleState(new THREE.Vector3(0,0,0), new THREE.Vector3(0,1,0)); - this.scene = scene; - this.stateStack = []; - - // TODO: Start by adding rules for '[' and ']' then more! - // Make sure to implement the functions for the new rules inside Turtle - if (typeof grammar === "undefined") { - this.renderGrammar = { - '+' : this.rotateTurtle.bind(this, 72, 0, 0), - '-' : this.rotateTurtle.bind(this, -72, 0, 0), - 'F' : this.makeCylinder.bind(this, 2, 0.1), - '[' : this.pushState.bind(this), - ']' : this.popState.bind(this), - '|' : this.rotateTurtle.bind(this, 180, 0, 0) - }; - } else { - this.renderGrammar = grammar; - } - } - - // Resets the turtle's position to the origin - // and its orientation to the Y axis - clear() { - this.state = new TurtleState(new THREE.Vector3(0,0,0), new THREE.Vector3(0,1,0)); - } - - // A function to help you debug your turtle functions - // by printing out the turtle's current state. - printState() { - console.log(this.state.pos) - console.log(this.state.dir) - } - - // Rotate the turtle's _dir_ vector by each of the - // Euler angles indicated by the input. - rotateTurtle(x, y, z) { - var e = new THREE.Euler( - x * 3.14/180, - y * 3.14/180, - z * 3.14/180); - this.state.dir.applyEuler(e); - } - - // Translate the turtle along the input vector. - // Does NOT change the turtle's _dir_ vector - moveTurtle(x, y, z) { - var new_vec = THREE.Vector3(x, y, z); - this.state.pos.add(new_vec); - }; - - // Translate the turtle along its _dir_ vector by the distance indicated - moveForward(dist) { - var newVec = this.state.dir.multiplyScalar(dist); - this.state.pos.add(newVec); - }; - - // Make a cylinder of given length and width starting at turtle pos - // Moves turtle pos ahead to end of the new cylinder - makeCylinder(len, width) { - var geometry = new THREE.CylinderGeometry(width, width, len); - var material = new THREE.MeshBasicMaterial( {color: 0x00cccc} ); - var cylinder = new THREE.Mesh( geometry, material ); - this.scene.add( cylinder ); - - //Orient the cylinder to the turtle's current direction - var quat = new THREE.Quaternion(); - quat.setFromUnitVectors(new THREE.Vector3(0,1,0), this.state.dir); - var mat4 = new THREE.Matrix4(); - mat4.makeRotationFromQuaternion(quat); - cylinder.applyMatrix(mat4); - - - //Move the cylinder so its base rests at the turtle's current position - var mat5 = new THREE.Matrix4(); - var trans = this.state.pos.add(this.state.dir.multiplyScalar(0.5 * len)); - mat5.makeTranslation(trans.x, trans.y, trans.z); - cylinder.applyMatrix(mat5); - - //Scoot the turtle forward by len units - this.moveForward(len/2); - }; - - // Add state into the stack - pushState() { - this.stateStack.push(cloneState()); - }; - - // Restore state to the LIFO - popState() { - this.state = this.stateStack.pop(); - }; - - cloneState() { - return JSON.parse(JSON.stringify(this.state)); - }; - - // Call the function to which the input symbol is bound. - // Look in the Turtle's constructor for examples of how to bind - // functions to grammar symbols. - renderSymbol(symbolNode) { - var func = this.renderGrammar[symbolNode.value]; - if (func) { - func(); - } - }; - - // Invoke renderSymbol for every node in a linked list of grammar symbols. - renderSymbols(linkedList) { - var currentNode; - for(currentNode = linkedList.head; currentNode != null; currentNode = currentNode.next) { - this.renderSymbol(currentNode); - } - } -} \ No newline at end of file From 3206b7b8d98463f5da8027d162dd5c814f1640d5 Mon Sep 17 00:00:00 2001 From: eldu Date: Thu, 16 Feb 2017 19:55:02 -0500 Subject: [PATCH 03/16] Symettrical subdivision --- src/main.js | 6 +-- src/shape.js | 111 +++++++++++++++++++++++++++++++++++++-------- src/shapesystem.js | 8 +++- 3 files changed, 100 insertions(+), 25 deletions(-) diff --git a/src/main.js b/src/main.js index dae9c995..4a2f6b30 100644 --- a/src/main.js +++ b/src/main.js @@ -45,10 +45,8 @@ function onLoad(framework) { // doLsystem(lsys, lsys.iterations, turtle); // }); - // gui.add(lsys, 'iterations', 0, 12).step(1).onChange(function(newVal) { - // clearScene(turtle); - // doLsystem(lsys, newVal, turtle); - // }); + gui.add(ss, 'iteration', 0, 12).step(1).onChange(function(newVal) { + }); // var obj = new THREE.Object3D(); diff --git a/src/shape.js b/src/shape.js index 8349b695..edc6f804 100644 --- a/src/shape.js +++ b/src/shape.js @@ -14,51 +14,122 @@ export default class Shape { if (arguments.length === 0) { // Default empty this.parent = null; - this.boundingBox = new THREE.BoxGeometry(10, 10, 10); + // this.boundingBox = new THREE.BoxGeometry(10, 10, 10); this.mesh = new THREE.Mesh(new THREE.BoxGeometry(10, 10, 10), lambertWhite); this.iteration = 0; } else { this.parent = parent; - this.boundingBox = boundingBox; + // this.boundingBox = boundingBox; this.mesh = mesh; - this.iteration = this.parent.iteration + 1; + + if (parent !== null) { + this.iteration = this.parent.iteration + 1; + } else { + this.iteration = 0; + } } + this.division = ''; // Current subdivision this.children = []; }; // If there is any Z subdivision then subdivide() { // 0 = x, 1 = y, 2 = z - // if (this.children.length === 0) { - // // subdivide - // var axis = 0; + if (this.children.length === 0) { + // subdivide + var axis = 2; // Just do this for now. + + var s = this.mesh.scale; + var p = this.mesh.position; + + if (axis == 0) { + var s_child = new THREE.Vector3(s.x / 2.0, s.y, s.z); + var p_left = new THREE.Vector3(p.x - s.x / 4.0, p.y, p.z); + var p_right = new THREE.Vector3(p.x + s.x / 4.0, p.y, p.z); + + var left = new THREE.Mesh( + new THREE.BoxGeometry(s_child.x, s_child.y, s_child.z), + lambertWhite); + + lambertWhite = new THREE.MeshLambertMaterial( {color: 0x00ffff} ); + + var right = new THREE.Mesh( + new THREE.BoxGeometry(s_child.x, s_child.y, s_child.z), + lambertWhite); + left.position.set(p_left.x, p_left.y, p_left.z); + right.position.set(p_right.x, p_right.y, p_right.z); + this.children.push(new Shape(this, left)); + this.children.push(new Shape(this, right)); + } else if (axis == 1) { + var s = this.mesh.scale; + var p = this.mesh.position; + + var s_child = new THREE.Vector3(s.x, s.y / 2.0, s.z); + + var p_bottom = new THREE.Vector3(p.x, p.y - s.y / 4.0, p.z); + var p_top = new THREE.Vector3(p.x, p.y + s.y / 4.0, p.z); + + var bottom = new THREE.Mesh( + new THREE.BoxGeometry(s_child.x, s_child.y, s_child.z), + lambertWhite); + bottom.position.set(p_bottom.x, p_bottom.y, p_bottom.z); - // if (axis == 0) { - // var s = this.parent.boundingBox + lambertWhite = new THREE.MeshLambertMaterial( {color: 0x00ffff} ); + var top = new THREE.Mesh( + new THREE.BoxGeometry(s_child.x, s_child.y, s_child.z), + lambertWhite); + top.position.set(p_top.x, p_top.y, p_top.z); - // Shape a = new Shape(this, this.parent.boundingBox ) - // } else if (axis == 1) { + this.children.push(new Shape(this, top)); + this.children.push(new Shape(this, bottom)); - // } else { + } else { + var s = this.mesh.scale; + var p = this.mesh.position; - // } + var s_child = new THREE.Vector3(s.x, s.y, s.z / 2.0); + var p_front = new THREE.Vector3(p.x, p.y, p.z + s.z / 4.0); + var p_back = new THREE.Vector3(p.x, p.y, p.z - s.z / 4.0); - // } else { - // for(var i = 0; i < this.children.length; i++) { - // this.children[i].subdivide(); - // } - // } + var front = new THREE.Mesh( + new THREE.BoxGeometry(s_child.x, s_child.y, s_child.z), + lambertWhite); + front.position.set(p_front.x, p_front.y, p_front.z); + + lambertWhite = new THREE.MeshLambertMaterial( {color: 0x00ffff} ); + var back = new THREE.Mesh( + new THREE.BoxGeometry(s_child.x, s_child.y, s_child.z), + lambertWhite); + back.position.set(p_back.x, p_back.y, p_back.z); + + this.children.push(new Shape(this, front)); + this.children.push(new Shape(this, back)); + } + } else { + for(var i = 0; i < this.children.length; i++) { + this.children[i].subdivide(); + } + } }; - draw(scene) { - scene.add(this.mesh); + draw(scene, n) { + // if (n < this.iteration && this.children.length != 0) { + if (this.children.length > 0) { + for(var i = 0; i < this.children.length; i++) { + this.children[i].draw(scene, n); + } + } else { + // this.drawBbox(scene); + scene.add(this.mesh); + //this.subdivide(); + } }; drawBbox(scene) { - var geo = new THREE.EdgesGeometry( this.boundingBox ); + var geo = new THREE.EdgesGeometry( this.mesh.geometry ); var mat = new THREE.LineBasicMaterial( { color: 0x00ffff, linewidth: 2 } ); var wireframe = new THREE.LineSegments( geo, mat ); scene.add( wireframe ); diff --git a/src/shapesystem.js b/src/shapesystem.js index b499ba69..767ee955 100644 --- a/src/shapesystem.js +++ b/src/shapesystem.js @@ -43,9 +43,15 @@ export default function shapeSystem(axiom, grammar, scene) { } } + var a = false; this.traverse = function(scene) { - axiom.draw(scene); + if (a === false) { + axiom.subdivide(); + a = true; + } + + axiom.draw(scene, this.iterations); } // This function returns a linked list that is the result // of expanding the L-system's axiom n times. From fd01ed6aea689dbb3f79739e585a753ab66a1ac2 Mon Sep 17 00:00:00 2001 From: eldu Date: Thu, 16 Feb 2017 23:28:47 -0500 Subject: [PATCH 04/16] Finished floors --- src/main.js | 6 ++++ src/shape.js | 70 +++++++++++++++++++++++++++++++++++++--------- src/shapesystem.js | 3 +- 3 files changed, 65 insertions(+), 14 deletions(-) diff --git a/src/main.js b/src/main.js index 4a2f6b30..54e18f4f 100644 --- a/src/main.js +++ b/src/main.js @@ -78,6 +78,12 @@ function onLoad(framework) { // var pendulum = new THREE.Mesh(pendulumGeo, material); // scene.add(pendulum); + var geometry = new THREE.PlaneGeometry( 5, 20, 32 ); + var material = new THREE.MeshBasicMaterial( {color: 0xffff00, side: THREE.DoubleSide} ); + var plane = new THREE.Mesh( geometry, material ); + plane.rotateX(Math.PI / 2.0); + scene.add( plane ); + ss.traverse(scene); } diff --git a/src/shape.js b/src/shape.js index edc6f804..c7fc9885 100644 --- a/src/shape.js +++ b/src/shape.js @@ -4,6 +4,11 @@ import Framework from './framework' var lambertWhite = new THREE.MeshLambertMaterial( {color: 0xffffff} ); +// Generate a random color +function randColor() { + return Math.random() * 0xffffff; +}; + // Shape Node // parent: parent of the node // boundingbox: bounding box of the shape in world space @@ -15,8 +20,9 @@ export default class Shape { // Default empty this.parent = null; // this.boundingBox = new THREE.BoxGeometry(10, 10, 10); - this.mesh = new THREE.Mesh(new THREE.BoxGeometry(10, 10, 10), + this.mesh = new THREE.Mesh(new THREE.BoxGeometry(1, 1, 1), lambertWhite); + this.mesh.position.set(0, 0.5, 0); this.iteration = 0; } else { this.parent = parent; @@ -35,11 +41,50 @@ export default class Shape { }; - // If there is any Z subdivision then - subdivide() { // 0 = x, 1 = y, 2 = z - if (this.children.length === 0) { + + + // Creates a gate + + // Creates floors + // Can only create on a building that has floors for the first time + // This should only happen once per building and should really be the first thing that happens + createFloors(numFloors) { // subdivide - var axis = 2; // Just do this for now. + var s_factor = 0.5; + + var s = this.mesh.scale; + var p = this.mesh.position; + + var s_child = s.clone(); + var s_axis; + + if (numFloors != null && numFloors > 0) { + numFloors = Math.floor(numFloors); + s_axis = 1.0 / numFloors; + } else { + numFloors = 2.0; + s_axis = 0.5; + } + + s_axis = s.y * s_axis; + s_child.setComponent(1, s_axis); + + for(var i = 0; i < numFloors; i++) { + var child = new THREE.Mesh(new THREE.BoxGeometry(s_child.x, s_child.y, s_child.z), + new THREE.MeshLambertMaterial( {color: randColor()} )); + + child.position.set(p.x, p.y - s.y / 2.0 + s_axis / 2.0 + s_axis * i, p.z); + this.children.push(new Shape(this, child)); + } + }; + + // Subdivides Evenly in Half + // Should not be used for in y direction for floor creation + subdivide(axis) { // 0 = x, 1 = y, 2 = z + if (this.children.length === 0) { + if (axis == null) { + axis = 0; + } var s = this.mesh.scale; var p = this.mesh.position; @@ -122,16 +167,15 @@ export default class Shape { this.children[i].draw(scene, n); } } else { - // this.drawBbox(scene); scene.add(this.mesh); - //this.subdivide(); } }; - drawBbox(scene) { - var geo = new THREE.EdgesGeometry( this.mesh.geometry ); - var mat = new THREE.LineBasicMaterial( { color: 0x00ffff, linewidth: 2 } ); - var wireframe = new THREE.LineSegments( geo, mat ); - scene.add( wireframe ); - }; + // Well that didn't work + // drawBbox(scene) { + // var geo = new THREE.EdgesGeometry( this.mesh.geometry ); + // var mat = new THREE.LineBasicMaterial( { color: 0x00ffff, linewidth: 2 } ); + // var wireframe = new THREE.LineSegments( geo, mat ); + // scene.add( wireframe ); + // }; } \ No newline at end of file diff --git a/src/shapesystem.js b/src/shapesystem.js index 767ee955..0cea968c 100644 --- a/src/shapesystem.js +++ b/src/shapesystem.js @@ -47,7 +47,8 @@ export default function shapeSystem(axiom, grammar, scene) { this.traverse = function(scene) { if (a === false) { - axiom.subdivide(); + axiom.createFloors(3); + //axiom.subdivide(); a = true; } From a0b5a4dded5fdfa6caf9e3dfa50363ac8b1ca0a1 Mon Sep 17 00:00:00 2001 From: eldu Date: Fri, 17 Feb 2017 14:40:56 -0500 Subject: [PATCH 05/16] onings --- src/main.js | 16 ++++++++++++++-- src/shape.js | 7 ++++++- src/shapesystem.js | 39 ++++++++++++++++++++++----------------- 3 files changed, 42 insertions(+), 20 deletions(-) diff --git a/src/main.js b/src/main.js index 54e18f4f..8a3b1627 100644 --- a/src/main.js +++ b/src/main.js @@ -11,6 +11,10 @@ var lambertWhite = new THREE.MeshLambertMaterial( {color: 0xffffff} ); // Geometry var boxGeo = new THREE.BoxGeometry( 1, 1, 1 ); + + + + // Mesh var cubeMesh = new THREE.Mesh( boxGeo, lambertWhite ); @@ -45,7 +49,8 @@ function onLoad(framework) { // doLsystem(lsys, lsys.iterations, turtle); // }); - gui.add(ss, 'iteration', 0, 12).step(1).onChange(function(newVal) { + gui.add(ss, 'iteration').onChange(function(newVal) { + console.log('iterate'); }); @@ -84,7 +89,14 @@ function onLoad(framework) { plane.rotateX(Math.PI / 2.0); scene.add( plane ); - ss.traverse(scene); + var o = ss.createOningGeometry(new THREE.Vector3(4.0, 1.0, 10.0)); + o.position.set(0.0, 0.5, 0.0); + o.scale.set(4.0, 1.0, 10.0); + + scene.add(o); + + //scene.add(roof_mesh); + //ss.traverse(scene); } // // clears the scene by removing all geometries added by turtle.js diff --git a/src/shape.js b/src/shape.js index c7fc9885..f5661a93 100644 --- a/src/shape.js +++ b/src/shape.js @@ -22,8 +22,13 @@ export default class Shape { // this.boundingBox = new THREE.BoxGeometry(10, 10, 10); this.mesh = new THREE.Mesh(new THREE.BoxGeometry(1, 1, 1), lambertWhite); - this.mesh.position.set(0, 0.5, 0); + this.mesh.scale.set(5, 5, 5); + this.mesh.position.set(0, 2.5, 0); this.iteration = 0; + + // For continuation purposes + this.name = 'floor'; + this.show = true; } else { this.parent = parent; // this.boundingBox = boundingBox; diff --git a/src/shapesystem.js b/src/shapesystem.js index 0cea968c..36978d9b 100644 --- a/src/shapesystem.js +++ b/src/shapesystem.js @@ -1,3 +1,4 @@ +const THREE = require('three'); import Shape from './shape.js' import Framework from './framework' @@ -54,22 +55,26 @@ export default function shapeSystem(axiom, grammar, scene) { axiom.draw(scene, this.iterations); } - // This function returns a linked list that is the result - // of expanding the L-system's axiom n times. - // The implementation we have provided you just returns a linked - // list of the axiom. - // this.doIterations = function(n) { - // draw(i, scene) { - // if (i < this.iteration) { - // for(var i = 0; i < this.children.length; i++) { - // this.children.draw(i, scene); - // } - // } else if (i == this.iteration) { - // scene - // } else { - // return; - // } - // } - // } + + // Returns a (1, 1, 1) rectangular prism with the top shrunk in so that when scaled + // to the input it looks like a oning of a building in the forbidden city + this.createOningGeometry = function(scale, width) { + if (!width) { + width = 1.0; // Standard width of the oning + } + + var oning = new THREE.BoxGeometry( 1, 1, 1 ); + var v = oning.vertices; + // console.log(roof.vertices); + var sx = (scale.x - width) / (scale.x * 2.0); + var sz = (scale.z - width) / (scale.z * 2.0); + + v[0].set(sx, 0.5, sz); + v[1].set(sx, 0.5, -sz); + v[4].set(-sx, 0.5, -sz); + v[5].set(-sx, 0.5, sz); + var oning_mesh = new THREE.Mesh(oning, new THREE.MeshLambertMaterial()); + return oning_mesh; + } } \ No newline at end of file From a94841b5beddc8e40af3e6c81ca0d96358c89165 Mon Sep 17 00:00:00 2001 From: eldu Date: Fri, 17 Feb 2017 14:57:24 -0500 Subject: [PATCH 06/16] Roof --- src/main.js | 4 ++-- src/shapesystem.js | 34 ++++++++++++++++++++++++++++++++-- 2 files changed, 34 insertions(+), 4 deletions(-) diff --git a/src/main.js b/src/main.js index 8a3b1627..04a261da 100644 --- a/src/main.js +++ b/src/main.js @@ -89,9 +89,9 @@ function onLoad(framework) { plane.rotateX(Math.PI / 2.0); scene.add( plane ); - var o = ss.createOningGeometry(new THREE.Vector3(4.0, 1.0, 10.0)); + var o = ss.createRoofGeometry(new THREE.Vector3(4.0, 1.0, 10.0)); o.position.set(0.0, 0.5, 0.0); - o.scale.set(4.0, 1.0, 10.0); + // o.scale.set(4.0, 1.0, 10.0); scene.add(o); diff --git a/src/shapesystem.js b/src/shapesystem.js index 36978d9b..fa7f8c57 100644 --- a/src/shapesystem.js +++ b/src/shapesystem.js @@ -63,9 +63,10 @@ export default function shapeSystem(axiom, grammar, scene) { width = 1.0; // Standard width of the oning } - var oning = new THREE.BoxGeometry( 1, 1, 1 ); + var oning = new THREE.BoxGeometry( 1.0, 1.0, 1.0 ); var v = oning.vertices; - // console.log(roof.vertices); + + console.log(oning.vertices); var sx = (scale.x - width) / (scale.x * 2.0); var sz = (scale.z - width) / (scale.z * 2.0); @@ -74,7 +75,36 @@ export default function shapeSystem(axiom, grammar, scene) { v[4].set(-sx, 0.5, -sz); v[5].set(-sx, 0.5, sz); var oning_mesh = new THREE.Mesh(oning, new THREE.MeshLambertMaterial()); + oning_mesh.scale.set(scale.x, scale.y, scale.z); return oning_mesh; } + this.createRoofGeometry = function(scale, width) { + if (!width) { + width = 2.0; + } + + var roof = new THREE.BoxGeometry( 1.0, 1.0, 1.0 ); + var v = roof.vertices; + + var sx, sz; + if (scale.x >= scale.z) { + sx = (scale.x - width) / (scale.x * 2.0); + sz = 0.0; + } else { // scale.z > scale.x + sx = 0.0; + sz = (scale.z - width) / (scale.z * 2.0); + } + + v[0].set(sx, 0.5, sz); + v[1].set(sx, 0.5, -sz); + v[4].set(-sx, 0.5, -sz); + v[5].set(-sx, 0.5, sz); + + var roof_mesh = new THREE.Mesh(roof, new THREE.MeshLambertMaterial()); + roof_mesh.scale.set(scale.x, scale.y, scale.z); + + return roof_mesh; + } + } \ No newline at end of file From 6d885fc8c14d857feb28d113b65859033abd2ced Mon Sep 17 00:00:00 2001 From: eldu Date: Fri, 17 Feb 2017 18:18:36 -0500 Subject: [PATCH 07/16] Box with columns --- src/main.js | 21 ++++++++++++++++----- src/shapesystem.js | 43 ++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 58 insertions(+), 6 deletions(-) diff --git a/src/main.js b/src/main.js index 04a261da..164fe8e2 100644 --- a/src/main.js +++ b/src/main.js @@ -72,6 +72,7 @@ function onLoad(framework) { // scene.add(obj); // // scene.add(cylinder); + // combining geometeries // var ballGeo = new THREE.SphereGeometry(10,35,35); // var material = new THREE.MeshLambertMaterial(); // var ball = new THREE.Mesh(ballGeo, material); @@ -89,17 +90,27 @@ function onLoad(framework) { plane.rotateX(Math.PI / 2.0); scene.add( plane ); - var o = ss.createRoofGeometry(new THREE.Vector3(4.0, 1.0, 10.0)); - o.position.set(0.0, 0.5, 0.0); - // o.scale.set(4.0, 1.0, 10.0); + // var o = ss.createRoofGeometry(new THREE.Vector3(4.0, 1.0, 10.0)); + // o.position.set(0.0, 0.5, 0.0); - scene.add(o); + // scene.add(o); + + var c = ss.createBoxwColGeometry(new THREE.Vector3(2.0, 1.0, 2.0)); + // var bbox = new THREE.Box3().setFromObject(c); + + var geo = new THREE.EdgesGeometry( c.geometry ); + var mat = new THREE.LineBasicMaterial( { color: 0x00ffff, linewidth: 2 } ); + var wireframe = new THREE.LineSegments( geo, mat ); + scene.add( wireframe ); + + //c.position.set(0.0, 0.5, 0.0); + scene.add(c); //scene.add(roof_mesh); //ss.traverse(scene); } -// // clears the scene by removing all geometries added by turtle.js +// clears the scene by removing all geometries added by turtle.js // function clearScene(turtle) { // var obj; // for( var i = turtle.scene.children.length - 1; i > 3; i--) { diff --git a/src/shapesystem.js b/src/shapesystem.js index fa7f8c57..dcda2809 100644 --- a/src/shapesystem.js +++ b/src/shapesystem.js @@ -66,7 +66,7 @@ export default function shapeSystem(axiom, grammar, scene) { var oning = new THREE.BoxGeometry( 1.0, 1.0, 1.0 ); var v = oning.vertices; - console.log(oning.vertices); + // console.log(oning.vertices); var sx = (scale.x - width) / (scale.x * 2.0); var sz = (scale.z - width) / (scale.z * 2.0); @@ -107,4 +107,45 @@ export default function shapeSystem(axiom, grammar, scene) { return roof_mesh; } + // Scale of the space + // Width for how much space on the perimeter should the columns take up + this.createBoxwColGeometry = function(scale, width) { + if (!width) { + width = 0.25; + } + + var sx = (scale.x - width) / scale.x; + var sz = (scale.z - width) / scale.z; + + var geo = new THREE.BoxGeometry( sx, 1.0, sz ); + var v = geo.vertices; + + var r = width / 4.0; + + var colGeo1 = new THREE.CylinderGeometry(r, r, 1.0, 10.0); + colGeo1.translate(sx / 2.0 + r, 0.0, sz / 2.0 + r); + + var colGeo2 = new THREE.CylinderGeometry(r, r, 1.0, 10.0); + colGeo2.translate(sx / 2.0 + r, 0.0, -sz / 2.0 - r); + + var colGeo3 = new THREE.CylinderGeometry(r, r, 1.0, 10.0); + colGeo3.translate(-sx / 2.0 - r, 0.0, sz / 2.0 + r); + + var colGeo4 = new THREE.CylinderGeometry(r, r, 1.0, 10.0); + colGeo4.translate(-sx / 2.0 - r, 0.0, -sz / 2.0 - r); + + geo.merge(colGeo1); + geo.merge(colGeo2); + geo.merge(colGeo3); + geo.merge(colGeo4); + + var mesh = new THREE.Mesh(geo, new THREE.MeshLambertMaterial()); + + mesh.scale.set(scale.x, scale.y, scale.z); + + + + return mesh; + } + } \ No newline at end of file From 69a998f74210252873214044b2ce3d8a53b533b5 Mon Sep 17 00:00:00 2001 From: eldu Date: Fri, 17 Feb 2017 18:22:53 -0500 Subject: [PATCH 08/16] fixed column warping --- src/main.js | 2 +- src/shapesystem.js | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main.js b/src/main.js index 164fe8e2..fc676f01 100644 --- a/src/main.js +++ b/src/main.js @@ -95,7 +95,7 @@ function onLoad(framework) { // scene.add(o); - var c = ss.createBoxwColGeometry(new THREE.Vector3(2.0, 1.0, 2.0)); + var c = ss.createBoxwColGeometry(new THREE.Vector3(2.0, 1.0, 3.0)); // var bbox = new THREE.Box3().setFromObject(c); var geo = new THREE.EdgesGeometry( c.geometry ); diff --git a/src/shapesystem.js b/src/shapesystem.js index dcda2809..7cf23045 100644 --- a/src/shapesystem.js +++ b/src/shapesystem.js @@ -123,15 +123,19 @@ export default function shapeSystem(axiom, grammar, scene) { var r = width / 4.0; var colGeo1 = new THREE.CylinderGeometry(r, r, 1.0, 10.0); + colGeo1.scale(1.0/scale.x, 1.0, 1.0/scale.z); colGeo1.translate(sx / 2.0 + r, 0.0, sz / 2.0 + r); var colGeo2 = new THREE.CylinderGeometry(r, r, 1.0, 10.0); + colGeo2.scale(1.0/scale.x, 1.0, 1.0/scale.z); colGeo2.translate(sx / 2.0 + r, 0.0, -sz / 2.0 - r); var colGeo3 = new THREE.CylinderGeometry(r, r, 1.0, 10.0); + colGeo3.scale(1.0/scale.x, 1.0, 1.0/scale.z); colGeo3.translate(-sx / 2.0 - r, 0.0, sz / 2.0 + r); var colGeo4 = new THREE.CylinderGeometry(r, r, 1.0, 10.0); + colGeo4.scale(1.0/scale.x, 1.0, 1.0/scale.z); colGeo4.translate(-sx / 2.0 - r, 0.0, -sz / 2.0 - r); geo.merge(colGeo1); @@ -140,11 +144,7 @@ export default function shapeSystem(axiom, grammar, scene) { geo.merge(colGeo4); var mesh = new THREE.Mesh(geo, new THREE.MeshLambertMaterial()); - mesh.scale.set(scale.x, scale.y, scale.z); - - - return mesh; } From 77f7660f7dfc0ff008ddf8c27df88495de7cd7f2 Mon Sep 17 00:00:00 2001 From: eldu Date: Fri, 17 Feb 2017 18:43:39 -0500 Subject: [PATCH 09/16] redid drawing tree --- src/main.js | 76 +++------------------------------------------- src/shape.js | 8 +++-- src/shapesystem.js | 11 +++++-- 3 files changed, 19 insertions(+), 76 deletions(-) diff --git a/src/main.js b/src/main.js index fc676f01..96457c7b 100644 --- a/src/main.js +++ b/src/main.js @@ -11,10 +11,6 @@ var lambertWhite = new THREE.MeshLambertMaterial( {color: 0xffffff} ); // Geometry var boxGeo = new THREE.BoxGeometry( 1, 1, 1 ); - - - - // Mesh var cubeMesh = new THREE.Mesh( boxGeo, lambertWhite ); @@ -38,87 +34,23 @@ function onLoad(framework) { camera.lookAt(new THREE.Vector3(0,0,0)); var axiom = new Shape(); - var ss = new ShapeSystem(axiom, boxGeo, cubeMesh); + var ss = new ShapeSystem(axiom, scene); gui.add(camera, 'fov', 0, 180).onChange(function(newVal) { camera.updateProjectionMatrix(); }); - // gui.add(lsys, 'axiom').onChange(function(newVal) { - // lsys.updateAxiom(newVal); - // doLsystem(lsys, lsys.iterations, turtle); - // }); - - gui.add(ss, 'iteration').onChange(function(newVal) { - console.log('iterate'); - }); - - - // var obj = new THREE.Object3D(); - // var geometry = new THREE.BoxGeometry( 1, 1, 1 ); - // var material = new THREE.MeshBasicMaterial( {color: 0x00ff00} ); - // var cube = new THREE.Mesh( geometry, material ); - - // var a = new THREE.CylinderGeometry( 1, 1, 1); - // a.position = new THREE.Vector3(0, 0, 5); - // var cylinder = new THREE.Mesh(a, new THREE.MeshBasicMaterial( {color: 0x0000ff} ) ); - - // var mat5 = new THREE.Matrix4(); - // mat5.makeTranslation(5, 0, 0); - // cylinder.applyMatrix(mat5); + gui.add(ss, 'iterate'); - // cube.add(cylinder); - // obj.add(cube); - // scene.add(obj); - // // scene.add(cylinder); - - // combining geometeries - // var ballGeo = new THREE.SphereGeometry(10,35,35); - // var material = new THREE.MeshLambertMaterial(); - // var ball = new THREE.Mesh(ballGeo, material); - - // var pendulumGeo = new THREE.CylinderGeometry(1, 1, 50, 16); - // ball.updateMatrix(); - // pendulumGeo.merge(ball.geometry, ball.matrix); - - // var pendulum = new THREE.Mesh(pendulumGeo, material); - // scene.add(pendulum); - - var geometry = new THREE.PlaneGeometry( 5, 20, 32 ); + var geometry = new THREE.PlaneGeometry( 20, 20, 32 ); var material = new THREE.MeshBasicMaterial( {color: 0xffff00, side: THREE.DoubleSide} ); var plane = new THREE.Mesh( geometry, material ); plane.rotateX(Math.PI / 2.0); scene.add( plane ); - // var o = ss.createRoofGeometry(new THREE.Vector3(4.0, 1.0, 10.0)); - // o.position.set(0.0, 0.5, 0.0); - - // scene.add(o); - - var c = ss.createBoxwColGeometry(new THREE.Vector3(2.0, 1.0, 3.0)); - // var bbox = new THREE.Box3().setFromObject(c); - - var geo = new THREE.EdgesGeometry( c.geometry ); - var mat = new THREE.LineBasicMaterial( { color: 0x00ffff, linewidth: 2 } ); - var wireframe = new THREE.LineSegments( geo, mat ); - scene.add( wireframe ); - - //c.position.set(0.0, 0.5, 0.0); - scene.add(c); - - //scene.add(roof_mesh); - //ss.traverse(scene); + ss.traverse(scene); } -// clears the scene by removing all geometries added by turtle.js -// function clearScene(turtle) { -// var obj; -// for( var i = turtle.scene.children.length - 1; i > 3; i--) { -// obj = turtle.scene.children[i]; -// turtle.scene.remove(obj); -// } -// } - // called on frame updates function onUpdate(framework) { } diff --git a/src/shape.js b/src/shape.js index f5661a93..9056e999 100644 --- a/src/shape.js +++ b/src/shape.js @@ -28,7 +28,6 @@ export default class Shape { // For continuation purposes this.name = 'floor'; - this.show = true; } else { this.parent = parent; // this.boundingBox = boundingBox; @@ -41,6 +40,7 @@ export default class Shape { } } + this.show = true; this.division = ''; // Current subdivision this.children = []; }; @@ -54,6 +54,7 @@ export default class Shape { // Can only create on a building that has floors for the first time // This should only happen once per building and should really be the first thing that happens createFloors(numFloors) { + this.show = false; // subdivide var s_factor = 0.5; @@ -91,6 +92,8 @@ export default class Shape { axis = 0; } + this.show = false; + var s = this.mesh.scale; var p = this.mesh.position; @@ -171,7 +174,8 @@ export default class Shape { for(var i = 0; i < this.children.length; i++) { this.children[i].draw(scene, n); } - } else { + } + if (this.show === true) { scene.add(this.mesh); } }; diff --git a/src/shapesystem.js b/src/shapesystem.js index 7cf23045..3ff307f3 100644 --- a/src/shapesystem.js +++ b/src/shapesystem.js @@ -7,14 +7,16 @@ function Rule(successor, probability) { this.probability = probability; } -export default function shapeSystem(axiom, grammar, scene) { +export default function shapeSystem(axiom, scene) { if (axiom instanceof Shape) { this.axiom = axiom; } else { this.axiom = new Shape(); } - this.grammar = grammar; + + + //this.grammar = grammar; this.iteration = 0; this.scene = scene; @@ -56,6 +58,11 @@ export default function shapeSystem(axiom, grammar, scene) { axiom.draw(scene, this.iterations); } + this.iterate = function() { + // remember scene is available through this.scene + console.log('iterate'); + } + // Returns a (1, 1, 1) rectangular prism with the top shrunk in so that when scaled // to the input it looks like a oning of a building in the forbidden city this.createOningGeometry = function(scale, width) { From bef801812e2f0d9b26b6ef54e055b7f5cc364615 Mon Sep 17 00:00:00 2001 From: eldu Date: Fri, 17 Feb 2017 20:28:38 -0500 Subject: [PATCH 10/16] simple iteration --- src/assets.js | 2 - src/main.js | 3 +- src/shape.js | 125 +++++++++++++++++++++++---------------------- src/shapesystem.js | 33 ++++++++---- 4 files changed, 88 insertions(+), 75 deletions(-) delete mode 100644 src/assets.js diff --git a/src/assets.js b/src/assets.js deleted file mode 100644 index 5a9abce0..00000000 --- a/src/assets.js +++ /dev/null @@ -1,2 +0,0 @@ -const THREE = require('three'); - diff --git a/src/main.js b/src/main.js index 96457c7b..96ab63aa 100644 --- a/src/main.js +++ b/src/main.js @@ -33,7 +33,7 @@ function onLoad(framework) { camera.position.set(50, 100, 200); camera.lookAt(new THREE.Vector3(0,0,0)); - var axiom = new Shape(); + var axiom = [new Shape()]; var ss = new ShapeSystem(axiom, scene); gui.add(camera, 'fov', 0, 180).onChange(function(newVal) { @@ -48,6 +48,7 @@ function onLoad(framework) { plane.rotateX(Math.PI / 2.0); scene.add( plane ); + // ss.axiom[0].subdivide(0); ss.traverse(scene); } diff --git a/src/shape.js b/src/shape.js index 9056e999..cc1cd1f2 100644 --- a/src/shape.js +++ b/src/shape.js @@ -9,13 +9,21 @@ function randColor() { return Math.random() * 0xffffff; }; +function mapRand(start, end) { + return Math.random * (end - start) + start; +}; + +function mat_randColor() { + return new THREE.MeshLambertMaterial({color:randColor()}); +} + // Shape Node // parent: parent of the node // boundingbox: bounding box of the shape in world space // geometry: geometry to render // children export default class Shape { - constructor(parent, mesh) { + constructor(parent, mesh, name) { if (arguments.length === 0) { // Default empty this.parent = null; @@ -27,8 +35,14 @@ export default class Shape { this.iteration = 0; // For continuation purposes - this.name = 'floor'; + this.name = 'building'; } else { + if (name) { + this.name = name; + } else { + this.name = ''; + } + this.parent = parent; // this.boundingBox = boundingBox; this.mesh = mesh; @@ -45,11 +59,6 @@ export default class Shape { this.children = []; }; - - - - // Creates a gate - // Creates floors // Can only create on a building that has floors for the first time // This should only happen once per building and should really be the first thing that happens @@ -80,68 +89,68 @@ export default class Shape { new THREE.MeshLambertMaterial( {color: randColor()} )); child.position.set(p.x, p.y - s.y / 2.0 + s_axis / 2.0 + s_axis * i, p.z); - this.children.push(new Shape(this, child)); + this.children.push(new Shape(this, child, i.toString())); // Indicate what floor it is } }; // Subdivides Evenly in Half - // Should not be used for in y direction for floor creation + // Should not be used for in y direction, instead use floor creation subdivide(axis) { // 0 = x, 1 = y, 2 = z + axis = 2; + this.show == false; + + var s = this.mesh.scale; + var p = this.mesh.position; + + // Random heights for the two different subdivisions + var h1 = mapRand(s.y / 2.0, s.y); + var h2 = mapRand(s.y / 2.0, s.y); + + + if (this.children.length === 0) { if (axis == null) { axis = 0; } + this.name = ''; // No longer a building once there are floors this.show = false; - var s = this.mesh.scale; - var p = this.mesh.position; if (axis == 0) { - var s_child = new THREE.Vector3(s.x / 2.0, s.y, s.z); - var p_left = new THREE.Vector3(p.x - s.x / 4.0, p.y, p.z); - var p_right = new THREE.Vector3(p.x + s.x / 4.0, p.y, p.z); + var sx1 = mapRand(s.x / 4.0, s.x / 2.0); + var sx2 = mapRand(s.x / 4.0, s.x / 2.0); + + var sz1 = mapRand(s.z / 2.0, s.z); + var sz2 = mapRand(s.z / 2.0, s.z); + + //var s_child = new THREE.Vector3(s.x / 2.0, s.y, s.z); + var p_left = new THREE.Vector3( + p.x - sx1 / 2.0, + p.y - s.y / 2.0 + h1 / 2.0, + p.z - s.z / 2.0 + sz1 / 2.0); + var p_right = new THREE.Vector3( + p.x + sx1 / 2.0, + p.y - s.y / 2.0 + h2 / 2.0, + p.z - s.z / 2.0 + sz2 / 2.0); var left = new THREE.Mesh( - new THREE.BoxGeometry(s_child.x, s_child.y, s_child.z), - lambertWhite); - - lambertWhite = new THREE.MeshLambertMaterial( {color: 0x00ffff} ); + new THREE.BoxGeometry(1.0, 1.0, 1.0), + mat_randColor()); + left.scale.set(sx1, h1, sz1); var right = new THREE.Mesh( - new THREE.BoxGeometry(s_child.x, s_child.y, s_child.z), - lambertWhite); + new THREE.BoxGeometry(1.0, 1.0, 1.0), + mat_randColor()); + right.scale.set(sx2, h2, sz2); + left.position.set(p_left.x, p_left.y, p_left.z); right.position.set(p_right.x, p_right.y, p_right.z); - this.children.push(new Shape(this, left)); - this.children.push(new Shape(this, right)); - } else if (axis == 1) { - var s = this.mesh.scale; - var p = this.mesh.position; - - var s_child = new THREE.Vector3(s.x, s.y / 2.0, s.z); - - var p_bottom = new THREE.Vector3(p.x, p.y - s.y / 4.0, p.z); - var p_top = new THREE.Vector3(p.x, p.y + s.y / 4.0, p.z); - - var bottom = new THREE.Mesh( - new THREE.BoxGeometry(s_child.x, s_child.y, s_child.z), - lambertWhite); - bottom.position.set(p_bottom.x, p_bottom.y, p_bottom.z); - - lambertWhite = new THREE.MeshLambertMaterial( {color: 0x00ffff} ); - var top = new THREE.Mesh( - new THREE.BoxGeometry(s_child.x, s_child.y, s_child.z), - lambertWhite); - top.position.set(p_top.x, p_top.y, p_top.z); - - this.children.push(new Shape(this, top)); - this.children.push(new Shape(this, bottom)); - - } else { - var s = this.mesh.scale; - var p = this.mesh.position; + // Add to the childrenc + this.children.push(new Shape(this, left, 'building')); + this.children.push(new Shape(this, right, 'building')); + } else { var s_child = new THREE.Vector3(s.x, s.y, s.z / 2.0); var p_front = new THREE.Vector3(p.x, p.y, p.z + s.z / 4.0); @@ -149,17 +158,16 @@ export default class Shape { var front = new THREE.Mesh( new THREE.BoxGeometry(s_child.x, s_child.y, s_child.z), - lambertWhite); + mat_randColor()); front.position.set(p_front.x, p_front.y, p_front.z); - lambertWhite = new THREE.MeshLambertMaterial( {color: 0x00ffff} ); var back = new THREE.Mesh( new THREE.BoxGeometry(s_child.x, s_child.y, s_child.z), - lambertWhite); + mat_randColor()); back.position.set(p_back.x, p_back.y, p_back.z); - this.children.push(new Shape(this, front)); - this.children.push(new Shape(this, back)); + this.children.push(new Shape(this, front, 'building')); + this.children.push(new Shape(this, back, 'building')); } } else { for(var i = 0; i < this.children.length; i++) { @@ -177,14 +185,9 @@ export default class Shape { } if (this.show === true) { scene.add(this.mesh); + } + else { + scene.remove(this.mesh); } }; - - // Well that didn't work - // drawBbox(scene) { - // var geo = new THREE.EdgesGeometry( this.mesh.geometry ); - // var mat = new THREE.LineBasicMaterial( { color: 0x00ffff, linewidth: 2 } ); - // var wireframe = new THREE.LineSegments( geo, mat ); - // scene.add( wireframe ); - // }; } \ No newline at end of file diff --git a/src/shapesystem.js b/src/shapesystem.js index 3ff307f3..afc28fac 100644 --- a/src/shapesystem.js +++ b/src/shapesystem.js @@ -8,12 +8,18 @@ function Rule(successor, probability) { } export default function shapeSystem(axiom, scene) { - if (axiom instanceof Shape) { + if (axiom) { this.axiom = axiom; } else { - this.axiom = new Shape(); + this.axiom = [new Shape()]; } + this.grammar = { + 'bottom' : 'create columns', + 'building' : 'createFloors or subdivide', + 'middle': 'possible oning', + 'top': 'add a roof' + }; //this.grammar = grammar; @@ -46,20 +52,25 @@ export default function shapeSystem(axiom, scene) { } } - var a = false; - - this.traverse = function(scene) { - if (a === false) { - axiom.createFloors(3); - //axiom.subdivide(); - a = true; + this.traverse = function() { + for (var i = 0; i < axiom.length; i++) { + axiom[i].draw(this.scene, this.iterations); } - - axiom.draw(scene, this.iterations); } this.iterate = function() { // remember scene is available through this.scene + + // Clear everything from the scene + // this.scene.children.forEach(function(object){ + // scene.remove(object); + // }); + + axiom[0].subdivide(); + + this.traverse(); + + this.iterations++ console.log('iterate'); } From 641447f0f52716ee1f05230f3458b3f98613fbf1 Mon Sep 17 00:00:00 2001 From: eldu Date: Fri, 17 Feb 2017 20:44:43 -0500 Subject: [PATCH 11/16] asymetrical subdivision and iteration --- src/shape.js | 76 ++++++++++++++++++++++++++++++---------------- src/shapesystem.js | 2 +- 2 files changed, 51 insertions(+), 27 deletions(-) diff --git a/src/shape.js b/src/shape.js index cc1cd1f2..ad163b40 100644 --- a/src/shape.js +++ b/src/shape.js @@ -10,7 +10,7 @@ function randColor() { }; function mapRand(start, end) { - return Math.random * (end - start) + start; + return Math.random() * (end - start) + start; }; function mat_randColor() { @@ -96,8 +96,17 @@ export default class Shape { // Subdivides Evenly in Half // Should not be used for in y direction, instead use floor creation subdivide(axis) { // 0 = x, 1 = y, 2 = z - axis = 2; - this.show == false; + // if (axis == 0) { + // axis = 1; + // } else { + // axis = 0; + // } + + // axis = 1; + + console.log(axis) + + // this.show == false; var s = this.mesh.scale; var p = this.mesh.position; @@ -107,7 +116,6 @@ export default class Shape { var h2 = mapRand(s.y / 2.0, s.y); - if (this.children.length === 0) { if (axis == null) { axis = 0; @@ -117,20 +125,21 @@ export default class Shape { this.show = false; + var sx1, sx2, sz1, sz2; + if (axis == 0) { - var sx1 = mapRand(s.x / 4.0, s.x / 2.0); - var sx2 = mapRand(s.x / 4.0, s.x / 2.0); + sx1 = mapRand(s.x / 4.0, s.x / 2.0); + sx2 = mapRand(s.x / 4.0, s.x / 2.0); - var sz1 = mapRand(s.z / 2.0, s.z); - var sz2 = mapRand(s.z / 2.0, s.z); + sz1 = mapRand(s.z / 2.0, s.z); + sz2 = mapRand(s.z / 2.0, s.z); - //var s_child = new THREE.Vector3(s.x / 2.0, s.y, s.z); var p_left = new THREE.Vector3( p.x - sx1 / 2.0, p.y - s.y / 2.0 + h1 / 2.0, p.z - s.z / 2.0 + sz1 / 2.0); var p_right = new THREE.Vector3( - p.x + sx1 / 2.0, + p.x + sx2 / 2.0, p.y - s.y / 2.0 + h2 / 2.0, p.z - s.z / 2.0 + sz2 / 2.0); @@ -147,31 +156,46 @@ export default class Shape { left.position.set(p_left.x, p_left.y, p_left.z); right.position.set(p_right.x, p_right.y, p_right.z); - // Add to the childrenc + // Add to the children this.children.push(new Shape(this, left, 'building')); this.children.push(new Shape(this, right, 'building')); - } else { - var s_child = new THREE.Vector3(s.x, s.y, s.z / 2.0); + } else { + sx1 = mapRand(s.x / 2.0, s.x); + sx2 = mapRand(s.x / 2.0, s.x); - var p_front = new THREE.Vector3(p.x, p.y, p.z + s.z / 4.0); - var p_back = new THREE.Vector3(p.x, p.y, p.z - s.z / 4.0); + sz1 = mapRand(s.z / 4.0, s.z / 2.0); + sz2 = mapRand(s.z / 4.0, s.z / 2.0); - var front = new THREE.Mesh( - new THREE.BoxGeometry(s_child.x, s_child.y, s_child.z), - mat_randColor()); - front.position.set(p_front.x, p_front.y, p_front.z); + var p_left = new THREE.Vector3( + p.x - s.x / 2.0 + sx1 / 2.0, + p.y - s.y / 2.0 + h1 / 2.0, + p.z - sz1 / 2.0); + var p_right = new THREE.Vector3( + p.x - s.x / 2.0 + sx2 / 2.0, + p.y - s.y / 2.0 + h2 / 2.0, + p.z + sz2 / 2.0); + + var left = new THREE.Mesh( + new THREE.BoxGeometry(1.0, 1.0, 1.0), + mat_randColor()); + left.scale.set(sx1, h1, sz1); + + var right = new THREE.Mesh( + new THREE.BoxGeometry(1.0, 1.0, 1.0), + mat_randColor()); + right.scale.set(sx2, h2, sz2); - var back = new THREE.Mesh( - new THREE.BoxGeometry(s_child.x, s_child.y, s_child.z), - mat_randColor()); - back.position.set(p_back.x, p_back.y, p_back.z); + left.position.set(p_left.x, p_left.y, p_left.z); + right.position.set(p_right.x, p_right.y, p_right.z); - this.children.push(new Shape(this, front, 'building')); - this.children.push(new Shape(this, back, 'building')); + // Add to the children + this.children.push(new Shape(this, left, 'building')); + this.children.push(new Shape(this, right, 'building')); } + } else { for(var i = 0; i < this.children.length; i++) { - this.children[i].subdivide(); + this.children[i].subdivide(i % 2); } } }; diff --git a/src/shapesystem.js b/src/shapesystem.js index afc28fac..34bc607f 100644 --- a/src/shapesystem.js +++ b/src/shapesystem.js @@ -66,7 +66,7 @@ export default function shapeSystem(axiom, scene) { // scene.remove(object); // }); - axiom[0].subdivide(); + axiom[0].subdivide(0); this.traverse(); From d1d4b5234e70002127e48fceec4eb7e2926fe604 Mon Sep 17 00:00:00 2001 From: eldu Date: Fri, 17 Feb 2017 21:09:21 -0500 Subject: [PATCH 12/16] floors and subdivision --- src/shape.js | 97 +++++++++++++++++++++++++++------------------- src/shapesystem.js | 27 +++++++------ 2 files changed, 70 insertions(+), 54 deletions(-) diff --git a/src/shape.js b/src/shape.js index ad163b40..1e8fcd75 100644 --- a/src/shape.js +++ b/src/shape.js @@ -63,60 +63,53 @@ export default class Shape { // Can only create on a building that has floors for the first time // This should only happen once per building and should really be the first thing that happens createFloors(numFloors) { - this.show = false; - // subdivide - var s_factor = 0.5; + this.show = false; + this.name = ''; // No longer a building - var s = this.mesh.scale; - var p = this.mesh.position; + // subdivide + var s_factor = 0.5; - var s_child = s.clone(); - var s_axis; + var s = this.mesh.scale; + var p = this.mesh.position; - if (numFloors != null && numFloors > 0) { - numFloors = Math.floor(numFloors); - s_axis = 1.0 / numFloors; - } else { - numFloors = 2.0; - s_axis = 0.5; - } + var s_child = s.clone(); + var s_axis; - s_axis = s.y * s_axis; - s_child.setComponent(1, s_axis); + if (numFloors != null && numFloors > 0) { + numFloors = Math.floor(numFloors); + s_axis = 1.0 / numFloors; + } else { + numFloors = 2.0; + s_axis = 0.5; + } - for(var i = 0; i < numFloors; i++) { - var child = new THREE.Mesh(new THREE.BoxGeometry(s_child.x, s_child.y, s_child.z), - new THREE.MeshLambertMaterial( {color: randColor()} )); + s_axis = s.y * s_axis; + s_child.setComponent(1, s_axis); - child.position.set(p.x, p.y - s.y / 2.0 + s_axis / 2.0 + s_axis * i, p.z); - this.children.push(new Shape(this, child, i.toString())); // Indicate what floor it is + for(var i = 0; i < numFloors; i++) { + var child = new THREE.Mesh(new THREE.BoxGeometry(s_child.x, s_child.y, s_child.z), + new THREE.MeshLambertMaterial( {color: randColor()} )); + + child.position.set(p.x, p.y - s.y / 2.0 + s_axis / 2.0 + s_axis * i, p.z); + var shape = new Shape(this, child, i.toString()); + if (i == numFloors - 1) { + shape.name = 'top'; } + this.children.push(shape); + } }; // Subdivides Evenly in Half // Should not be used for in y direction, instead use floor creation subdivide(axis) { // 0 = x, 1 = y, 2 = z - // if (axis == 0) { - // axis = 1; - // } else { - // axis = 0; - // } - - // axis = 1; - - console.log(axis) - - // this.show == false; - - var s = this.mesh.scale; - var p = this.mesh.position; - - // Random heights for the two different subdivisions - var h1 = mapRand(s.y / 2.0, s.y); - var h2 = mapRand(s.y / 2.0, s.y); + if (this.children.length === 0) { + var s = this.mesh.scale; + var p = this.mesh.position; + // Random heights for the two different subdivisions + var h1 = mapRand(s.y / 2.0, s.y); + var h2 = mapRand(s.y / 2.0, s.y); - if (this.children.length === 0) { if (axis == null) { axis = 0; } @@ -200,6 +193,30 @@ export default class Shape { } }; + // THIS IS WHERE ALL THE GRAMMAR IS BASICALLY + // This is called by the ShapeSystem whatever. + iterate() { + var r = Math.random(); + + if (this.children.length > 0) { + for(var i = 0; i < this.children.length; i++) { + this.children[i].iterate(); + } + } + + if (this.name == 'building') { + if (r < 0.8) { + // Subdivide + + this.subdivide(0); + } else { + r = Math.random(); + + this.createFloors(6); // Creates floors + } + } + } + draw(scene, n) { // if (n < this.iteration && this.children.length != 0) { if (this.children.length > 0) { diff --git a/src/shapesystem.js b/src/shapesystem.js index 34bc607f..b90126d1 100644 --- a/src/shapesystem.js +++ b/src/shapesystem.js @@ -14,13 +14,13 @@ export default function shapeSystem(axiom, scene) { this.axiom = [new Shape()]; } - this.grammar = { - 'bottom' : 'create columns', - 'building' : 'createFloors or subdivide', - 'middle': 'possible oning', - 'top': 'add a roof' - }; - + // LOL JK FORGET THIS, JUST GO TO ITERATE I MEAN IT"S JUST THERE, BYE + // this.grammar = { + // 'bottom' : 'create columns', + // 'building' : 'createFloors or subdivide', + // 'middle': 'possible oning', + // 'top': 'add a roof' + // }; //this.grammar = grammar; this.iteration = 0; @@ -59,16 +59,15 @@ export default function shapeSystem(axiom, scene) { } this.iterate = function() { - // remember scene is available through this.scene - - // Clear everything from the scene - // this.scene.children.forEach(function(object){ - // scene.remove(object); - // }); + for (var i = 0; i < axiom.length; i++) { + var a = axiom[i]; - axiom[0].subdivide(0); + // Iterate + a.iterate(); + } this.traverse(); + this.iterations++ console.log('iterate'); From 17585ff7ccff120f2fb44826f5589a6d0a57a101 Mon Sep 17 00:00:00 2001 From: eldu Date: Fri, 17 Feb 2017 22:00:12 -0500 Subject: [PATCH 13/16] roofs --- src/shape.js | 146 +++++++++++++++++++++++++++++++++++++++++---- src/shapesystem.js | 93 ----------------------------- 2 files changed, 134 insertions(+), 105 deletions(-) diff --git a/src/shape.js b/src/shape.js index 1e8fcd75..f2aa3237 100644 --- a/src/shape.js +++ b/src/shape.js @@ -30,8 +30,8 @@ export default class Shape { // this.boundingBox = new THREE.BoxGeometry(10, 10, 10); this.mesh = new THREE.Mesh(new THREE.BoxGeometry(1, 1, 1), lambertWhite); - this.mesh.scale.set(5, 5, 5); - this.mesh.position.set(0, 2.5, 0); + this.mesh.scale.set(10, 10, 10); + this.mesh.position.set(0, 5, 0); this.iteration = 0; // For continuation purposes @@ -87,12 +87,17 @@ export default class Shape { s_child.setComponent(1, s_axis); for(var i = 0; i < numFloors; i++) { - var child = new THREE.Mesh(new THREE.BoxGeometry(s_child.x, s_child.y, s_child.z), + var child = new THREE.Mesh(new THREE.BoxGeometry(1.0, 1.0, 1.0), new THREE.MeshLambertMaterial( {color: randColor()} )); + child.scale.set(s_child.x, s_child.y, s_child.z); child.position.set(p.x, p.y - s.y / 2.0 + s_axis / 2.0 + s_axis * i, p.z); - var shape = new Shape(this, child, i.toString()); - if (i == numFloors - 1) { + var shape = new Shape(this, child, 'floor'); + + if (i == 0) { + shape.name = 'bottom'; + } + else if (i == numFloors - 1) { shape.name = 'top'; } this.children.push(shape); @@ -193,6 +198,105 @@ export default class Shape { } }; + // Returns a (1, 1, 1) rectangular prism with the top shrunk in so that when scaled + // to the input it looks like a oning of a building in the forbidden city + createOningGeometry(scale, width) { + if (!width) { + width = 1.0; // Standard width of the oning + } + + var oning = new THREE.BoxGeometry( 1.0, 1.0, 1.0 ); + var v = oning.vertices; + + // console.log(oning.vertices); + var sx = (scale.x - width) / (scale.x * 2.0); + var sz = (scale.z - width) / (scale.z * 2.0); + + v[0].set(sx, 0.5, sz); + v[1].set(sx, 0.5, -sz); + v[4].set(-sx, 0.5, -sz); + v[5].set(-sx, 0.5, sz); + var oning_mesh = new THREE.Mesh(oning, new THREE.MeshLambertMaterial()); + oning_mesh.scale.set(scale.x, scale.y, scale.z); + return oning_mesh; + }; + + createRoofGeometry(scale, width) { + this.name = ''; + + if (!width) { + width = 2.0; + } + + var roof = new THREE.BoxGeometry( 1.0, 1.0, 1.0 ); + var v = roof.vertices; + + var sx, sz; + if (scale.x <= scale.z) { + sx = (scale.x - width) / (scale.x * 2.0); + sz = 0.0; + } else { // scale.z > scale.x + sx = 0.0; + sz = (scale.z - width) / (scale.z * 2.0); + } + + v[0].set(sx, 0.5, sz); + v[1].set(sx, 0.5, -sz); + v[4].set(-sx, 0.5, -sz); + v[5].set(-sx, 0.5, sz); + + var roof_mesh = new THREE.Mesh(roof, new THREE.MeshLambertMaterial()); + roof_mesh.scale.set(scale.x, scale.y, scale.z); + + var p = this.mesh.position; + roof_mesh.position.set(p.x, p.y + scale.y, p.z); + + this.children.push(new Shape(this, roof_mesh, 'roof')); + + //return roof_mesh; + }; + + // Scale of the space + // Width for how much space on the perimeter should the columns take up + createBoxwColGeometry(scale, width) { + if (!width) { + width = 0.25; + } + + var sx = (scale.x - width) / scale.x; + var sz = (scale.z - width) / scale.z; + + var geo = new THREE.BoxGeometry( sx, 1.0, sz ); + var v = geo.vertices; + + var r = width / 4.0; + + var colGeo1 = new THREE.CylinderGeometry(r, r, 1.0, 10.0); + colGeo1.scale(1.0/scale.x, 1.0, 1.0/scale.z); + colGeo1.translate(sx / 2.0 + r, 0.0, sz / 2.0 + r); + + var colGeo2 = new THREE.CylinderGeometry(r, r, 1.0, 10.0); + colGeo2.scale(1.0/scale.x, 1.0, 1.0/scale.z); + colGeo2.translate(sx / 2.0 + r, 0.0, -sz / 2.0 - r); + + var colGeo3 = new THREE.CylinderGeometry(r, r, 1.0, 10.0); + colGeo3.scale(1.0/scale.x, 1.0, 1.0/scale.z); + colGeo3.translate(-sx / 2.0 - r, 0.0, sz / 2.0 + r); + + var colGeo4 = new THREE.CylinderGeometry(r, r, 1.0, 10.0); + colGeo4.scale(1.0/scale.x, 1.0, 1.0/scale.z); + colGeo4.translate(-sx / 2.0 - r, 0.0, -sz / 2.0 - r); + + geo.merge(colGeo1); + geo.merge(colGeo2); + geo.merge(colGeo3); + geo.merge(colGeo4); + + var mesh = new THREE.Mesh(geo, new THREE.MeshLambertMaterial()); + mesh.scale.set(scale.x, scale.y, scale.z); + return mesh; + } + // THIS IS WHERE ALL THE GRAMMAR IS BASICALLY // This is called by the ShapeSystem whatever. iterate() { @@ -204,18 +308,36 @@ export default class Shape { } } - if (this.name == 'building') { + // This is a finished intermediate node that no longer matters in terms of iteration + if (this.name == '') { + return; + } else if (this.name == 'building') { + // Subdivision into more buildings if (r < 0.8) { - // Subdivide - - this.subdivide(0); + if (r < 0.4) { + this.subdivide(0); + } else { + this.subdivide(1); + } + + // Divides the building into at least 2 floors + // More floors the taller the building is though } else { - r = Math.random(); + this.createFloors(Math.floor(Math.random() * this.mesh.scale.y) + 2); + } + } else if (this.name == 'top') { + if (r < 0.8) { + // make a roof + console.log('making a roof'); + this.createRoofGeometry(this.mesh.scale, this.mesh.scale.x / 4.0); + } + } else if (this.name == 'bottom') { + if (r < 0.5) { + // add columns - this.createFloors(6); // Creates floors } } - } + }; draw(scene, n) { // if (n < this.iteration && this.children.length != 0) { diff --git a/src/shapesystem.js b/src/shapesystem.js index b90126d1..d34436be 100644 --- a/src/shapesystem.js +++ b/src/shapesystem.js @@ -72,97 +72,4 @@ export default function shapeSystem(axiom, scene) { this.iterations++ console.log('iterate'); } - - // Returns a (1, 1, 1) rectangular prism with the top shrunk in so that when scaled - // to the input it looks like a oning of a building in the forbidden city - this.createOningGeometry = function(scale, width) { - if (!width) { - width = 1.0; // Standard width of the oning - } - - var oning = new THREE.BoxGeometry( 1.0, 1.0, 1.0 ); - var v = oning.vertices; - - // console.log(oning.vertices); - var sx = (scale.x - width) / (scale.x * 2.0); - var sz = (scale.z - width) / (scale.z * 2.0); - - v[0].set(sx, 0.5, sz); - v[1].set(sx, 0.5, -sz); - v[4].set(-sx, 0.5, -sz); - v[5].set(-sx, 0.5, sz); - var oning_mesh = new THREE.Mesh(oning, new THREE.MeshLambertMaterial()); - oning_mesh.scale.set(scale.x, scale.y, scale.z); - return oning_mesh; - } - - this.createRoofGeometry = function(scale, width) { - if (!width) { - width = 2.0; - } - - var roof = new THREE.BoxGeometry( 1.0, 1.0, 1.0 ); - var v = roof.vertices; - - var sx, sz; - if (scale.x >= scale.z) { - sx = (scale.x - width) / (scale.x * 2.0); - sz = 0.0; - } else { // scale.z > scale.x - sx = 0.0; - sz = (scale.z - width) / (scale.z * 2.0); - } - - v[0].set(sx, 0.5, sz); - v[1].set(sx, 0.5, -sz); - v[4].set(-sx, 0.5, -sz); - v[5].set(-sx, 0.5, sz); - - var roof_mesh = new THREE.Mesh(roof, new THREE.MeshLambertMaterial()); - roof_mesh.scale.set(scale.x, scale.y, scale.z); - - return roof_mesh; - } - - // Scale of the space - // Width for how much space on the perimeter should the columns take up - this.createBoxwColGeometry = function(scale, width) { - if (!width) { - width = 0.25; - } - - var sx = (scale.x - width) / scale.x; - var sz = (scale.z - width) / scale.z; - - var geo = new THREE.BoxGeometry( sx, 1.0, sz ); - var v = geo.vertices; - - var r = width / 4.0; - - var colGeo1 = new THREE.CylinderGeometry(r, r, 1.0, 10.0); - colGeo1.scale(1.0/scale.x, 1.0, 1.0/scale.z); - colGeo1.translate(sx / 2.0 + r, 0.0, sz / 2.0 + r); - - var colGeo2 = new THREE.CylinderGeometry(r, r, 1.0, 10.0); - colGeo2.scale(1.0/scale.x, 1.0, 1.0/scale.z); - colGeo2.translate(sx / 2.0 + r, 0.0, -sz / 2.0 - r); - - var colGeo3 = new THREE.CylinderGeometry(r, r, 1.0, 10.0); - colGeo3.scale(1.0/scale.x, 1.0, 1.0/scale.z); - colGeo3.translate(-sx / 2.0 - r, 0.0, sz / 2.0 + r); - - var colGeo4 = new THREE.CylinderGeometry(r, r, 1.0, 10.0); - colGeo4.scale(1.0/scale.x, 1.0, 1.0/scale.z); - colGeo4.translate(-sx / 2.0 - r, 0.0, -sz / 2.0 - r); - - geo.merge(colGeo1); - geo.merge(colGeo2); - geo.merge(colGeo3); - geo.merge(colGeo4); - - var mesh = new THREE.Mesh(geo, new THREE.MeshLambertMaterial()); - mesh.scale.set(scale.x, scale.y, scale.z); - return mesh; - } - } \ No newline at end of file From a7401fad3ce859b6385f34397ec0b3a86fdf1008 Mon Sep 17 00:00:00 2001 From: eldu Date: Fri, 17 Feb 2017 22:07:13 -0500 Subject: [PATCH 14/16] Added different columns --- src/shape.js | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/shape.js b/src/shape.js index f2aa3237..2daee1f9 100644 --- a/src/shape.js +++ b/src/shape.js @@ -259,6 +259,8 @@ export default class Shape { // Scale of the space // Width for how much space on the perimeter should the columns take up createBoxwColGeometry(scale, width) { + this.name = ''; + if (!width) { width = 0.25; } @@ -294,7 +296,10 @@ export default class Shape { var mesh = new THREE.Mesh(geo, new THREE.MeshLambertMaterial()); mesh.scale.set(scale.x, scale.y, scale.z); - return mesh; + var p = this.mesh.position; + mesh.position.set(p.x, p.y, p.z); + + this.mesh = mesh; } // THIS IS WHERE ALL THE GRAMMAR IS BASICALLY @@ -334,7 +339,8 @@ export default class Shape { } else if (this.name == 'bottom') { if (r < 0.5) { // add columns - + console.log('adding some columns'); + this.createBoxwColGeometry(this.mesh.scale, this.mesh.scale.x / 4.0); } } }; From 2bfd17152ff2eb30afa88d1b1d4737d9f757f8ef Mon Sep 17 00:00:00 2001 From: eldu Date: Fri, 17 Feb 2017 22:25:11 -0500 Subject: [PATCH 15/16] submitable --- src/main.js | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/main.js b/src/main.js index 96ab63aa..f1039be2 100644 --- a/src/main.js +++ b/src/main.js @@ -33,7 +33,13 @@ function onLoad(framework) { camera.position.set(50, 100, 200); camera.lookAt(new THREE.Vector3(0,0,0)); - var axiom = [new Shape()]; + new Shape(null, ) + var axiom = [new Shape(), new Shape(), new Shape(), new Shape(), new Shape(), new Shape(), new Shape()]; + for (var i = 0; i < axiom.length; i++) { + var sc = axiom[i].mesh.scale; + axiom[i].mesh.position.set((3.0 + sc.x) * i , sc.y / 2.0, sc.z); + } + var ss = new ShapeSystem(axiom, scene); gui.add(camera, 'fov', 0, 180).onChange(function(newVal) { @@ -42,7 +48,7 @@ function onLoad(framework) { gui.add(ss, 'iterate'); - var geometry = new THREE.PlaneGeometry( 20, 20, 32 ); + var geometry = new THREE.PlaneGeometry( 250, 50, 32 ); var material = new THREE.MeshBasicMaterial( {color: 0xffff00, side: THREE.DoubleSide} ); var plane = new THREE.Mesh( geometry, material ); plane.rotateX(Math.PI / 2.0); From f5881eaeb765c864b2c70f1adbd98433b5c859da Mon Sep 17 00:00:00 2001 From: eldu Date: Fri, 17 Feb 2017 22:31:15 -0500 Subject: [PATCH 16/16] read me --- README.md | 40 ++++++++++++---------------------------- 1 file changed, 12 insertions(+), 28 deletions(-) diff --git a/README.md b/README.md index fad423fa..cb127fa3 100644 --- a/README.md +++ b/README.md @@ -8,38 +8,22 @@ For this assignment you'll be building directly off of Project 3. To make things **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! ## 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 +Shape class ## 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) +- Subdivision of buildings +- Floors +- Roofs on top floor +- Columns on bottom floor +- I have the geometry to make onings, but alas I didn't end up using it. + ## 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. +- Regular ground plane (I understand, I'm sorry) +- Made multiple buildings ## Make it interesting (10) -Experiment! Make your city a work of art. - - -## 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. +- Well, I was going to go for the forbidden city, but that didn't work out. +But I am satisfied to the point I got to despite the point allocation. -## 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. +Submitted Late. \ No newline at end of file