Created
March 21, 2016 04:28
-
-
Save cr1901/33cb3fd0fdbb2737b189 to your computer and use it in GitHub Desktop.
Solvespace.js Progress
This file contains hidden or 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
SolvespaceCamera = function( render_width, render_height, scale, up, right, offset ) { | |
THREE.Camera.call( this ); | |
this.type = 'SolvespaceCamera'; | |
this.render_width = render_width; | |
this.render_height = render_height; | |
this.zoom_scale = scale; /* Avoid namespace collision w/ THREE.Object.scale */ | |
this.up = up; | |
this.right = right; | |
this.offset = offset; | |
this.depth_bias = 0; | |
this.updateProjectionMatrix(); | |
}; | |
SolvespaceCamera.prototype = Object.create( THREE.Camera.prototype ); | |
SolvespaceCamera.prototype.constructor = SolvespaceCamera; | |
SolvespaceCamera.prototype.updateProjectionMatrix = function() { | |
temp = new THREE.Matrix4(); | |
offset = new THREE.Matrix4().makeTranslation(this.offset.x, this.offset.y, this.offset.z); | |
n = new THREE.Vector3().crossVectors(this.up, this.right); | |
rotate = new THREE.Matrix4().makeBasis(this.right, this.up, n); | |
/* TODO: If we want perspective, we need an additional matrix | |
here which will modify w for perspective divide. */ | |
scale = new THREE.Matrix4().makeScale(2*this.zoom_scale/this.render_width, | |
2*this.zoom_scale/this.render_height, -this.zoom_scale/30000.0); | |
/* FIXME: Where did the negative sign in the zScale come from? | |
It's not in Solvespace, but it's required here to prevent the depth buffer | |
from being reversed. Notably, THREE.js uses an Orthographic projection | |
which inverts the z-coordinate. */ | |
render_correct = new THREE.Matrix4() | |
.makeScale(1, 1, | |
1); | |
/* FIXME: This adds a (negative, thanks to scaling) bias to the | |
z coordinate to push certain layers (edges) closer to the front of the | |
screen. Biases don't match solvespace because solvespace uses Open GL | |
1.0's glDepthRange to change the offset/normalization. We do it manually | |
here. Solvespace uses a depth_bias of 2/60000 for edges. This also works | |
here, but it looks bad. */ | |
// depth_correct = new THREE.Matrix4().makeTranslation(0, 0, this.depth_bias); | |
temp.multiply( scale ); | |
temp.multiply( offset ); | |
temp.multiply( rotate ); | |
// temp.multiply( depth_correct ); | |
this.projectionMatrix.copy( temp ); | |
}; | |
SolvespaceCamera.prototype.NormalizeProjectionVectors = function() { | |
/* After rotating, up and right may no longer be orthogonal. | |
However, their cross product will produce the correct | |
rotated plane, and we can recover an orthogonal basis. */ | |
var n = new THREE.Vector3().crossVectors(this.right, this.up); | |
this.up = new THREE.Vector3().crossVectors(n, this.right); | |
this.right.normalize(); | |
this.up.normalize(); | |
}; | |
SolvespaceCamera.prototype.rotate = function(right, up) { | |
var oldRight = new THREE.Vector3().copy(this.right).normalize(); | |
var oldUp = new THREE.Vector3().copy(this.up).normalize(); | |
this.up.applyAxisAngle(oldRight, up); | |
this.right.applyAxisAngle(oldUp, right); | |
this.NormalizeProjectionVectors(); | |
console.log("this.right", this.right); | |
console.log("this.up", this.up); | |
} | |
SolvespaceControls = function(object, domElement) { | |
var _this = this; | |
this.object = object; | |
this.domElement = domElement; | |
this.screen = { left: 0, top: 0, width: 0, height: 0 }; | |
var changeEvent = { type: 'change' }; | |
var startEvent = { type: 'start' }; | |
var endEvent = { type: 'end' }; | |
var _changed; | |
var _rotatePrev = new THREE.Vector2(0, 0); | |
var _rotateCur = new THREE.Vector2(0, 0); | |
this.handleEvent = function (event) { | |
if ( typeof this[ event.type ] == 'function' ) { | |
this[ event.type ](event); | |
} | |
} | |
function mousedown( event ) { | |
event.preventDefault(); | |
event.stopPropagation(); | |
console.log(event) | |
if ( event.button === 1) { | |
_rotateCur.set(event.screenX, event.screenY); | |
_rotatePrev.copy(_rotateCur); | |
} | |
document.addEventListener( 'mousemove', mousemove, false ); | |
document.addEventListener( 'mouseup', mouseup, false ); | |
} | |
function mousemove(event) { | |
_rotateCur.set(event.screenX, event.screenY); | |
var diff = new THREE.Vector2().subVectors(_rotateCur, _rotatePrev) | |
.multiplyScalar(1/object.zoom_scale); | |
object.rotate(0.3*Math.PI/180*diff.x*object.zoom_scale, | |
0.3*Math.PI/180*diff.y*object.zoom_scale); | |
_changed = true; | |
_rotatePrev.copy(_rotateCur); | |
} | |
function mouseup(event) { | |
event.preventDefault(); | |
event.stopPropagation(); | |
document.removeEventListener( 'mousemove', mousemove ); | |
document.removeEventListener( 'mouseup', mouseup ); | |
_this.dispatchEvent( endEvent ); | |
} | |
this.update = function( ) { | |
if (_changed) { | |
_this.dispatchEvent( changeEvent ); | |
_changed = false; | |
} | |
} | |
this.domElement.addEventListener( 'mousedown', mousedown, false); | |
} | |
SolvespaceControls.prototype = Object.create( THREE.EventDispatcher.prototype ); | |
SolvespaceControls.prototype.constructor = SolvespaceControls; | |
solvespace = function(obj, params) { | |
var scene, edgeScene, camera, edgeCamera, renderer; | |
var geometry, controls, material, mesh, edges; | |
var width, height, edgeBias; | |
var directionalLightArray = []; | |
if(typeof params === "undefined" || !("width" in params)) { | |
width = window.innerWidth; | |
} else { | |
width = params.width; | |
} | |
if(typeof params === "undefined" || !("height" in params)) { | |
height = window.innerHeight; | |
} else { | |
height = params.height; | |
} | |
edgeBias = obj.bounds.edgeBias; | |
domElement = init(); | |
render(); | |
return domElement; | |
function init() { | |
scene = new THREE.Scene(); | |
edgeScene = new THREE.Scene(); | |
camera = new SolvespaceCamera(window.innerWidth, | |
window.innerHeight, 5, new THREE.Vector3(0, 1,0), | |
new THREE.Vector3(1, 0, 0), new THREE.Vector3(0, 0, 0)); | |
mesh = createMesh(obj); | |
scene.add(mesh); | |
edges = createEdges(obj); | |
edgeScene.add(edges); | |
for(var i = 0; i < obj.lights.d.length; i++) { | |
var lightColor = new THREE.Color(obj.lights.d[i].intensity, | |
obj.lights.d[i].intensity, obj.lights.d[i].intensity); | |
var directionalLight = new THREE.DirectionalLight(lightColor, 1); | |
directionalLight.position.set(obj.lights.d[i].direction[0], | |
obj.lights.d[i].direction[1], obj.lights.d[i].direction[2]); | |
directionalLightArray.push(directionalLight); | |
scene.add(directionalLight); | |
} | |
var lightColor = new THREE.Color(obj.lights.a, obj.lights.a, obj.lights.a); | |
var ambientLight = new THREE.AmbientLight(lightColor.getHex()); | |
scene.add(ambientLight); | |
renderer = new THREE.WebGLRenderer(); | |
renderer.setSize(width, height); | |
renderer.autoClear = false; | |
controls = new SolvespaceControls(camera, renderer.domElement); | |
controls.screen.width = width; | |
controls.screen.height = height; | |
controls.addEventListener("change", render); | |
controls.addEventListener("change", lightUpdate); | |
//controls.addEventListener("change", setControlsCenter); | |
animate(); | |
return renderer.domElement; | |
} | |
function animate() { | |
requestAnimationFrame(animate); | |
controls.update(); | |
} | |
function render() { | |
requestAnimationFrame( render ); | |
renderer.clear(); | |
renderer.render(scene, camera); | |
camera.depth_bias = 0.2; | |
camera.updateProjectionMatrix(); | |
renderer.render(edgeScene, camera); | |
camera.depth_bias = 0; | |
camera.updateProjectionMatrix(); | |
} | |
function lightUpdate() { | |
var changeBasis = new THREE.Matrix4(); | |
// The original light positions were in camera space. | |
// Project them into standard space using camera's basis | |
// vectors (up, target, and their cross product). | |
n = new THREE.Vector3().crossVectors(camera.up, camera.right); | |
changeBasis.makeBasis(camera.right, camera.up, n); | |
for(var i = 0; i < 2; i++) { | |
var newLightPos = changeBasis.applyToVector3Array( | |
[obj.lights.d[i].direction[0], obj.lights.d[i].direction[1], | |
obj.lights.d[i].direction[2]]); | |
directionalLightArray[i].position.set(newLightPos[0], | |
newLightPos[1], newLightPos[2]); | |
} | |
} | |
function setControlsCenter() { | |
var rect = renderer.domElement.getBoundingClientRect() | |
controls.screen.left = rect.left + document.body.scrollLeft; | |
controls.screen.top = rect.top + document.body.scrollTop; | |
} | |
function createMesh(mesh_obj) { | |
var geometry = new THREE.Geometry(); | |
var materialIndex = 0, materialList = []; | |
var opacitiesSeen = {}; | |
for(var i = 0; i < mesh_obj.points.length; i++) { | |
geometry.vertices.push(new THREE.Vector3(mesh_obj.points[i][0], | |
mesh_obj.points[i][1], mesh_obj.points[i][2])); | |
} | |
for(var i = 0; i < mesh_obj.faces.length; i++) { | |
var currOpacity = ((mesh_obj.colors[i] & 0xFF000000) >>> 24)/255.0; | |
if(opacitiesSeen[currOpacity] === undefined) { | |
opacitiesSeen[currOpacity] = materialIndex; | |
materialIndex++; | |
materialList.push(new THREE.MeshLambertMaterial( | |
{vertexColors: THREE.FaceColors, opacity: currOpacity, | |
transparent: true})); | |
} | |
geometry.faces.push(new THREE.Face3(mesh_obj.faces[i][0], | |
mesh_obj.faces[i][1], mesh_obj.faces[i][2], | |
new THREE.Vector3(mesh_obj.normals[i][0], | |
mesh_obj.normals[i][1], mesh_obj.normals[i][2]), | |
new THREE.Color(mesh_obj.colors[i] & 0x00FFFFFF), | |
opacitiesSeen[currOpacity])); | |
} | |
geometry.computeBoundingSphere(); | |
return new THREE.Mesh(geometry, new THREE.MeshFaceMaterial(materialList)); | |
} | |
function createEdges(mesh_obj) { | |
var geometry = new THREE.Geometry(); | |
var material = new THREE.LineBasicMaterial(); | |
for(var i = 0; i < mesh_obj.edges.length; i++) { | |
geometry.vertices.push(new THREE.Vector3(mesh_obj.edges[i][0][0], | |
mesh_obj.edges[i][0][1], mesh_obj.edges[i][0][2]), | |
new THREE.Vector3(mesh_obj.edges[i][1][0], | |
mesh_obj.edges[i][1][1], mesh_obj.edges[i][1][2])); | |
} | |
geometry.computeBoundingSphere(); | |
return new THREE.LineSegments(geometry, material); | |
} | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment