-
Notifications
You must be signed in to change notification settings - Fork 141
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
d9a9430
commit 4391f0e
Showing
83 changed files
with
12,965 additions
and
0 deletions.
There are no files selected for viewing
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
import gl, { FBO } from "./gl.js"; | ||
import CameraOrbit from "./cameras/Orbit.js"; | ||
import GridFloor from "./primitives/GridFloor.js"; | ||
import Quad from "./primitives/Quad.js"; | ||
import Renderer from "./util/Renderer.js"; | ||
import RenderLoop from "./util/RenderLoop.js"; | ||
import VDebug from "./entities/VisualDebugger.js"; | ||
import {KBMCtrl, KBMCtrl_Viewport} from "./util/KBMCtrl.js" | ||
|
||
export default{ | ||
render :Renderer, //Main Render Function | ||
renderLoop :null, //Render loop | ||
lblFPS :null, //Html Element reference to a tag to update text of FPS | ||
|
||
mainCamera :null, //Main camera for the scene | ||
ctrlCamera :null, //Keyboard and Mouse controls for the camera | ||
|
||
debugLine :null, //Renderable used to help debug data or models | ||
debugPoint :null, //Same but with points. | ||
|
||
gridFloor :null, //Just a reference to the renderable for the grid floor. | ||
scene :[], //Array that holds the heirarchy of transforms / renderables. | ||
|
||
deltaTime :0, | ||
sinceStart :0, | ||
|
||
//Begin the GL Context | ||
init:function(){ gl.set("FungiCanvas"); return this; }, | ||
|
||
//Build all the main objects needed to get a scene up and running | ||
ready:function(renderHandler,opt=1){ | ||
this.mainCamera = new CameraOrbit().setPosition(0,0.5,2).setEulerDegrees(-15,10,0); | ||
this.ctrlCamera = new KBMCtrl().addHandler("camera",new KBMCtrl_Viewport(this.mainCamera),true,true); | ||
|
||
this.renderLoop = new RenderLoop(renderHandler); | ||
this.lblFPS = document.getElementById("lblFPS"); | ||
setInterval(function(){ this.lblFPS.innerHTML = this.renderLoop.fps; }.bind(this),200); | ||
|
||
if((opt & 1) == 1){ | ||
this.gridFloor = GridFloor(); | ||
this.scene.push(this.gridFloor); | ||
} | ||
|
||
//Setup Features | ||
if(opt){ | ||
if((opt & 2) == 2) this.scene.push( this.debugLine = new VDebug() ); //DEBUG LINE RENDERER | ||
if((opt & 4) == 4) this.scene.push( this.debugPoint = new VDebug().drawPoints() ); //DEBUG POINT RENDERER | ||
} | ||
|
||
return this; | ||
}, | ||
|
||
|
||
//Lesson 61 has example of how to do Deferred Rendering with MultiSample Render Buffers then Blits to Texture Buffers for final render | ||
setupDeferred:function(matName,onPre=null,onPost=null){ | ||
var fbo = new FBO(); //FBO Struct Builder | ||
this.deferred = { | ||
quad : Quad(-1,-1,1,1,matName,"postQuad").setOptions(true,false), | ||
fboRender : fbo.create().texColorBuffer("bColor",0).texDepthBuffer().finalize("fboRender"), | ||
onPreRender : ()=>{ FBO.clear(this.deferred.fboRender,false); }, | ||
onPostRender : ()=>{ | ||
FBO.deactivate(); | ||
this.render.prepareNext(this.deferred.quad).draw(); | ||
} | ||
}; | ||
|
||
if(onPre != null) this.render.onPreRender = onPre; | ||
if(onPost != null) this.render.onPostRender = onPost; | ||
}, | ||
|
||
|
||
//Get a frame ready to be rendered. | ||
update:function(){ | ||
this.mainCamera.update(); | ||
|
||
gl.UBOTransform.update( | ||
"matCameraView",this.mainCamera.invertedLocalMatrix, | ||
"posCamera",this.mainCamera.getWorldPosition(), //Because of Orbit, Position isn't true worldspace position, need to rotate , //this.mainCamera.position | ||
"fTime",new Float32Array( [this.sinceStart] ) | ||
); | ||
|
||
gl.clear(); | ||
return this; | ||
} | ||
} |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,168 @@ | ||
import Vec3 from "./maths/Vec3.js"; | ||
import Mat3 from "./maths/Mat3.js"; | ||
import Mat4 from "./maths/Mat4.js"; | ||
import Quat from "./maths/Quat.js"; | ||
import DualQuat from "./maths/DualQuat.js"; | ||
|
||
const DEG2RAD = Math.PI/180; | ||
const RAD2DEG = 180/Math.PI; | ||
|
||
/* | ||
https://stackoverflow.com/questions/5674149/3d-coordinates-on-a-sphere-to-latitude-and-longitude | ||
lat = acos(y / radius); | ||
long = (atan2(x,z) + PI + PI / 2) % (PI * 2) - PI; | ||
var phi = Math.acos(point.y / radius); //lat | ||
var theta = (Math.atan2(point.x, point.z) + Math.PI + Math.PI / 2) % (Math.PI * 2) - Math.PI; // lon | ||
// theta is a hack, since I want to rotate by Math.PI/2 to start. sorryyyyyyyyyyy | ||
return { | ||
lat: 180 * phi / Math.PI - 90, | ||
lon: 180 * theta / Math.PI | ||
*/ | ||
|
||
|
||
//Normalize x value to x range, then normalize to lerp the z range. | ||
function map(x, xMin,xMax, zMin,zMax){ return (x - xMin) / (xMax - xMin) * (zMax-zMin) + zMin; } | ||
|
||
function clamp(v,min,max){ return Math.max(min,Math.min(max,v)); } | ||
|
||
function smoothStep(edge1, edge2, val){ //https://en.wikipedia.org/wiki/Smoothstep | ||
var x = Math.max(0, Math.min(1, (val-edge1)/(edge2-edge1))); | ||
return x*x*(3-2*x); | ||
} | ||
|
||
//Get a number between A and B from a normalized number. | ||
function lerp(a,b,t){ return a + t * (b-a); } | ||
|
||
//From a point in space, closest spot to a 2D line | ||
function closestPointToLine2D(x0,y0,x1,y1,px,py){ | ||
var dx = x1 - x0, | ||
dy = y1 - y0, | ||
t = ((px-x0)*dx + (py-y0)*dy) / (dx*dx+dy*dy), | ||
x = x0 + (dx * t), //Util.lerp(x0, x1, t), | ||
y = y0 + (dy * t); //Util.lerp(y0, y1, t); | ||
return [x,y] | ||
} | ||
|
||
//From a point in space, closest spot to a 3D line | ||
function closestPointToLine3D(a,b,p,out){ | ||
if(out == undefined) out = new Vec3(); | ||
var dx = b.x - a.x, | ||
dy = b.y - a.y, | ||
dz = a.z - a.z, | ||
t = ((p.x-a.x)*dx + (p.y-a.y)*dy + (p.z-a.z)*dz) / (dx*dx+dy*dy+dz*dz), | ||
x = a.x + (dx * t), | ||
y = a.y + (dy * t), | ||
z = a.z + (dz * t); | ||
return out.set(x,y,z); | ||
} | ||
|
||
//Return back the two points that are closes on two infinite lines | ||
//http://geomalgorithms.com/a07-_distance.html | ||
function closestpoint_2Lines(A0,A1,B0,B1){ | ||
var u = A1.clone().sub(A0), | ||
v = B1.clone().sub(B0), | ||
w = A0.clone().sub(B0), | ||
a = Vec3.dot(u,u), // always >= 0 | ||
b = Vec3.dot(u,v), | ||
c = Vec3.dot(v,v), // always >= 0 | ||
d = Vec3.dot(u,w), | ||
e = Vec3.dot(v,w), | ||
D = a*c - b*b, // always >= 0 | ||
tU, tV; | ||
//compute the line parameters of the two closest points | ||
if(D < 0.000001){ // the lines are almost parallel | ||
tU = 0.0; | ||
tV = (b>c ? d/b : e/c); // use the largest denominator | ||
}else{ | ||
tU = (b*e - c*d) / D; | ||
tV = (a*e - b*d) / D; | ||
} | ||
|
||
//Calc Length | ||
//Vector vLen = w + (uT * u) - (vT * v); // = L1(sc) - L2(tc) | ||
//Float len = sqrt( dot(vLen,vLen) ); | ||
|
||
return [ u.scale(tU).add(A0), v.scale(tV).add(B0) ]; | ||
} | ||
|
||
//Return back the two points that are the closests but bound by the limit of two segments | ||
//http://geomalgorithms.com/a07-_distance.html | ||
function closestPointS_2Segments(A0,A1,B0,B1){ | ||
var u = A1.clone().sub(A0), | ||
v = B1.clone().sub(B0), | ||
w = A0.clone().sub(B0), | ||
a = Vec3.dot(u,u), // always >= 0 | ||
b = Vec3.dot(u,v), | ||
c = Vec3.dot(v,v), // always >= 0 | ||
d = Vec3.dot(u,w), | ||
e = Vec3.dot(v,w), | ||
D = a*c - b*b, // always >= 0 | ||
sc, sN, sD = D, // sc = sN / sD, default sD = D >= 0 | ||
tc, tN, tD = D; // tc = tN / tD, default tD = D >= 0 | ||
|
||
// compute the line parameters of the two closest points | ||
if(D < 0.000001){ // the lines are almost parallel | ||
sN = 0.0; // force using point P0 on segment S1 | ||
sD = 1.0; // to prevent possible division by 0.0 later | ||
tN = e; | ||
tD = c; | ||
}else{ // get the closest points on the infinite lines | ||
sN = (b*e - c*d); | ||
tN = (a*e - b*d); | ||
if(sN < 0.0){ // sc < 0 => the s=0 edge is visible | ||
sN = 0.0; | ||
tN = e; | ||
tD = c; | ||
}else if (sN > sD){ // sc > 1 => the s=1 edge is visible | ||
sN = sD; | ||
tN = e + b; | ||
tD = c; | ||
} | ||
} | ||
|
||
if (tN < 0.0){ // tc < 0 => the t=0 edge is visible | ||
tN = 0.0; | ||
// recompute sc for this edge | ||
if (-d < 0.0) sN = 0.0; | ||
else if (-d > a) sN = sD; | ||
else{ | ||
sN = -d; | ||
sD = a; | ||
} | ||
}else if(tN > tD){ // tc > 1 => the t=1 edge is visible | ||
tN = tD; | ||
// recompute sc for this edge | ||
if((-d + b) < 0.0) sN = 0; | ||
else if ((-d + b) > a) sN = sD; | ||
else{ | ||
sN = (-d + b); | ||
sD = a; | ||
} | ||
} | ||
|
||
// finally do the division to get sc and tc | ||
sc = (Math.abs(sN) < 0.000001 ? 0.0 : sN / sD); | ||
tc = (Math.abs(tN) < 0.000001 ? 0.0 : tN / tD); | ||
|
||
// get the difference of the two closest points | ||
//Vector dP = w + (sc * u) - (tc * v); // = S1(sc) - S2(tc) | ||
|
||
return [ u.scale(sc).add(A0), v.scale(tc).add(B0) ]; | ||
} | ||
|
||
|
||
export default { DEG2RAD:DEG2RAD, RAD2DEG:RAD2DEG, | ||
map:map, | ||
clamp:clamp, | ||
smoothStep:smoothStep, | ||
closestPointToLine2D:closestPointToLine2D, | ||
closestPointToLine3D:closestPointToLine3D, | ||
closestpoint_2Lines:closestpoint_2Lines, | ||
closestPointS_2Segments:closestPointS_2Segments, | ||
} | ||
|
||
export { Vec3, Mat3, Mat4, Quat, DualQuat, DEG2RAD, RAD2DEG } |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
import gl from "../gl.js"; | ||
import fungi from "../fungi.js"; | ||
import Transform from "../entities/Transform.js"; | ||
import {Vec3, Mat4, Quat, DEG2RAD} from "../Maths.js"; | ||
|
||
class Orbit extends Transform{ | ||
constructor(fov,near,far){ | ||
super(); | ||
//Setup the projection and invert matrices | ||
this.projectionMatrix = new Float32Array(16); | ||
this.invertedProjectionMatrix = new Float32Array(16); | ||
this.invertedLocalMatrix = new Float32Array(16); | ||
|
||
var ratio = gl.ctx.canvas.width / gl.ctx.canvas.height; | ||
Mat4.perspective(this.projectionMatrix, fov || 45, ratio, near || 0.1, far || 100.0); | ||
Mat4.invert(this.invertedProjectionMatrix, this.projectionMatrix); //Save Inverted version for Ray Casting. | ||
|
||
gl.UBOTransform.update( | ||
"matProjection",this.projectionMatrix, | ||
"screenRes", new Float32Array( [ gl.width, gl.height ] ) | ||
); //Initialize The Transform UBO. | ||
|
||
//Orbit Camera will control things based on euler, its cheating but not ready for quaternions | ||
this.euler = new Vec3(); | ||
} | ||
|
||
orthoProjection(zoom=1,near=-10,far=100){ | ||
var w = 1 * zoom, | ||
h = gl.height / gl.width * zoom; | ||
|
||
Mat4.ortho(this.projectionMatrix, -w, w, -h, h, near, far); | ||
Mat4.invert(this.invertedProjectionMatrix, this.projectionMatrix); //Save Inverted version for Ray Casting. | ||
|
||
gl.UBOTransform.update( | ||
"matProjection",this.projectionMatrix, | ||
"screenRes", new Float32Array( [ gl.width, gl.height ] ) | ||
); //Initialize The Transform UBO. | ||
|
||
return this; | ||
} | ||
|
||
//Override how this transfer creates the localMatrix : Call Update, not this function in render loop. | ||
updateMatrix(){ | ||
//Only Update the Matrix if its needed. | ||
//if(!this.position.isModified && !this.rotation.isModified && !this.euler.isModified) return this.localMatrix; | ||
|
||
Quat.setFromEuler(this.rotation,this.euler.x,this.euler.y,this.euler.z,"YXZ"); | ||
Mat4.fromQuaternion(this.localMatrix,this.rotation); | ||
this.localMatrix.resetTranslation().translate(this.position); | ||
|
||
//Set the modified indicator to false on all the transforms. | ||
this.position.isModified = false; | ||
this.rotation.isModified = false; | ||
this.euler.isModified = false; | ||
return this.localMatrix; | ||
} | ||
|
||
//Update the Matrices and UBO. | ||
update(){ | ||
if(this.position.isModified || this.scale.isModified || this.euler.isModified){ | ||
this.updateMatrix(); | ||
Mat4.invert(this.invertedLocalMatrix,this.localMatrix); | ||
} | ||
} | ||
|
||
setEulerDegrees(x,y,z){ this.euler.set(x * DEG2RAD,y * DEG2RAD,z * DEG2RAD); return this; } | ||
|
||
getWorldPosition(){ | ||
//Because of how orbit works, position isn't in worldspace. | ||
//Need to apply rotation to bring it into world splace | ||
var ary = new Float32Array(3); | ||
Quat.rotateVec3(this.rotation,this.position,ary); | ||
return ary; | ||
} | ||
|
||
worldToScreen(vAry){ | ||
var mat = new Float32Array(16), // Matrix4 Holder | ||
p = [0,0,0,0], // Vec4 | ||
rtn = []; // List of vec2 results | ||
|
||
//Move Points from WorldSpace to -> View Space (View Matrix) -> ClipSpace (ProjMatrix) | ||
Mat4.mult(mat,this.projectionMatrix,this.invertedLocalMatrix); | ||
|
||
for(var i=0; i < vAry.length; i++){ | ||
Mat4.transformVec3(p, vAry[i], mat); | ||
|
||
//Move from Clip Space to NDC Space (Normalized Device Coordinate Space) (-1 to 1 opengl viewport) | ||
if(p[3] != 0){ //only if W is not zero, | ||
p[0] = p[0] / p[3]; | ||
p[1] = p[1] / p[3]; | ||
} | ||
|
||
//Then finally move the points to Screen Space | ||
//Map points from -1 to 1 range into 0 to 1 range, Then multiple by canvas size | ||
rtn.push( // Replaced /2 with *0.5 | ||
( p[0] + 1) * 0.5 * gl.width, | ||
(-p[1] + 1) * 0.5 * gl.height | ||
); | ||
} | ||
|
||
if(vAry.length == 1) return rtn[0]; //Just return the one point | ||
return rtn; //Return all the points | ||
} | ||
} | ||
|
||
export default Orbit; |
Oops, something went wrong.