Forked from: uskoyama's forked: 3d under the carpet View Diff (1) forked: 3d under the carpet kenhanabishi Follow 2012-07-17 20:49:00 License: MIT License Fork2 Fav1 View3344 Play Stop Reload Fullscreen Smart Phone Fork tree Readme JavaScript 523 lines HTML 11 lines CSS 15 lines forked: 3d under the carpet // forked from uskoyama's "forked: 3d under the carpet" http://jsdo.it/uskoyama/yDLs // forked from M.Izuuchi's "forked: 3d under the carpet" http://jsdo.it/M.Izuuchi/gwTL // forked from tmake's "3d under the carpet" http://jsdo.it/tmake/1IRf DEBUG = true; var co = Math.cos; var si = Math.sin; var tau = Math.PI*2; var canvas = document.getElementById('world'); var context = canvas.getContext("2d"); canvas.height = window.innerHeight-5; canvas.width = window.innerWidth-5; var canvasCenter = new Vec2(canvas.width/2 , canvas.height/2); var log = { d: function(message){ logWrite("d", message);}, i: function(message){ logWrite("i", message);} }; log.i("Start"); log.d("Debug Mode"); log.i("Creating Camera"); log.i("Color: "+"bla"*5+" "+rgbToHTML(1,0,0)); var cam = new Camera(0,0,200, 0, -tau/15, 0); var trackball = new Trackball(cam, new Vec3(0,0,50), 180); log.i("Initializing Point Grid"); var grid = PointGrid(15, 15, 300, 300, 0, 500, 0.01); var mDown = false; var mPosDrag = new Vec2(0,0); var ctrlDown = false; var shiftDown = false; var mousePos = new Vec2(0,0); canvas.addEventListener('mousedown', function(evt){ mDown = true; mPosDrag = new Vec2(evt.pageX,evt.pageY); },false); canvas.addEventListener('mouseup', function(){ mDown = false; },false); window.addEventListener('keydown', function(evt){ log.d(evt.keyCode+" down"); switch(evt.keyCode){ case 16: shiftDown = true; break; case 17: ctrlDown = true; break; case 187: // + Key if (cam.zoom <= 10.0) cam.setZoom( cam.zoom + 0.05); document.getElementById("zoomlevel").innerText=cam.zoom; log.d("cam.zoom: "+cam.zoom); break; case 189: // - Key if (cam.zoom >= 0.1) cam.setZoom( cam.zoom - 0.05); document.getElementById("zoomlevel").innerText=cam.zoom; log.d("cam.zoom: "+cam.zoom); break; default: break; } }, false); window.addEventListener('keyup', function(evt){ log.d(evt.keyCode+" up"); switch(evt.keyCode){ case 16: shiftDown = false; break; case 17: ctrlDown = false; break; default: break; } }, false); canvas.addEventListener('mousemove', function(evt){ mousePos = getMousePos(evt); if (mDown){ //log.d("MousePos: "+mousePos.toStr()); var deltaPos = mousePos.sub(mPosDrag); mPosDrag = mousePos; if (ctrlDown){ var dVec = cam.Toc().dotVec(new Vec3(-deltaPos.x/2,0,0)); dVec.z = deltaPos.y/2; trackball.move(trackball.pos.add(dVec)); } else if( shiftDown){ trackball.scale(deltaPos.y); } else{ trackball.rotate(-deltaPos.x/100, -deltaPos.y/100); } } }, false); var stage = new Stage("stage"); stage.startRenderLoop( function(dTime){ context.clearRect ( 0 , 0 , canvas.width , canvas.height ); if(!mDown) trackball.rotate(0.01, 0); var forces = new Array(3); var curOnPlane = cam.projectCanvasPointToPlane(mousePos.sub(canvasCenter), new Vec3(0,0,1),0); //log.d("curOnPlane "+curOnPlane.toStr()); for (x = 0; x < grid.length; x++){ for (y =0; y < grid[x].length; y++){ var point = grid[x][y]; forces[0] = point.dampForce(0.3); forces[1] = point.resetForce(20); var h = hut(-point.pos.x+curOnPlane.x, -point.pos.y+curOnPlane.y, 30); //var grH = gradHut(-point.pos.x+curOnPlane.x, -point.pos.y+curOnPlane.y, 30); forces[2] = new Vec3(-100*h*2*(-point.pos.x+curOnPlane.x), -100*h*2*(-point.pos.y+curOnPlane.y), -5000*h); /*point.pos.x-curOnPlane.x, point.pos.y-curOnPlane.y, 200));*/ point.move(forces, dTime/1000); renderPointToCanvas(point); } } }); //--------------------------------------------------- function logWrite(type, message){ var log = document.getElementById('log'); if (log){ if ( type == "i" || ((type == "d") && DEBUG) ){ log.value += message+"\n"; } } } function rgbToHTML(r, g, b){ var HTMLCol = b + g*256 + r* 65536; var cStr = HTMLCol.toString(16); imax = 6-cStr.length; for (i = 1; i<=imax; i++){ cStr = "0"+cStr; } return "#"+cStr; } function speedToColor(v, vmin, vmax, Cmin,Co, Cmax) { if (v <= vmin) return Cmin; if (v >= vmax) return Cmax; if ((v > vmin) && (v <0)) return Co + (Cmin-Co)/vmin*v; if ((v < vmax) && (v >=0)) return Co + (Cmin-Co)/vmin*v; } function speedToColor2(v,vmax, Cmin,Cmax){ if ((v <-vmax) || (v > vmax)) return Cmax; else return Math.abs(Math.floor((Cmax-Cmin)/vmax*v)) + Cmin ; } //'getMousePos' Borrowed from http://www.html5canvastutorials.com/advanced/html5-canvas-mouse-coordinates/ function getMousePos(evt){ // get canvas position var obj = canvas; var top = 0; var left = 0; while (obj && obj.tagName != 'BODY') { top += obj.offsetTop; left += obj.offsetLeft; obj = obj.offsetParent; } // return relative mouse position return new Vec2(evt.clientX - left + window.pageXOffset, evt.clientY - top + window.pageYOffset); } function Stage(name){ log.i("Creating Stage"); var date = new Date(); var oldTime = date.getTime(); var renderFunc =null; var instName = name; var timeoutString = ""; this.startRenderLoop = function(renderFunction){ log.i("Setting up render-Loop"); date = new Date(); oldTime = date.getTime(); renderFunc = renderFunction; timeoutString = instName+".renderLoop()"; log.i("start rendering"); this.renderLoop(); }; this.renderLoop = function() { date = new Date(); var newTime = date.getTime(); renderFunc(newTime - oldTime); oldTime = newTime; window.setTimeout(timeoutString, 30 ); }; } /* ------ not used anymore ------ function renderPointGrid(grid){ var point = null; for (x = 0; x < grid.length; x++){ for (y =0; y < grid[x].length; y++){ point = grid[x][y]; renderPointToCanvas(point); } } }*/ function renderPointToCanvas(point){ var v_csys = cam.vecToCamSys(point.pos); if (cam.isPointInVA(v_csys)){ var p = cam.projectVec3ToVec2(v_csys); p.x *= cam.sfX; p.y *= -cam.sfY; var cvp = canvasCenter.add(p); // actual drawing-process context.beginPath(); context.arc(cvp.x, cvp.y, point.rad/v_csys.y*cam.zoom, 0, tau, false); //var r = speedToColor(point.speed.z, -500, 500, 0, 100, 250); //var g = speedToColor(point.speed.x, -500, 500, 250, 50, 250); //var b = speedToColor(point.speed.y, -500, 500, 250, 50, 250); var r = speedToColor2(point.speed.z, 1000, 31, 255); var g = speedToColor2(point.speed.x, 1000, 133, 102); var b = speedToColor2(point.speed.y, 1000, 255, 153); context.fillStyle = rgbToHTML(r,g,b);//"#9966FF"; context.fill(); } } function hut(x,y,width){ return Math.exp(-( Math.pow(x/width,2) + Math.pow(y/width,2))); } function gradHut(x,y,width){ var h = hut(x,y,width); var sqw = Math.pow(width,2); return new Vec2(-2*x/sqw*h, -2*y/sqw*h); } //-------------------Classes-------------------- function Point(x,y,z, rad, mass){ this.rad = rad; this.zeroPos = new Vec3(x,y,hut(x,y,60)*50); this.pos = new Vec3(Math.random()*700,Math.random()*700,Math.random()*700); this.speed = new Vec3(0,0,0); this.mass = Math.random()*0.04+0.01; //calculate Point-Position and Speed from Force-Array this.move = function(forces, dTime){ var resForce = new Vec3(0,0,0); for (var i=0; i< forces.length; i++){ resForce = resForce.add(forces[i]); } var accel = resForce.mul(-1/this.mass); //Time is slowed down a little bit, to lessen numerical instabilities this.speed = this.speed.add(accel.mul(dTime/10)); this.pos = this.pos.add(this.speed.mul(dTime/10)); }; this.dampForce = function(damping){ return this.speed.mul(damping); }; this.resetForce = function(strength){ return this.zeroPos.sub(this.pos).mul(-strength); }; this.getPos = function(){ return this.pos; }; this.setPos = function(newPos){ this.pos = newPos; }; } function PointGrid(numx, numy, widthX, widthY, z, pointRad, pointMass){ var grid = new Array(numx); for (ix = 0; ix < numx; ix++){ grid[ix] = new Array(numy); for (iy = 0; iy < numy; iy++){ var posx = ix/numx * widthX - widthX/2 ; var posy = iy/numy * widthY - widthY/2 ; grid[ix][iy] = new Point(posx, posy, z, pointRad, pointMass); //log.d("point: "+grid[ix][iy].zeroPos.toStr()); } } return grid; } function Trackball(camera,ballPos,ballRadius){ this.cam = camera; this.pos = ballPos; this.rad = ballRadius; this.rotate = function(alpha, beta){ this.cam.a += alpha; this.cam.b += beta; this.move(this.pos); }; this.move = function(pos){ this.pos = pos; var rVec = new Vec3(0,this.rad,0); this.cam.pos = this.pos.sub(this.cam.Toc().dotVec(rVec)); }; this.scale = function(radius){ this.rad += radius; this.move(this.pos); }; } function Camera(x,y,z, a,b,c){ this.pos = new Vec3(x,y,z); this.a = a; this.b = b; this.c = c; this.zoom = 1.0 ; this.w = 2.0; this.h = canvas.width/canvas.height* this.w; //scaleFactors of the Image-Plane to the Canvas this.sfX = canvas.width/this.w; this.sfY = canvas.height/this.h; //Points farther away from the camera won't be rendered this.farDist = 10000; this.calcClippingPlanes = function(){ this.vecA = new Vec3(-this.w/2, this.zoom, this.h/2); this.vecB = new Vec3(this.w/2, this.zoom, this.h/2); this.vecC = new Vec3(this.w/2, this.zoom, -this.h/2); this.vecD = new Vec3(-this.w/2, this.zoom, -this.h/2); //normal Vectors of Clipping-Planes this.nT = this.vecA.cross(this.vecB); this.nR = this.vecB.cross(this.vecC); this.nB = this.vecC.cross(this.vecD); this.nL = this.vecD.cross(this.vecA); }; this.calcClippingPlanes(); log.d("normalVectors: "); log.d(this.nT.x +" "+ this.nT.y +" "+ this.nT.z); log.d(this.nR.x +" "+ this.nR.y +" "+ this.nR.z); log.d(this.nB.x +" "+ this.nB.y +" "+ this.nB.z); log.d(this.nL.x +" "+ this.nL.y +" "+ this.nL.z); this.setZoom = function(zoom){ this.zoom = zoom; this.calcClippingPlanes(); }; //check if point is in visible Area this.isPointInVA = function(vec){ //using an if-clause will break evaluation of logic expression as soon as first term evals to false //log.d("nT: "+(this.nT.dot(vec) > 0)+" nR: "+(this.nR.dot(vec) >0)+" nB: "+(this.nB.dot(vec) >0)+" nL: "+(this.nL.dot(vec) >0)); if ((vec.y > this.zoom) && (vec.y < this.farDist)&& (this.nT.dot(vec) >0) && (this.nR.dot(vec) >0) && (this.nB.dot(vec) >0) && (this.nL.dot(vec) >0)) return true; else return false; }; //calculate TransformationMatrix 0-System to CameraSystem, using Euler-Angles this.Toc = function(){ var v1 = new Vec3( co(this.a)*co(this.c) - si(this.a)*co(this.b)*si(this.c) , -co(this.a)*si(this.c) - si(this.a)*co(this.b)*co(this.c) , si(this.a)*si(this.b) ); var v2 = new Vec3( si(this.a)*co(this.c) + co(this.a)*co(this.b)*si(this.c), -si(this.a)*si(this.c) + co(this.a)*co(this.b)*co(this.c), -co(this.a)*si(this.b) ); var v3 = new Vec3( si(this.b)*si(this.c), si(this.b)*co(this.c), co(this.b)); return new Mat3x3( v1, v2, v3); }; this.Tco = function(){ return this.Toc().trans(); }; //Show Vector from 0-System in Camera-System this.vecToCamSys = function(vec){ var o_v_cp = vec.sub(this.pos); return this.Tco().dotVec(o_v_cp); }; //check if point is in ViewingArea this.isInVA = function(vec3){ }; //Do Pinhole-Camera Projection for a Single Vector to Image-Plane x-z this.projectVec3ToVec2 = function(vec3) { var x2d = vec3.x/vec3.y * this.zoom; var z2d = vec3.z/vec3.y * this.zoom; return new Vec2(x2d, z2d); }; //Project a Vector from 3d-Space in 0-System to 2d-ImagePlane in Camera-System this.project = function(vec) { var v_csys = this.vecToCamSys(vec); return this.projectVec3ToVec2(v_csys); }; //Project a Point from the Image-Plane to a Line in Space; this.lineDirFromCanvasPoint = function(vec2){ return new Vec3(vec2.x/this.sfX, this.zoom, -vec2.y/this.sfY); }; this.projectCanvasPointToPlane = function(cPoint, planeNormal, pZeroDist){ //log.d("project, "+cPoint.toStr()+planeNormal.toStr()); var m = this.lineDirFromCanvasPoint(cPoint); //log.d("lineDir"+m.toStr()); var m_o = this.Toc().dotVec(m); //log.d("lineDirasdf"+m_o.toStr()); var lambda = (pZeroDist- planeNormal.dot(this.pos)) / planeNormal.dot(m_o) ; //log.d("lambda: "+lambda); var planePoint = this.pos.add(m_o.mul(lambda)); //log.d("pp "+planePoint.toStr()); return planePoint; }; } function Vec3(x,y,z){ this.x = x; this.y = y; this.z = z; //add vectors tho this this.add = function(vec3){ return new Vec3(this.x + vec3.x, this.y+vec3.y, this.z+ vec3.z); }; //reverse direction of Vector this.reverse = function(){ return new Vec3( -this.x, -this.y, -this.z); }; //subtract vector from this this.sub = function(vec3){ return new Vec3(this.x - vec3.x, this.y - vec3.y, this.z - vec3.z); }; //ordinary Scalar-Product this.dot = function(vec3){ return this.x*vec3.x + this.y*vec3.y + this.z*vec3.z; }; this.cross = function(vec3){ return new Vec3(this.y*vec3.z - this.z*vec3.y, this.z*vec3.x - this.x*vec3.z, this.x*vec3.y - this.y*vec3.x ); }; this.mul = function(scalar){ return new Vec3(this.x*scalar, this.y*scalar, this.z*scalar); }; this.toStr = function(){ return "("+this.x+", "+this.y+", "+this.z+")"; }; } function Vec2(x,y){ this.x = x; this.y = y; //add vectors tho this this.add = function(vec){ return new Vec2(this.x + vec.x, this.y+vec.y); }; this.sub = function(vec){ return new Vec2(this.x - vec.x, this.y-vec.y); }; this.toStr = function(){ return "("+this.x+", "+this.y+")"; }; } function Mat3x3(vec1,vec2,vec3){ //row vectors in the 3x3-Matrix this.vec1 = vec1; this.vec2 = vec2; this.vec3 = vec3; // Matrix-Vector-Product this.dotVec = function(vec){ return new Vec3(vec.dot(this.vec1), vec.dot(this.vec2), vec.dot(this.vec3) ); }; //Transpose Matrix this.trans = function(){ var v1 = new Vec3(this.vec1.x, this.vec2.x, this.vec3.x); var v2 = new Vec3(this.vec1.y, this.vec2.y, this.vec3.y); var v3 = new Vec3(this.vec1.z, this.vec2.z, this.vec3.z); return new Mat3x3(v1,v2,v3); }; this.toStr = function(){ return "("+this.vec1.toStr()+"\n"+this.vec2.toStr()+"\n"+this.vec3.toStr()+")"; }; } <canvas id='world'></canvas> <div id="overlay" class=overlay> <table> <tr><td class="right">Rotate :</td><td>Drag Mouse</td></tr> <tr><td class="right">Move :</td><td>[CTRL] + Drag Mouse</td></tr> <tr><td class="right">In/Out :</td><td>[SHIFT] + Drag Mouse</td></tr> <tr><td class="right">Zoom:</td><td>[+] and [-] Keys</td></tr> </table> Current Zoom-Level: <b><span id="zoomlevel">1.0</span></b> </div> <!-- <textarea id='log' rows="12" cols="50"></textarea> --> forked: 3d under the carpet body { background-color: #000000;} .overlay { position:absolute; top:10px; left:10px; width:270px; height:95px; z-index:1; padding: 5px; background: rgb(0, 0, 0); background: rgba(0, 0, 0, 0.5); color: rgb(255,255,255); border-radius: 5px; font: 12px sans-serif; } .right{ text-align: right; } // forked from uskoyama's "forked: 3d under the carpet" http://jsdo.it/uskoyama/yDLs // forked from M.Izuuchi's "forked: 3d under the carpet" http://jsdo.it/M.Izuuchi/gwTL // forked from tmake's "3d under the carpet" http://jsdo.it/tmake/1IRf DEBUG = true; var co = Math.cos; var si = Math.sin; var tau = Math.PI*2; var canvas = document.getElementById('world'); var context = canvas.getContext("2d"); canvas.height = window.innerHeight-5; canvas.width = window.innerWidth-5; var canvasCenter = new Vec2(canvas.width/2 , canvas.height/2); var log = { d: function(message){ logWrite("d", message);}, i: function(message){ logWrite("i", message);} }; log.i("Start"); log.d("Debug Mode"); log.i("Creating Camera"); log.i("Color: "+"bla"*5+" "+rgbToHTML(1,0,0)); var cam = new Camera(0,0,200, 0, -tau/15, 0); var trackball = new Trackball(cam, new Vec3(0,0,50), 180); log.i("Initializing Point Grid"); var grid = PointGrid(15, 15, 300, 300, 0, 500, 0.01); var mDown = false; var mPosDrag = new Vec2(0,0); var ctrlDown = false; var shiftDown = false; var mousePos = new Vec2(0,0); canvas.addEventListener('mousedown', function(evt){ mDown = true; mPosDrag = new Vec2(evt.pageX,evt.pageY); },false); canvas.addEventListener('mouseup', function(){ mDown = false; },false); window.addEventListener('keydown', function(evt){ log.d(evt.keyCode+" down"); switch(evt.keyCode){ case 16: shiftDown = true; break; case 17: ctrlDown = true; break; case 187: // + Key if (cam.zoom <= 10.0) cam.setZoom( cam.zoom + 0.05); document.getElementById("zoomlevel").innerText=cam.zoom; log.d("cam.zoom: "+cam.zoom); break; case 189: // - Key if (cam.zoom >= 0.1) cam.setZoom( cam.zoom - 0.05); document.getElementById("zoomlevel").innerText=cam.zoom; log.d("cam.zoom: "+cam.zoom); break; default: break; } }, false); window.addEventListener('keyup', function(evt){ log.d(evt.keyCode+" up"); switch(evt.keyCode){ case 16: shiftDown = false; break; case 17: ctrlDown = false; break; default: break; } }, false); canvas.addEventListener('mousemove', function(evt){ mousePos = getMousePos(evt); if (mDown){ //log.d("MousePos: "+mousePos.toStr()); var deltaPos = mousePos.sub(mPosDrag); mPosDrag = mousePos; if (ctrlDown){ var dVec = cam.Toc().dotVec(new Vec3(-deltaPos.x/2,0,0)); dVec.z = deltaPos.y/2; trackball.move(trackball.pos.add(dVec)); } else if( shiftDown){ trackball.scale(deltaPos.y); } else{ trackball.rotate(-deltaPos.x/100, -deltaPos.y/100); } } }, false); var stage = new Stage("stage"); stage.startRenderLoop( function(dTime){ context.clearRect ( 0 , 0 , canvas.width , canvas.height ); if(!mDown) trackball.rotate(0.01, 0); var forces = new Array(3); var curOnPlane = cam.projectCanvasPointToPlane(mousePos.sub(canvasCenter), new Vec3(0,0,1),0); //log.d("curOnPlane "+curOnPlane.toStr()); for (x = 0; x < grid.length; x++){ for (y =0; y < grid[x].length; y++){ var point = grid[x][y]; forces[0] = point.dampForce(0.3); forces[1] = point.resetForce(20); var h = hut(-point.pos.x+curOnPlane.x, -point.pos.y+curOnPlane.y, 30); //var grH = gradHut(-point.pos.x+curOnPlane.x, -point.pos.y+curOnPlane.y, 30); forces[2] = new Vec3(-100*h*2*(-point.pos.x+curOnPlane.x), -100*h*2*(-point.pos.y+curOnPlane.y), -5000*h); /*point.pos.x-curOnPlane.x, point.pos.y-curOnPlane.y, 200));*/ point.move(forces, dTime/1000); renderPointToCanvas(point); } } }); //--------------------------------------------------- function logWrite(type, message){ var log = document.getElementById('log'); if (log){ if ( type == "i" || ((type == "d") && DEBUG) ){ log.value += message+"\n"; } } } function rgbToHTML(r, g, b){ var HTMLCol = b + g*256 + r* 65536; var cStr = HTMLCol.toString(16); imax = 6-cStr.length; for (i = 1; i<=imax; i++){ cStr = "0"+cStr; } return "#"+cStr; } function speedToColor(v, vmin, vmax, Cmin,Co, Cmax) { if (v <= vmin) return Cmin; if (v >= vmax) return Cmax; if ((v > vmin) && (v <0)) return Co + (Cmin-Co)/vmin*v; if ((v < vmax) && (v >=0)) return Co + (Cmin-Co)/vmin*v; } function speedToColor2(v,vmax, Cmin,Cmax){ if ((v <-vmax) || (v > vmax)) return Cmax; else return Math.abs(Math.floor((Cmax-Cmin)/vmax*v)) + Cmin ; } //'getMousePos' Borrowed from http://www.html5canvastutorials.com/advanced/html5-canvas-mouse-coordinates/ function getMousePos(evt){ // get canvas position var obj = canvas; var top = 0; var left = 0; while (obj && obj.tagName != 'BODY') { top += obj.offsetTop; left += obj.offsetLeft; obj = obj.offsetParent; } // return relative mouse position return new Vec2(evt.clientX - left + window.pageXOffset, evt.clientY - top + window.pageYOffset); } function Stage(name){ log.i("Creating Stage"); var date = new Date(); var oldTime = date.getTime(); var renderFunc =null; var instName = name; var timeoutString = ""; this.startRenderLoop = function(renderFunction){ log.i("Setting up render-Loop"); date = new Date(); oldTime = date.getTime(); renderFunc = renderFunction; timeoutString = instName+".renderLoop()"; log.i("start rendering"); this.renderLoop(); }; this.renderLoop = function() { date = new Date(); var newTime = date.getTime(); renderFunc(newTime - oldTime); oldTime = newTime; window.setTimeout(timeoutString, 30 ); }; } /* ------ not used anymore ------ function renderPointGrid(grid){ var point = null; for (x = 0; x < grid.length; x++){ for (y =0; y < grid[x].length; y++){ point = grid[x][y]; renderPointToCanvas(point); } } }*/ function renderPointToCanvas(point){ var v_csys = cam.vecToCamSys(point.pos); if (cam.isPointInVA(v_csys)){ var p = cam.projectVec3ToVec2(v_csys); p.x *= cam.sfX; p.y *= -cam.sfY; var cvp = canvasCenter.add(p); // actual drawing-process context.beginPath(); context.arc(cvp.x, cvp.y, point.rad/v_csys.y*cam.zoom, 0, tau, false); //var r = speedToColor(point.speed.z, -500, 500, 0, 100, 250); //var g = speedToColor(point.speed.x, -500, 500, 250, 50, 250); //var b = speedToColor(point.speed.y, -500, 500, 250, 50, 250); var r = speedToColor2(point.speed.z, 1000, 31, 255); var g = speedToColor2(point.speed.x, 1000, 133, 102); var b = speedToColor2(point.speed.y, 1000, 255, 153); context.fillStyle = rgbToHTML(r,g,b);//"#9966FF"; context.fill(); } } function hut(x,y,width){ return Math.exp(-( Math.pow(x/width,2) + Math.pow(y/width,2))); } function gradHut(x,y,width){ var h = hut(x,y,width); var sqw = Math.pow(width,2); return new Vec2(-2*x/sqw*h, -2*y/sqw*h); } //-------------------Classes-------------------- function Point(x,y,z, rad, mass){ this.rad = rad; this.zeroPos = new Vec3(x,y,hut(x,y,60)*50); this.pos = new Vec3(Math.random()*700,Math.random()*700,Math.random()*700); this.speed = new Vec3(0,0,0); this.mass = Math.random()*0.04+0.01; //calculate Point-Position and Speed from Force-Array this.move = function(forces, dTime){ var resForce = new Vec3(0,0,0); for (var i=0; i< forces.length; i++){ resForce = resForce.add(forces[i]); } var accel = resForce.mul(-1/this.mass); //Time is slowed down a little bit, to lessen numerical instabilities this.speed = this.speed.add(accel.mul(dTime/10)); this.pos = this.pos.add(this.speed.mul(dTime/10)); }; this.dampForce = function(damping){ return this.speed.mul(damping); }; this.resetForce = function(strength){ return this.zeroPos.sub(this.pos).mul(-strength); }; this.getPos = function(){ return this.pos; }; this.setPos = function(newPos){ this.pos = newPos; }; } function PointGrid(numx, numy, widthX, widthY, z, pointRad, pointMass){ var grid = new Array(numx); for (ix = 0; ix < numx; ix++){ grid[ix] = new Array(numy); for (iy = 0; iy < numy; iy++){ var posx = ix/numx * widthX - widthX/2 ; var posy = iy/numy * widthY - widthY/2 ; grid[ix][iy] = new Point(posx, posy, z, pointRad, pointMass); //log.d("point: "+grid[ix][iy].zeroPos.toStr()); } } return grid; } function Trackball(camera,ballPos,ballRadius){ this.cam = camera; this.pos = ballPos; this.rad = ballRadius; this.rotate = function(alpha, beta){ this.cam.a += alpha; this.cam.b += beta; this.move(this.pos); }; this.move = function(pos){ this.pos = pos; var rVec = new Vec3(0,this.rad,0); this.cam.pos = this.pos.sub(this.cam.Toc().dotVec(rVec)); }; this.scale = function(radius){ this.rad += radius; this.move(this.pos); }; } function Camera(x,y,z, a,b,c){ this.pos = new Vec3(x,y,z); this.a = a; this.b = b; this.c = c; this.zoom = 1.0 ; this.w = 2.0; this.h = canvas.width/canvas.height* this.w; //scaleFactors of the Image-Plane to the Canvas this.sfX = canvas.width/this.w; this.sfY = canvas.height/this.h; //Points farther away from the camera won't be rendered this.farDist = 10000; this.calcClippingPlanes = function(){ this.vecA = new Vec3(-this.w/2, this.zoom, this.h/2); this.vecB = new Vec3(this.w/2, this.zoom, this.h/2); this.vecC = new Vec3(this.w/2, this.zoom, -this.h/2); this.vecD = new Vec3(-this.w/2, this.zoom, -this.h/2); //normal Vectors of Clipping-Planes this.nT = this.vecA.cross(this.vecB); this.nR = this.vecB.cross(this.vecC); this.nB = this.vecC.cross(this.vecD); this.nL = this.vecD.cross(this.vecA); }; this.calcClippingPlanes(); log.d("normalVectors: "); log.d(this.nT.x +" "+ this.nT.y +" "+ this.nT.z); log.d(this.nR.x +" "+ this.nR.y +" "+ this.nR.z); log.d(this.nB.x +" "+ this.nB.y +" "+ this.nB.z); log.d(this.nL.x +" "+ this.nL.y +" "+ this.nL.z); this.setZoom = function(zoom){ this.zoom = zoom; this.calcClippingPlanes(); }; //check if point is in visible Area this.isPointInVA = function(vec){ //using an if-clause will break evaluation of logic expression as soon as first term evals to false //log.d("nT: "+(this.nT.dot(vec) > 0)+" nR: "+(this.nR.dot(vec) >0)+" nB: "+(this.nB.dot(vec) >0)+" nL: "+(this.nL.dot(vec) >0)); if ((vec.y > this.zoom) && (vec.y < this.farDist)&& (this.nT.dot(vec) >0) && (this.nR.dot(vec) >0) && (this.nB.dot(vec) >0) && (this.nL.dot(vec) >0)) return true; else return false; }; //calculate TransformationMatrix 0-System to CameraSystem, using Euler-Angles this.Toc = function(){ var v1 = new Vec3( co(this.a)*co(this.c) - si(this.a)*co(this.b)*si(this.c) , -co(this.a)*si(this.c) - si(this.a)*co(this.b)*co(this.c) , si(this.a)*si(this.b) ); var v2 = new Vec3( si(this.a)*co(this.c) + co(this.a)*co(this.b)*si(this.c), -si(this.a)*si(this.c) + co(this.a)*co(this.b)*co(this.c), -co(this.a)*si(this.b) ); var v3 = new Vec3( si(this.b)*si(this.c), si(this.b)*co(this.c), co(this.b)); return new Mat3x3( v1, v2, v3); }; this.Tco = function(){ return this.Toc().trans(); }; //Show Vector from 0-System in Camera-System this.vecToCamSys = function(vec){ var o_v_cp = vec.sub(this.pos); return this.Tco().dotVec(o_v_cp); }; //check if point is in ViewingArea this.isInVA = function(vec3){ }; //Do Pinhole-Camera Projection for a Single Vector to Image-Plane x-z this.projectVec3ToVec2 = function(vec3) { var x2d = vec3.x/vec3.y * this.zoom; var z2d = vec3.z/vec3.y * this.zoom; return new Vec2(x2d, z2d); }; //Project a Vector from 3d-Space in 0-System to 2d-ImagePlane in Camera-System this.project = function(vec) { var v_csys = this.vecToCamSys(vec); return this.projectVec3ToVec2(v_csys); }; //Project a Point from the Image-Plane to a Line in Space; this.lineDirFromCanvasPoint = function(vec2){ return new Vec3(vec2.x/this.sfX, this.zoom, -vec2.y/this.sfY); }; this.projectCanvasPointToPlane = function(cPoint, planeNormal, pZeroDist){ //log.d("project, "+cPoint.toStr()+planeNormal.toStr()); var m = this.lineDirFromCanvasPoint(cPoint); //log.d("lineDir"+m.toStr()); var m_o = this.Toc().dotVec(m); //log.d("lineDirasdf"+m_o.toStr()); var lambda = (pZeroDist- planeNormal.dot(this.pos)) / planeNormal.dot(m_o) ; //log.d("lambda: "+lambda); var planePoint = this.pos.add(m_o.mul(lambda)); //log.d("pp "+planePoint.toStr()); return planePoint; }; } function Vec3(x,y,z){ this.x = x; this.y = y; this.z = z; //add vectors tho this this.add = function(vec3){ return new Vec3(this.x + vec3.x, this.y+vec3.y, this.z+ vec3.z); }; //reverse direction of Vector this.reverse = function(){ return new Vec3( -this.x, -this.y, -this.z); }; //subtract vector from this this.sub = function(vec3){ return new Vec3(this.x - vec3.x, this.y - vec3.y, this.z - vec3.z); }; //ordinary Scalar-Product this.dot = function(vec3){ return this.x*vec3.x + this.y*vec3.y + this.z*vec3.z; }; this.cross = function(vec3){ return new Vec3(this.y*vec3.z - this.z*vec3.y, this.z*vec3.x - this.x*vec3.z, this.x*vec3.y - this.y*vec3.x ); }; this.mul = function(scalar){ return new Vec3(this.x*scalar, this.y*scalar, this.z*scalar); }; this.toStr = function(){ return "("+this.x+", "+this.y+", "+this.z+")"; }; } function Vec2(x,y){ this.x = x; this.y = y; //add vectors tho this this.add = function(vec){ return new Vec2(this.x + vec.x, this.y+vec.y); }; this.sub = function(vec){ return new Vec2(this.x - vec.x, this.y-vec.y); }; this.toStr = function(){ return "("+this.x+", "+this.y+")"; }; } function Mat3x3(vec1,vec2,vec3){ //row vectors in the 3x3-Matrix this.vec1 = vec1; this.vec2 = vec2; this.vec3 = vec3; // Matrix-Vector-Product this.dotVec = function(vec){ return new Vec3(vec.dot(this.vec1), vec.dot(this.vec2), vec.dot(this.vec3) ); }; //Transpose Matrix this.trans = function(){ var v1 = new Vec3(this.vec1.x, this.vec2.x, this.vec3.x); var v2 = new Vec3(this.vec1.y, this.vec2.y, this.vec3.y); var v3 = new Vec3(this.vec1.z, this.vec2.z, this.vec3.z); return new Mat3x3(v1,v2,v3); }; this.toStr = function(){ return "("+this.vec1.toStr()+"\n"+this.vec2.toStr()+"\n"+this.vec3.toStr()+")"; }; } <canvas id='world'></canvas> <div id="overlay" class=overlay> <table> <tr><td class="right">Rotate :</td><td>Drag Mouse</td></tr> <tr><td class="right">Move :</td><td>[CTRL] + Drag Mouse</td></tr> <tr><td class="right">In/Out :</td><td>[SHIFT] + Drag Mouse</td></tr> <tr><td class="right">Zoom:</td><td>[+] and [-] Keys</td></tr> </table> Current Zoom-Level: <b><span id="zoomlevel">1.0</span></b> </div> <!-- <textarea id='log' rows="12" cols="50"></textarea> --> body { background-color: #000000;} .overlay { position:absolute; top:10px; left:10px; width:270px; height:95px; z-index:1; padding: 5px; background: rgb(0, 0, 0); background: rgba(0, 0, 0, 0.5); color: rgb(255,255,255); border-radius: 5px; font: 12px sans-serif; } .right{ text-align: right; } use an iframe compat browser, deer Play on jsdo.it games Author Share ブログに埋め込む QR Tag Download Complete! Description What kind of game? Control Device Smartphone Controllerjsdo.it WebSocket Controller» Mouse Keyboard Touch Device Fullscreen Activated Inactivated jsdo.it games から削除する Submit Author kenhanabishi Tweet Default Panel Auto play Screenshot Readme JavaScript HTML CSS Size Width: px Height: px code <script type="text/javascript" src="http://jsdo.it/blogparts/v3BX/js"></script> 3d 3d 3d-engine 3d-engine application art&design camera camera canvas canvas game html5 html5 html5_elements&api particles particles physics physics trackballl trackballl Discussion Questions on this code? Tags 3d 3d-engine application art&design camera canvas game html5 html5_elements&api particles physics trackballl Favorite by Maran.Emil Forked sort by latest page views favorite forked forked: 3d under the carpet susi917 16 5164 524/11/15 3d 3d-engine animation application art&design camera canvas game html5 html5_elements&api javascript particles physics trackballl アニメーション forked: 3d under the carpet sayuri.ito17 20 2956 524/11/15 3d 3d-engine application art&design camera canvas game html5 html5_elements&api particles physics trackballl