diff --git a/.gitignore b/.gitignore
new file mode 100644
index 00000000..3c3629e6
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+node_modules
diff --git a/.vscode/.browse.VC.db b/.vscode/.browse.VC.db
new file mode 100644
index 00000000..724e59ed
Binary files /dev/null and b/.vscode/.browse.VC.db differ
diff --git a/.vscode/.browse.VC.db-shm b/.vscode/.browse.VC.db-shm
new file mode 100644
index 00000000..f54b673c
Binary files /dev/null and b/.vscode/.browse.VC.db-shm differ
diff --git a/.vscode/.browse.VC.db-wal b/.vscode/.browse.VC.db-wal
new file mode 100644
index 00000000..51d082fb
Binary files /dev/null and b/.vscode/.browse.VC.db-wal differ
diff --git a/index.html b/index.html
new file mode 100755
index 00000000..f775186a
--- /dev/null
+++ b/index.html
@@ -0,0 +1,19 @@
+
+
+
+ HW1: Noise
+
+
+
+
+
+
\ No newline at end of file
diff --git a/package.json b/package.json
new file mode 100755
index 00000000..370fadd3
--- /dev/null
+++ b/package.json
@@ -0,0 +1,29 @@
+{
+ "scripts": {
+ "start": "webpack-dev-server --hot --inline",
+ "build": "webpack",
+ "deploy": "gh-pages-deploy"
+ },
+ "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",
+ "gh-pages-deploy": "^0.4.2",
+ "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 100755
index 00000000..9cfcd1b4
--- /dev/null
+++ b/src/framework.js
@@ -0,0 +1,75 @@
+
+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);
+ });
+
+ // 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
+}
+
+export const PI = 3.14159265
+export const e = 2.7181718
\ No newline at end of file
diff --git a/src/main.js b/src/main.js
new file mode 100755
index 00000000..006a8a90
--- /dev/null
+++ b/src/main.js
@@ -0,0 +1,421 @@
+const THREE = require('three');
+import Framework from './framework'
+
+class Agent {
+ constructor(x, y, idx, color) {
+ this.pos = new THREE.Vector3(x, y, 1);
+ this.vel = new THREE.Vector3(0, 0, 0);
+ this.size = new THREE.Vector3(0, 0, 0);
+ this.radius = 5;
+ this.markers = [];
+ this.idx = idx;
+ this.color = color;
+ }
+}
+
+class Marker {
+ constructor(x, y) {
+ this.pos = new THREE.Vector3(x, y, 1);
+
+ this.dist = Infinity;
+ this.agent = null;
+ this.color = new THREE.Color(0x000000);
+ this.idx = -1;
+ }
+}
+
+class Grid {
+ constructor(scene, width, height) {
+ this.width = width;
+ this.height = height;
+ this.markers = [];
+ this.agentClasses = {};
+
+ this.geom = new THREE.PlaneGeometry(width, height, 32);
+ this.mat = new THREE.MeshBasicMaterial({ color: 0xffffff, side: THREE.DoubleSide });
+ this.mesh = new THREE.Mesh(this.geom, this.mat);
+
+ this.scene = scene;
+
+ this.scene.add(this.mesh);
+
+ this.geomMarkers = null;
+ this.meshMarkers = null;
+ this.meshAgents = [];
+
+ this.debug = true;
+ }
+
+ generateMarkers(n) {
+ for (var i = 0; i < n; i++) {
+ var x = THREE.Math.randInt(0, this.width - 1);
+ var y = THREE.Math.randInt(0, this.height - 1);
+ var idx = x + (y * this.width);
+
+ this.markers[idx] = new Marker(x, y);
+ }
+ }
+
+ renderMarkers() {
+ var geom = new THREE.Geometry();
+
+ for (var i = 0; i < this.markers.length; i++) {
+ var marker = this.markers[i];
+
+ if (marker) {
+ var idx = geom.vertices.length;
+
+ geom.vertices.push(marker.pos);
+ geom.colors.push(marker.color);
+
+ marker.idx = idx;
+ }
+ }
+
+ var mat = new THREE.PointsMaterial({ vertexColors: THREE.VertexColors });
+ var mesh = new THREE.Points(geom, mat);
+
+ mesh.translateX(this.width / -2);
+ mesh.translateY(this.height / -2);
+
+ mesh.translateX(0.5);
+ mesh.translateY(0.5);
+
+ this.scene.add(mesh);
+
+ this.geomMarkers = geom;
+ this.meshMarkers = mesh;
+ }
+
+ generateAgentClass(id, n, goal, color) {
+ var agents = [];
+
+ for (var i = 0; i < n; i++) {
+ var x = THREE.Math.randFloat(0, this.width - 1);
+ var y = THREE.Math.randFloat(0, this.height - 1);
+ var idx = i;
+ var agent = new Agent(x, y, idx, color);
+
+ agents.push(agent);
+ }
+
+ this.agentClasses[id] = {
+ goal: goal,
+ agents: agents,
+ color: color
+ };
+ }
+
+ renderAgents() {
+ Object.keys(this.agentClasses).forEach(function(id) {
+ var agentClass = this.agentClasses[id];
+ var { goal, agents, color } = agentClass;
+ var group = new THREE.Group();
+
+ for (var i = 0; i < agents.length; i++) {
+ var agent = agents[i];
+ var mesh = this.createAgentMesh(agent, color);
+
+ agent.mesh = mesh;
+ group.add(mesh);
+ }
+
+ group.translateX(this.width / -2);
+ group.translateY(this.height / -2);
+
+ this.scene.add(group);
+
+ this.meshAgents.push(group);
+
+ this.renderGoal(goal, color);
+ }, this);
+ }
+
+ createAgentMesh(agent, color) {
+ var group = new THREE.Group();
+ var { pos, radius } = agent;
+
+ var geomA = new THREE.CylinderGeometry(1, 1, 2, 32);
+ var matA = new THREE.MeshBasicMaterial({ color: color });
+ var meshA = new THREE.Mesh(geomA, matA);
+
+ meshA.rotateX(Math.PI / 2.0);
+
+ var curve = new THREE.EllipseCurve(0, 0, radius, radius, 0, 2 * Math.PI, false, 0);
+ var path = new THREE.Path(curve.getPoints(20));
+ var geomB = path.createPointsGeometry(20);
+ var matB = new THREE.LineBasicMaterial({ color: color });
+ var meshB = new THREE.Line(geomB, matB);
+
+ group.add(meshA);
+ group.add(meshB);
+
+ group.translateX(pos.x);
+ group.translateY(pos.y);
+
+ return group;
+ }
+
+ renderGoal(goal, color) {
+ var geom = new THREE.BoxGeometry(2, 2, 1);
+ var mat = new THREE.MeshBasicMaterial({ color: color });
+ var mesh = new THREE.Mesh(geom, mat);
+
+ mesh.translateX(goal.x);
+ mesh.translateY(goal.y);
+ mesh.translateZ(goal.z);
+
+ mesh.translateX(this.width / -2);
+ mesh.translateY(this.height / -2);
+
+ this.scene.add(mesh);
+ }
+
+ update() {
+ this.clearMarkersAgents();
+ this.updateAgentsMarkers();
+ this.updateMarkersColors();
+ this.updateAgentsVelocities();
+ this.updateAgentsPositions();
+ this.updateVisibility();
+ }
+
+ updateVisibility() {
+ for (var i = 0; i < this.meshAgents.length; i++) {
+ var meshAgentsClass = this.meshAgents[i];
+
+ for (var j = 0; j < meshAgentsClass.children.length; j++) {
+ var agent = meshAgentsClass.children[j];
+ var radiusMesh = agent.children[1];
+
+ radiusMesh.visible = this.debug;
+ }
+ }
+
+ this.meshMarkers.visible = this.debug;
+ }
+
+ updateAgentsPositions() {
+ Object.keys(this.agentClasses).forEach(function(id) {
+ var agentClass = this.agentClasses[id];
+ var { goal, agents, color } = agentClass;
+
+ for (var i = 0; i < agents.length; i++) {
+ var agent = agents[i];
+ var { pos, vel, mesh } = agent;
+
+ pos.add(vel);
+
+ mesh.translateX(vel.x);
+ mesh.translateY(vel.y);
+ }
+ }, this);
+ }
+
+ updateAgentsVelocities() {
+ Object.keys(this.agentClasses).forEach(function(id) {
+ var agentClass = this.agentClasses[id];
+ var { goal, agents, color } = agentClass;
+
+ for (var i = 0; i < agents.length; i++) {
+ var agent = agents[i];
+ var { pos, markers } = agent;
+ var goalVec = goal.clone().sub(pos);
+ var wSum = 0;
+ var vSum = new THREE.Vector3(0, 0, 0);
+
+ for (var j = 0; j < markers.length; j++) {
+ var marker = markers[j];
+ var markerVec = marker.pos.clone().sub(pos);
+ var markerMag = markerVec.length();
+
+ var theta = goalVec.angleTo(markerVec);
+ var w = (1 + Math.cos(theta)) / (1 + markerMag);
+ var v = markerVec.clone().multiplyScalar(w);
+
+ wSum += w;
+ vSum.add(v);
+ }
+
+ vSum.divideScalar(wSum);
+ vSum.divideScalar(10);
+ vSum.clampLength(0.01, 1);
+ agent.vel = vSum;
+ }
+ }, this);
+ }
+
+ updateMarkersColors() {
+ for (var i = 0; i < this.markers.length; i++) {
+ var marker = this.markers[i];
+
+ if (marker) {
+ var { agent, idx } = marker;
+ var color = (agent) ? new THREE.Color(agent.color) : new THREE.Color(0x000000);
+
+ this.geomMarkers.colors[idx].set(color);
+ }
+ }
+
+ this.geomMarkers.colorsNeedUpdate = true;
+ }
+
+ updateAgentsMarkers() {
+ Object.keys(this.agentClasses).forEach(function(id) {
+ var agentClass = this.agentClasses[id];
+ var { goal, agents, color } = agentClass;
+
+ for (var i = 0; i < agents.length; i++) {
+ var agent = agents[i];
+ var { pos, radius } = agent;
+
+ agent.markers = [];
+
+ for (var dx = -5; dx <= 5; dx++) {
+ for (var dy = -5; dy <= 5; dy++) {
+
+ var x = Math.floor(agent.pos.x);
+ var y = Math.floor(agent.pos.y);
+
+ x += dx;
+ y += dy;
+
+ THREE.Math.clamp(x, 0, this.width - 1);
+ THREE.Math.clamp(y, 0, this.height - 1);
+
+ var idx = x + (y * this.width);
+ var marker = this.markers[idx];
+
+ if (!marker) continue;
+
+ var dist = pos.distanceTo(marker.pos);
+
+ if (dist < marker.dist && dist <= radius) {
+ marker.dist = dist;
+ marker.agent = agent;
+ }
+ }
+ }
+ }
+
+ for (var i = 0; i < this.markers.length; i++) {
+ var marker = this.markers[i];
+
+ if (marker) {
+
+ var agent = marker.agent;
+
+ if (agent) agent.markers.push(marker);
+ }
+ }
+ }, this);
+ }
+
+ clearMarkersAgents() {
+ for (var i = 0; i < this.markers.length; i++) {
+ var marker = this.markers[i];
+
+ if (marker) {
+ marker.dist = Infinity;
+ marker.agent = null;
+ }
+ }
+ }
+
+ clearAll() {
+ for (var i = this.scene.children.length - 1; i >= 0; i--) {
+ this.scene.remove(this.scene.children[i]);
+ }
+ }
+}
+
+function setupFourCorners(scene) {
+ var grid = new Grid(scene, 100, 100);
+
+ grid.generateMarkers(5000);
+ grid.renderMarkers();
+
+ var goal0 = new THREE.Vector3(0, 0, 1);
+ var goal1 = new THREE.Vector3(100, 100, 1);
+ var goal2 = new THREE.Vector3(0, 100, 1);
+ var goal3 = new THREE.Vector3(100, 0, 1);
+ var color0 = 0xd8548c;
+ var color1 = 0x49d5d0;
+ var color2 = 0xfe7448
+ var color3 = 0x1b91f2;
+
+ grid.generateAgentClass(0, 20, goal0, color0);
+ grid.generateAgentClass(1, 20, goal1, color1);
+ grid.generateAgentClass(2, 20, goal2, color2);
+ grid.generateAgentClass(3, 20, goal3, color3);
+ grid.renderAgents();
+
+ return grid;
+}
+
+function setupSingleCenter(scene) {
+ var grid = new Grid(scene, 100, 100);
+
+ grid.generateMarkers(5000);
+ grid.renderMarkers();
+
+ var goal0 = new THREE.Vector3(52, 52, 1);
+ var goal1 = new THREE.Vector3(48, 48, 1);
+ var color0 = 0xd8548c;
+ var color1 = 0x49d5d0;
+
+ grid.generateAgentClass(0, 20, goal0, color0);
+ grid.generateAgentClass(1, 20, goal1, color1);
+ grid.renderAgents();
+
+ return grid;
+}
+
+function onLoad(framework) {
+ var { scene, camera, renderer, gui, stats } = framework;
+
+ var options = {
+ scenario: 'Four corners',
+ debug: true
+ };
+
+ var grid = setupFourCorners(scene);
+
+ framework.grid = grid;
+
+ camera.position.set(0, 0, 100);
+ camera.lookAt(new THREE.Vector3(0,0,0));
+
+ gui.add(camera, 'fov', 0, 180).onChange(function(newVal) {
+ camera.updateProjectionMatrix();
+ });
+
+ gui.add(options, 'scenario', ['Four corners', 'Single center']).name('Scenario').onChange(function(newVal) {
+ framework.grid.clearAll();
+
+ var grid;
+
+ if (newVal === 'Four corners') {
+ grid = setupFourCorners(scene);
+ } else {
+ grid = setupSingleCenter(scene);
+ }
+
+ framework.grid = grid;
+ grid.debug = options.debug;
+ });
+
+ gui.add(options, 'debug').name('Debug').onChange(function(newVal) {
+ framework.grid.debug = newVal;
+ });
+}
+
+function onUpdate(framework) {
+ var { scene, camera, renderer, gui, stats, grid } = framework;
+
+ if (grid) {
+ grid.update();
+ }
+}
+
+Framework.init(onLoad, onUpdate);
\ No newline at end of file
diff --git a/src/shaders/part-frag.glsl b/src/shaders/part-frag.glsl
new file mode 100755
index 00000000..c8869c71
--- /dev/null
+++ b/src/shaders/part-frag.glsl
@@ -0,0 +1,9 @@
+varying vec3 vNormal;
+varying float noise;
+uniform sampler2D image;
+
+
+void main() {
+ vec3 color = vec3(0.0, 0.0, 0.0);
+ gl_FragColor = vec4( color, 1.0 );
+}
\ No newline at end of file
diff --git a/src/shaders/part-vert.glsl b/src/shaders/part-vert.glsl
new file mode 100755
index 00000000..e6f9a0c7
--- /dev/null
+++ b/src/shaders/part-vert.glsl
@@ -0,0 +1,6 @@
+varying vec3 vNormal;
+
+void main() {
+ vNormal = normal;
+ gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
+}
\ No newline at end of file
diff --git a/webpack.config.js b/webpack.config.js
new file mode 100755
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