http://www.wikiart.org/en/rene-magritte/gonconda-1953 http://threejs.org/docs/
Last active
August 29, 2015 14:07
-
-
Save alecperkins/54e63051921ab501404d to your computer and use it in GitHub Desktop.
A proto project: https://github.com/droptype/proto
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
script. | |
// https://github.com/chandlerprall/ThreeCSG/ | |
window.ThreeBSP = (function() { | |
var ThreeBSP, | |
EPSILON = 1e-5, | |
COPLANAR = 0, | |
FRONT = 1, | |
BACK = 2, | |
SPANNING = 3; | |
ThreeBSP = function( geometry ) { | |
// Convert THREE.Geometry to ThreeBSP | |
var i, _length_i, | |
face, vertex, faceVertexUvs, uvs, | |
polygon, | |
polygons = [], | |
tree; | |
if ( geometry instanceof THREE.Geometry ) { | |
this.matrix = new THREE.Matrix4; | |
} else if ( geometry instanceof THREE.Mesh ) { | |
// #todo: add hierarchy support | |
geometry.updateMatrix(); | |
this.matrix = geometry.matrix.clone(); | |
geometry = geometry.geometry; | |
} else if ( geometry instanceof ThreeBSP.Node ) { | |
this.tree = geometry; | |
this.matrix = new THREE.Matrix4; | |
return this; | |
} else { | |
throw 'ThreeBSP: Given geometry is unsupported'; | |
} | |
for ( i = 0, _length_i = geometry.faces.length; i < _length_i; i++ ) { | |
face = geometry.faces[i]; | |
faceVertexUvs = geometry.faceVertexUvs[0][i]; | |
polygon = new ThreeBSP.Polygon; | |
if ( face instanceof THREE.Face3 ) { | |
vertex = geometry.vertices[ face.a ]; | |
uvs = faceVertexUvs ? new THREE.Vector2( faceVertexUvs[0].x, faceVertexUvs[0].y ) : null; | |
vertex = new ThreeBSP.Vertex( vertex.x, vertex.y, vertex.z, face.vertexNormals[0], uvs ); | |
vertex.applyMatrix4(this.matrix); | |
polygon.vertices.push( vertex ); | |
vertex = geometry.vertices[ face.b ]; | |
uvs = faceVertexUvs ? new THREE.Vector2( faceVertexUvs[1].x, faceVertexUvs[1].y ) : null; | |
vertex = new ThreeBSP.Vertex( vertex.x, vertex.y, vertex.z, face.vertexNormals[2], uvs ); | |
vertex.applyMatrix4(this.matrix); | |
polygon.vertices.push( vertex ); | |
vertex = geometry.vertices[ face.c ]; | |
uvs = faceVertexUvs ? new THREE.Vector2( faceVertexUvs[2].x, faceVertexUvs[2].y ) : null; | |
vertex = new ThreeBSP.Vertex( vertex.x, vertex.y, vertex.z, face.vertexNormals[2], uvs ); | |
vertex.applyMatrix4(this.matrix); | |
polygon.vertices.push( vertex ); | |
} else if ( typeof THREE.Face4 ) { | |
vertex = geometry.vertices[ face.a ]; | |
uvs = faceVertexUvs ? new THREE.Vector2( faceVertexUvs[0].x, faceVertexUvs[0].y ) : null; | |
vertex = new ThreeBSP.Vertex( vertex.x, vertex.y, vertex.z, face.vertexNormals[0], uvs ); | |
vertex.applyMatrix4(this.matrix); | |
polygon.vertices.push( vertex ); | |
vertex = geometry.vertices[ face.b ]; | |
uvs = faceVertexUvs ? new THREE.Vector2( faceVertexUvs[1].x, faceVertexUvs[1].y ) : null; | |
vertex = new ThreeBSP.Vertex( vertex.x, vertex.y, vertex.z, face.vertexNormals[1], uvs ); | |
vertex.applyMatrix4(this.matrix); | |
polygon.vertices.push( vertex ); | |
vertex = geometry.vertices[ face.c ]; | |
uvs = faceVertexUvs ? new THREE.Vector2( faceVertexUvs[2].x, faceVertexUvs[2].y ) : null; | |
vertex = new ThreeBSP.Vertex( vertex.x, vertex.y, vertex.z, face.vertexNormals[2], uvs ); | |
vertex.applyMatrix4(this.matrix); | |
polygon.vertices.push( vertex ); | |
vertex = geometry.vertices[ face.d ]; | |
uvs = faceVertexUvs ? new THREE.Vector2( faceVertexUvs[3].x, faceVertexUvs[3].y ) : null; | |
vertex = new ThreeBSP.Vertex( vertex.x, vertex.y, vertex.z, face.vertexNormals[3], uvs ); | |
vertex.applyMatrix4(this.matrix); | |
polygon.vertices.push( vertex ); | |
} else { | |
throw 'Invalid face type at index ' + i; | |
} | |
polygon.calculateProperties(); | |
polygons.push( polygon ); | |
}; | |
this.tree = new ThreeBSP.Node( polygons ); | |
}; | |
ThreeBSP.prototype.subtract = function( other_tree ) { | |
var a = this.tree.clone(), | |
b = other_tree.tree.clone(); | |
a.invert(); | |
a.clipTo( b ); | |
b.clipTo( a ); | |
b.invert(); | |
b.clipTo( a ); | |
b.invert(); | |
a.build( b.allPolygons() ); | |
a.invert(); | |
a = new ThreeBSP( a ); | |
a.matrix = this.matrix; | |
return a; | |
}; | |
ThreeBSP.prototype.union = function( other_tree ) { | |
var a = this.tree.clone(), | |
b = other_tree.tree.clone(); | |
a.clipTo( b ); | |
b.clipTo( a ); | |
b.invert(); | |
b.clipTo( a ); | |
b.invert(); | |
a.build( b.allPolygons() ); | |
a = new ThreeBSP( a ); | |
a.matrix = this.matrix; | |
return a; | |
}; | |
ThreeBSP.prototype.intersect = function( other_tree ) { | |
var a = this.tree.clone(), | |
b = other_tree.tree.clone(); | |
a.invert(); | |
b.clipTo( a ); | |
b.invert(); | |
a.clipTo( b ); | |
b.clipTo( a ); | |
a.build( b.allPolygons() ); | |
a.invert(); | |
a = new ThreeBSP( a ); | |
a.matrix = this.matrix; | |
return a; | |
}; | |
ThreeBSP.prototype.toGeometry = function() { | |
var i, j, | |
matrix = new THREE.Matrix4().getInverse( this.matrix ), | |
geometry = new THREE.Geometry(), | |
polygons = this.tree.allPolygons(), | |
polygon_count = polygons.length, | |
polygon, polygon_vertice_count, | |
vertice_dict = {}, | |
vertex_idx_a, vertex_idx_b, vertex_idx_c, | |
vertex, face, | |
verticeUvs; | |
for ( i = 0; i < polygon_count; i++ ) { | |
polygon = polygons[i]; | |
polygon_vertice_count = polygon.vertices.length; | |
for ( j = 2; j < polygon_vertice_count; j++ ) { | |
verticeUvs = []; | |
vertex = polygon.vertices[0]; | |
verticeUvs.push( new THREE.Vector2( vertex.uv.x, vertex.uv.y ) ); | |
vertex = new THREE.Vector3( vertex.x, vertex.y, vertex.z ); | |
vertex.applyMatrix4(matrix); | |
if ( typeof vertice_dict[ vertex.x + ',' + vertex.y + ',' + vertex.z ] !== 'undefined' ) { | |
vertex_idx_a = vertice_dict[ vertex.x + ',' + vertex.y + ',' + vertex.z ]; | |
} else { | |
geometry.vertices.push( vertex ); | |
vertex_idx_a = vertice_dict[ vertex.x + ',' + vertex.y + ',' + vertex.z ] = geometry.vertices.length - 1; | |
} | |
vertex = polygon.vertices[j-1]; | |
verticeUvs.push( new THREE.Vector2( vertex.uv.x, vertex.uv.y ) ); | |
vertex = new THREE.Vector3( vertex.x, vertex.y, vertex.z ); | |
vertex.applyMatrix4(matrix); | |
if ( typeof vertice_dict[ vertex.x + ',' + vertex.y + ',' + vertex.z ] !== 'undefined' ) { | |
vertex_idx_b = vertice_dict[ vertex.x + ',' + vertex.y + ',' + vertex.z ]; | |
} else { | |
geometry.vertices.push( vertex ); | |
vertex_idx_b = vertice_dict[ vertex.x + ',' + vertex.y + ',' + vertex.z ] = geometry.vertices.length - 1; | |
} | |
vertex = polygon.vertices[j]; | |
verticeUvs.push( new THREE.Vector2( vertex.uv.x, vertex.uv.y ) ); | |
vertex = new THREE.Vector3( vertex.x, vertex.y, vertex.z ); | |
vertex.applyMatrix4(matrix); | |
if ( typeof vertice_dict[ vertex.x + ',' + vertex.y + ',' + vertex.z ] !== 'undefined' ) { | |
vertex_idx_c = vertice_dict[ vertex.x + ',' + vertex.y + ',' + vertex.z ]; | |
} else { | |
geometry.vertices.push( vertex ); | |
vertex_idx_c = vertice_dict[ vertex.x + ',' + vertex.y + ',' + vertex.z ] = geometry.vertices.length - 1; | |
} | |
face = new THREE.Face3( | |
vertex_idx_a, | |
vertex_idx_b, | |
vertex_idx_c, | |
new THREE.Vector3( polygon.normal.x, polygon.normal.y, polygon.normal.z ) | |
); | |
geometry.faces.push( face ); | |
geometry.faceVertexUvs[0].push( verticeUvs ); | |
} | |
} | |
return geometry; | |
}; | |
ThreeBSP.prototype.toMesh = function( material ) { | |
var geometry = this.toGeometry(), | |
mesh = new THREE.Mesh( geometry, material ); | |
mesh.position.setFromMatrixPosition( this.matrix ); | |
mesh.rotation.setFromRotationMatrix( this.matrix ); | |
return mesh; | |
}; | |
ThreeBSP.Polygon = function( vertices, normal, w ) { | |
if ( !( vertices instanceof Array ) ) { | |
vertices = []; | |
} | |
this.vertices = vertices; | |
if ( vertices.length > 0 ) { | |
this.calculateProperties(); | |
} else { | |
this.normal = this.w = undefined; | |
} | |
}; | |
ThreeBSP.Polygon.prototype.calculateProperties = function() { | |
var a = this.vertices[0], | |
b = this.vertices[1], | |
c = this.vertices[2]; | |
this.normal = b.clone().subtract( a ).cross( | |
c.clone().subtract( a ) | |
).normalize(); | |
this.w = this.normal.clone().dot( a ); | |
return this; | |
}; | |
ThreeBSP.Polygon.prototype.clone = function() { | |
var i, vertice_count, | |
polygon = new ThreeBSP.Polygon; | |
for ( i = 0, vertice_count = this.vertices.length; i < vertice_count; i++ ) { | |
polygon.vertices.push( this.vertices[i].clone() ); | |
}; | |
polygon.calculateProperties(); | |
return polygon; | |
}; | |
ThreeBSP.Polygon.prototype.flip = function() { | |
var i, vertices = []; | |
this.normal.multiplyScalar( -1 ); | |
this.w *= -1; | |
for ( i = this.vertices.length - 1; i >= 0; i-- ) { | |
vertices.push( this.vertices[i] ); | |
}; | |
this.vertices = vertices; | |
return this; | |
}; | |
ThreeBSP.Polygon.prototype.classifyVertex = function( vertex ) { | |
var side_value = this.normal.dot( vertex ) - this.w; | |
if ( side_value < -EPSILON ) { | |
return BACK; | |
} else if ( side_value > EPSILON ) { | |
return FRONT; | |
} else { | |
return COPLANAR; | |
} | |
}; | |
ThreeBSP.Polygon.prototype.classifySide = function( polygon ) { | |
var i, vertex, classification, | |
num_positive = 0, | |
num_negative = 0, | |
vertice_count = polygon.vertices.length; | |
for ( i = 0; i < vertice_count; i++ ) { | |
vertex = polygon.vertices[i]; | |
classification = this.classifyVertex( vertex ); | |
if ( classification === FRONT ) { | |
num_positive++; | |
} else if ( classification === BACK ) { | |
num_negative++; | |
} | |
} | |
if ( num_positive > 0 && num_negative === 0 ) { | |
return FRONT; | |
} else if ( num_positive === 0 && num_negative > 0 ) { | |
return BACK; | |
} else if ( num_positive === 0 && num_negative === 0 ) { | |
return COPLANAR; | |
} else { | |
return SPANNING; | |
} | |
}; | |
ThreeBSP.Polygon.prototype.splitPolygon = function( polygon, coplanar_front, coplanar_back, front, back ) { | |
var classification = this.classifySide( polygon ); | |
if ( classification === COPLANAR ) { | |
( this.normal.dot( polygon.normal ) > 0 ? coplanar_front : coplanar_back ).push( polygon ); | |
} else if ( classification === FRONT ) { | |
front.push( polygon ); | |
} else if ( classification === BACK ) { | |
back.push( polygon ); | |
} else { | |
var vertice_count, | |
i, j, ti, tj, vi, vj, | |
t, v, | |
f = [], | |
b = []; | |
for ( i = 0, vertice_count = polygon.vertices.length; i < vertice_count; i++ ) { | |
j = (i + 1) % vertice_count; | |
vi = polygon.vertices[i]; | |
vj = polygon.vertices[j]; | |
ti = this.classifyVertex( vi ); | |
tj = this.classifyVertex( vj ); | |
if ( ti != BACK ) f.push( vi ); | |
if ( ti != FRONT ) b.push( vi ); | |
if ( (ti | tj) === SPANNING ) { | |
t = ( this.w - this.normal.dot( vi ) ) / this.normal.dot( vj.clone().subtract( vi ) ); | |
v = vi.interpolate( vj, t ); | |
f.push( v ); | |
b.push( v ); | |
} | |
} | |
if ( f.length >= 3 ) front.push( new ThreeBSP.Polygon( f ).calculateProperties() ); | |
if ( b.length >= 3 ) back.push( new ThreeBSP.Polygon( b ).calculateProperties() ); | |
} | |
}; | |
ThreeBSP.Vertex = function( x, y, z, normal, uv ) { | |
this.x = x; | |
this.y = y; | |
this.z = z; | |
this.normal = normal || new THREE.Vector3; | |
this.uv = uv || new THREE.Vector2; | |
}; | |
ThreeBSP.Vertex.prototype.clone = function() { | |
return new ThreeBSP.Vertex( this.x, this.y, this.z, this.normal.clone(), this.uv.clone() ); | |
}; | |
ThreeBSP.Vertex.prototype.add = function( vertex ) { | |
this.x += vertex.x; | |
this.y += vertex.y; | |
this.z += vertex.z; | |
return this; | |
}; | |
ThreeBSP.Vertex.prototype.subtract = function( vertex ) { | |
this.x -= vertex.x; | |
this.y -= vertex.y; | |
this.z -= vertex.z; | |
return this; | |
}; | |
ThreeBSP.Vertex.prototype.multiplyScalar = function( scalar ) { | |
this.x *= scalar; | |
this.y *= scalar; | |
this.z *= scalar; | |
return this; | |
}; | |
ThreeBSP.Vertex.prototype.cross = function( vertex ) { | |
var x = this.x, | |
y = this.y, | |
z = this.z; | |
this.x = y * vertex.z - z * vertex.y; | |
this.y = z * vertex.x - x * vertex.z; | |
this.z = x * vertex.y - y * vertex.x; | |
return this; | |
}; | |
ThreeBSP.Vertex.prototype.normalize = function() { | |
var length = Math.sqrt( this.x * this.x + this.y * this.y + this.z * this.z ); | |
this.x /= length; | |
this.y /= length; | |
this.z /= length; | |
return this; | |
}; | |
ThreeBSP.Vertex.prototype.dot = function( vertex ) { | |
return this.x * vertex.x + this.y * vertex.y + this.z * vertex.z; | |
}; | |
ThreeBSP.Vertex.prototype.lerp = function( a, t ) { | |
this.add( | |
a.clone().subtract( this ).multiplyScalar( t ) | |
); | |
this.normal.add( | |
a.normal.clone().sub( this.normal ).multiplyScalar( t ) | |
); | |
this.uv.add( | |
a.uv.clone().sub( this.uv ).multiplyScalar( t ) | |
); | |
return this; | |
}; | |
ThreeBSP.Vertex.prototype.interpolate = function( other, t ) { | |
return this.clone().lerp( other, t ); | |
}; | |
ThreeBSP.Vertex.prototype.applyMatrix4 = function ( m ) { | |
// input: THREE.Matrix4 affine matrix | |
var x = this.x, y = this.y, z = this.z; | |
var e = m.elements; | |
this.x = e[0] * x + e[4] * y + e[8] * z + e[12]; | |
this.y = e[1] * x + e[5] * y + e[9] * z + e[13]; | |
this.z = e[2] * x + e[6] * y + e[10] * z + e[14]; | |
return this; | |
} | |
ThreeBSP.Node = function( polygons ) { | |
var i, polygon_count, | |
front = [], | |
back = []; | |
this.polygons = []; | |
this.front = this.back = undefined; | |
if ( !(polygons instanceof Array) || polygons.length === 0 ) return; | |
this.divider = polygons[0].clone(); | |
for ( i = 0, polygon_count = polygons.length; i < polygon_count; i++ ) { | |
this.divider.splitPolygon( polygons[i], this.polygons, this.polygons, front, back ); | |
} | |
if ( front.length > 0 ) { | |
this.front = new ThreeBSP.Node( front ); | |
} | |
if ( back.length > 0 ) { | |
this.back = new ThreeBSP.Node( back ); | |
} | |
}; | |
ThreeBSP.Node.isConvex = function( polygons ) { | |
var i, j; | |
for ( i = 0; i < polygons.length; i++ ) { | |
for ( j = 0; j < polygons.length; j++ ) { | |
if ( i !== j && polygons[i].classifySide( polygons[j] ) !== BACK ) { | |
return false; | |
} | |
} | |
} | |
return true; | |
}; | |
ThreeBSP.Node.prototype.build = function( polygons ) { | |
var i, polygon_count, | |
front = [], | |
back = []; | |
if ( !this.divider ) { | |
this.divider = polygons[0].clone(); | |
} | |
for ( i = 0, polygon_count = polygons.length; i < polygon_count; i++ ) { | |
this.divider.splitPolygon( polygons[i], this.polygons, this.polygons, front, back ); | |
} | |
if ( front.length > 0 ) { | |
if ( !this.front ) this.front = new ThreeBSP.Node(); | |
this.front.build( front ); | |
} | |
if ( back.length > 0 ) { | |
if ( !this.back ) this.back = new ThreeBSP.Node(); | |
this.back.build( back ); | |
} | |
}; | |
ThreeBSP.Node.prototype.allPolygons = function() { | |
var polygons = this.polygons.slice(); | |
if ( this.front ) polygons = polygons.concat( this.front.allPolygons() ); | |
if ( this.back ) polygons = polygons.concat( this.back.allPolygons() ); | |
return polygons; | |
}; | |
ThreeBSP.Node.prototype.clone = function() { | |
var node = new ThreeBSP.Node(); | |
node.divider = this.divider.clone(); | |
node.polygons = this.polygons.map( function( polygon ) { return polygon.clone(); } ); | |
node.front = this.front && this.front.clone(); | |
node.back = this.back && this.back.clone(); | |
return node; | |
}; | |
ThreeBSP.Node.prototype.invert = function() { | |
var i, polygon_count, temp; | |
for ( i = 0, polygon_count = this.polygons.length; i < polygon_count; i++ ) { | |
this.polygons[i].flip(); | |
} | |
this.divider.flip(); | |
if ( this.front ) this.front.invert(); | |
if ( this.back ) this.back.invert(); | |
temp = this.front; | |
this.front = this.back; | |
this.back = temp; | |
return this; | |
}; | |
ThreeBSP.Node.prototype.clipPolygons = function( polygons ) { | |
var i, polygon_count, | |
front, back; | |
if ( !this.divider ) return polygons.slice(); | |
front = [], back = []; | |
for ( i = 0, polygon_count = polygons.length; i < polygon_count; i++ ) { | |
this.divider.splitPolygon( polygons[i], front, back, front, back ); | |
} | |
if ( this.front ) front = this.front.clipPolygons( front ); | |
if ( this.back ) back = this.back.clipPolygons( back ); | |
else back = []; | |
return front.concat( back ); | |
}; | |
ThreeBSP.Node.prototype.clipTo = function( node ) { | |
this.polygons = node.clipPolygons( this.polygons ); | |
if ( this.front ) this.front.clipTo( node ); | |
if ( this.back ) this.back.clipTo( node ); | |
}; | |
return ThreeBSP; | |
})(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
DEBUG = false | |
{ | |
Shape | |
DirectionalLight | |
AmbientLight | |
MeshLambertMaterial | |
MeshPhongMaterial | |
Mesh | |
BoxGeometry | |
mergeGeometry | |
CylinderGeometry | |
SphereGeometry | |
WebGLRenderer | |
Scene | |
PerspectiveCamera | |
} = THREE | |
scene = new Scene() | |
camera = new PerspectiveCamera( | |
70 | |
window.innerWidth / window.innerHeight | |
0.1 | |
1000 | |
) | |
if DEBUG | |
camera.position.set(400,200,400) | |
camera.lookAt(x:0,y:0,z:0) | |
else | |
camera.position.z = 600 | |
scene.add(camera) | |
renderer = new WebGLRenderer() | |
renderer.setSize(window.innerWidth, window.innerHeight) | |
renderer.setClearColor(0xD8E6F7,1) | |
document.body.appendChild(renderer.domElement) | |
origin = | |
x: window.innerWidth / 2 | |
y: window.innerHeight / 2 | |
unless DEBUG | |
renderer.domElement.addEventListener 'mousemove', (e) -> | |
# Convert the screen coordinates to world | |
rel_x = origin.x - e.pageX | |
rel_y = e.pageY - origin.y | |
# Adjust camera position | |
SCALE_FACTOR = 0.05 | |
camera.position.x = rel_x * SCALE_FACTOR | |
camera.position.y = rel_y * SCALE_FACTOR | |
requestAnimationFrame(render) | |
WINDOW_WIDTH = 40 | |
WINDOW_HEIGHT = 80 | |
WINDOW_DEPTH = 10 # Depth of window from surface of facade. | |
WINDOW_X_SPACING = 1.5 * WINDOW_WIDTH | |
WINDOW_Y_SPACING = 1 * WINDOW_WIDTH | |
WINDOW_X_MARGIN = WINDOW_WIDTH | |
WINDOW_Y_MARGIN = WINDOW_WIDTH | |
SILL_WIDTH = WINDOW_WIDTH * 1.25 | |
SILL_HEIGHT = 10 | |
SILL_DEPTH = 5 | |
generateWindow = -> | |
space = new Mesh( | |
new BoxGeometry(WINDOW_WIDTH, WINDOW_HEIGHT, WINDOW_DEPTH * 2) | |
) | |
sill = new Mesh( | |
new BoxGeometry(SILL_WIDTH, SILL_HEIGHT, SILL_DEPTH) | |
) | |
sill.position.y -= WINDOW_HEIGHT / 2 + SILL_HEIGHT / 2 | |
sill.position.z += SILL_DEPTH | |
# Custom set position to keep the window components together. | |
_setPosition = (x,y,z) -> | |
space.position.x = x | |
space.position.y = y | |
space.position.z = z | |
sill.position.x = x | |
sill.position.y = y - (WINDOW_HEIGHT / 2) | |
sill.position.z = z + SILL_DEPTH / 2 | |
return { | |
# The space is used to subtract the gap for the window from the building. | |
space: space | |
frame: null | |
sill: sill | |
setPosition: _setPosition | |
} | |
generateBuilding = (width_n=2) -> | |
num_window_rows = 3 | |
# Dimensions of the base. The width is based on the window width and spacing. | |
height = 400 | |
depth = 180 | |
width = width_n * WINDOW_WIDTH + 2 * WINDOW_X_MARGIN + (width_n - 1) * WINDOW_X_SPACING | |
roof_height = 80 | |
win_origin_x = width / 2 | |
win_origin_y = height / 2 | |
# Generate the windows for the given unit width. | |
window_bsps = [] | |
sill_bsps = [] | |
# window_meshes = [] | |
[0...width_n].forEach (col) -> | |
[0...num_window_rows].forEach (row) -> | |
_y = win_origin_y - WINDOW_Y_MARGIN - (WINDOW_HEIGHT / 2) * (row + 1) - (WINDOW_Y_SPACING + (WINDOW_HEIGHT / 2)) * row | |
_x = win_origin_x - WINDOW_X_MARGIN - (WINDOW_WIDTH / 2) * (col + 1) - (WINDOW_X_SPACING + (WINDOW_WIDTH / 2)) * col | |
_z = depth / 2 | |
_window = generateWindow() | |
_window.setPosition(_x, _y, _z) | |
# window_meshes.push(_window.) | |
window_bsps.push(new ThreeBSP(_window.space)) | |
sill_bsps.push(new ThreeBSP(_window.sill)) | |
base = new BoxGeometry(width, height, depth) | |
base_materal = new MeshLambertMaterial(color: 0xFFFFFF) | |
base_mesh = new Mesh(base) | |
base_bsp = new ThreeBSP(base_mesh) | |
window_bsps.forEach (w) -> base_bsp = base_bsp.subtract(w) | |
sill_bsps.forEach (s) -> base_bsp = base_bsp.union(s) | |
if width_n > 2 | |
chimney_mesh = new Mesh(new BoxGeometry(10, 100, 20)) | |
chimney_mesh.position.x = -1 * (width / 2) + 5 + 0.1 | |
chimney_mesh.position.y = height / 2 + 50 | |
chimney_mesh.position.z = depth / 5 | |
console.log 'chimney_mesh', chimney_mesh | |
chimney_bsp = new ThreeBSP(chimney_mesh) | |
base_bsp = base_bsp.union(chimney_bsp) | |
if Math.random() > 0.5 | |
chimney_mesh = new Mesh(new BoxGeometry(10, 100, 20)) | |
chimney_mesh.position.x = (width / 2) - 5 - 0.1 | |
chimney_mesh.position.y = height / 2 + 50 | |
chimney_mesh.position.z = depth / 5 | |
chimney_bsp = new ThreeBSP(chimney_mesh) | |
base_bsp = base_bsp.union(chimney_bsp) | |
base_mesh = base_bsp.toMesh(base_materal) | |
base_mesh.receiveShadow = true | |
roof_section = new Shape() | |
roof_section.moveTo(depth / -2, height / 2) | |
roof_section.lineTo(0, height / 2 + roof_height) | |
roof_section.lineTo(depth / 2, height / 2) | |
roof_section.lineTo(depth / -2, height / 2) | |
roof = roof_section.extrude | |
curveSegments: 1 | |
steps: 1 | |
amount: width | |
bevelEnabled: false | |
roof_material = new MeshLambertMaterial(color: 0x7C4F55) | |
roof_mesh = new Mesh(roof, roof_material) | |
roof_mesh.receiveShadow = true | |
roof_mesh.rotation.y = 0.5 * Math.PI | |
roof_mesh.position.x = width / -2 | |
base_mesh.add(roof_mesh) | |
building = | |
width: width | |
mesh: base_mesh | |
adjustPosition: (_x, _y, _z) -> | |
base_mesh.position.x += _x | |
base_mesh.position.y += _y | |
base_mesh.position.z += _z | |
addToScene: (_scene) -> | |
_scene.add(base_mesh) | |
return building | |
total_width = 0 | |
buildings = [0...6].map (i) -> | |
b = generateBuilding(Math.floor(Math.random() * 4) + 2) | |
total_width += b.width | |
return b | |
console.log 'total_width', total_width | |
previous_center = 0 | |
previous_width = 0 | |
buildings.forEach (b, i) -> | |
_direction = if i % 2 is 0 then 1 else -1 | |
console.log previous_center, previous_width / 2, b.width / 2, total_width / 2 | |
_x = previous_center + previous_width / 2 + b.width / 2 | |
_y = -300 + _direction * Math.floor(Math.random() * 25 + 20) | |
previous_width = b.width | |
previous_center = _x | |
# Apply offset after to avoid a mess with signs. | |
_x -= total_width / 2 | |
b.adjustPosition(_x, _y, 100) | |
b.addToScene(scene) | |
close_building = generateBuilding(2) | |
close_building.adjustPosition(250,0,510) | |
close_building.mesh.rotation.y -= Math.PI / 3 * 1.5 | |
close_building.addToScene(scene) | |
# Add the abducted/invading people | |
PERSON_X_SPACING = 100 | |
PERSON_Y_SPACING = 100 | |
PERSON_Z_SPACING = 200 | |
person_clothing_material = new MeshLambertMaterial(color: 0x111111) | |
person_head_material = new MeshLambertMaterial(color: 0xd3af8e) | |
# shoe_material = new MeshPhongMaterial(color: 0x000000) | |
person_torso = new CylinderGeometry(4.5, 4.5, 24, 32) | |
person_shoulders = new CylinderGeometry(1, 4.5, 2, 32) | |
person_leg = new CylinderGeometry(1.25, 1.25, 8, 32) | |
person_head = new SphereGeometry(2) | |
person_hat = new CylinderGeometry(2, 2, 0.5, 32) | |
person_hat_bowl = new SphereGeometry(2) | |
person_hat_brim = new CylinderGeometry(3, 3, 0.1, 32) | |
generatePerson = -> | |
_person = new Mesh( | |
person_torso | |
person_clothing_material | |
) | |
_person_shoulders = new Mesh(person_shoulders, person_clothing_material) | |
_person_shoulders.position.y += 12 + 1 | |
_person.add(_person_shoulders) | |
_person.scale.set(1,1,0.5) | |
_person_head = new Mesh( | |
person_head | |
person_head_material | |
) | |
_person_hat = new Mesh(person_hat, person_clothing_material) | |
_person_hat_bowl = new Mesh(person_hat_bowl, person_clothing_material) | |
_person_hat_brim = new Mesh(person_hat_brim, person_clothing_material) | |
_person_hat_bowl.position.y += 0.25 | |
_person_hat_brim.position.y -= 0.25 + 0.1 | |
_person_hat.add(_person_hat_bowl) | |
_person_hat.add(_person_hat_brim) | |
_person_hat.position.y += 1 | |
_person_head.add(_person_hat) | |
_person_head.position.y += 15 | |
_person.add(_person_head) | |
_person_leg_1 = new Mesh( | |
person_leg | |
person_clothing_material | |
) | |
_person_leg_1.position.y += -16 | |
_person_leg_1.position.x += 1.3 | |
_person.add(_person_leg_1) | |
_person_leg_2 = new Mesh( | |
person_leg | |
person_clothing_material | |
) | |
_person_leg_2.position.y += -16 | |
_person_leg_2.position.x += -1.3 | |
_person.add(_person_leg_2) | |
return _person | |
[-10..10].forEach (x) -> | |
[-10..10].forEach (y) -> | |
[0...3].forEach (z) -> | |
person = generatePerson() | |
offset = if y % 2 then 0.5 else 0 | |
person.position.set( | |
(x + offset) * PERSON_X_SPACING | |
y * PERSON_Y_SPACING | |
z * PERSON_Z_SPACING | |
) | |
_dir = if Math.random() > 0.5 then 1 else -1 | |
person.rotation.y += Math.random() * 0.2 * _dir | |
# Only have the one layer cast shadows, to avoid needing a more | |
# expensive lighting system that would correctly fade shadows. | |
person.castShadow = z is 1 | |
scene.add(person) | |
sun = new DirectionalLight(0xffffff, 1) | |
sun.position.set(-220, 150, 200) | |
sun.castShadow = true | |
scene.add(sun) | |
sky_light = new THREE.AmbientLight( 0x222222) | |
sky_light.castShadow = true | |
scene.add( sky_light ) | |
renderer.shadowMapEnabled = true | |
renderer.shadowMapSoft = true | |
renderer.shadowCameraNear = 3 | |
renderer.shadowCameraFar = camera.far | |
renderer.shadowCameraFov = 50 | |
renderer.shadowMapBias = 0.0039 | |
renderer.shadowMapDarkness = 0.5 | |
renderer.shadowMapWidth = 1024 | |
renderer.shadowMapHeight = 1024 | |
render = -> | |
renderer.render(scene, camera) | |
render() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"name": "magritte-golconda", | |
"proto_version": "1.5.1", | |
"script_libraries": [ | |
"https://cdnjs.cloudflare.com/ajax/libs/three.js/r68/three.min.js" | |
], | |
"style_libraries": [ | |
], | |
"extra_head_markup": "<meta name='viewport' content='width=device-width'>" | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
html, | |
body | |
margin: 0 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment