-
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
59e4380
commit 501efe9
Showing
15 changed files
with
2,210 additions
and
23 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,144 @@ | ||
class Camera{ | ||
constructor(gl,fov,near,far){ | ||
//Setup the perspective matrix | ||
this.projectionMatrix = new Float32Array(16); | ||
var ratio = gl.canvas.width / gl.canvas.height; | ||
Matrix4.perspective(this.projectionMatrix, fov || 45, ratio, near || 0.1, far || 100.0); | ||
|
||
this.transform = new Transform(); //Setup transform to control the position of the camera | ||
this.viewMatrix = new Float32Array(16); //Cache the matrix that will hold the inverse of the transform. | ||
|
||
this.mode = Camera.MODE_ORBIT; //Set what sort of control mode to use. | ||
} | ||
|
||
panX(v){ | ||
if(this.mode == Camera.MODE_ORBIT) return; // Panning on the X Axis is only allowed when in free mode | ||
this.updateViewMatrix(); | ||
this.transform.position.x += this.transform.right[0] * v; | ||
this.transform.position.y += this.transform.right[1] * v; | ||
this.transform.position.z += this.transform.right[2] * v; | ||
} | ||
|
||
panY(v){ | ||
this.updateViewMatrix(); | ||
this.transform.position.y += this.transform.up[1] * v; | ||
if(this.mode == Camera.MODE_ORBIT) return; //Can only move up and down the y axix in orbit mode | ||
this.transform.position.x += this.transform.up[0] * v; | ||
this.transform.position.z += this.transform.up[2] * v; | ||
} | ||
|
||
panZ(v){ | ||
this.updateViewMatrix(); | ||
if(this.mode == Camera.MODE_ORBIT){ | ||
this.transform.position.z += v; //orbit mode does translate after rotate, so only need to set Z, the rotate will handle the rest. | ||
}else{ | ||
//in freemode to move forward, we need to move based on our forward which is relative to our current rotation | ||
this.transform.position.x += this.transform.forward[0] * v; | ||
this.transform.position.y += this.transform.forward[1] * v; | ||
this.transform.position.z += this.transform.forward[2] * v; | ||
} | ||
} | ||
|
||
//To have different modes of movements, this function handles the view matrix update for the transform object. | ||
updateViewMatrix(){ | ||
//Optimize camera transform update, no need for scale nor rotateZ | ||
if(this.mode == Camera.MODE_FREE){ | ||
this.transform.matView.reset() | ||
.vtranslate(this.transform.position) | ||
.rotateX(this.transform.rotation.x * Transform.deg2Rad) | ||
.rotateY(this.transform.rotation.y * Transform.deg2Rad); | ||
|
||
}else{ | ||
this.transform.matView.reset() | ||
.rotateX(this.transform.rotation.x * Transform.deg2Rad) | ||
.rotateY(this.transform.rotation.y * Transform.deg2Rad) | ||
.vtranslate(this.transform.position); | ||
|
||
} | ||
|
||
this.transform.updateDirection(); | ||
|
||
//Cameras work by doing the inverse transformation on all meshes, the camera itself is a lie :) | ||
Matrix4.invert(this.viewMatrix,this.transform.matView.raw); | ||
return this.viewMatrix; | ||
} | ||
|
||
getTranslatelessMatrix(){ | ||
var mat = new Float32Array(this.viewMatrix); | ||
mat[12] = mat[13] = mat[14] = 0.0; //Reset Translation position in the Matrix to zero. | ||
return mat; | ||
} | ||
} | ||
|
||
Camera.MODE_FREE = 0; //Allows free movement of position and rotation, basicly first person type of camera | ||
Camera.MODE_ORBIT = 1; //Movement is locked to rotate around the origin, Great for 3d editors or a single model viewer | ||
|
||
|
||
class CameraController{ | ||
constructor(gl,camera){ | ||
var oThis = this; | ||
var box = gl.canvas.getBoundingClientRect(); | ||
this.canvas = gl.canvas; //Need access to the canvas html element, main to access events | ||
this.camera = camera; //Reference to the camera to control | ||
|
||
this.rotateRate = -300; //How fast to rotate, degrees per dragging delta | ||
this.panRate = 5; //How fast to pan, max unit per dragging delta | ||
this.zoomRate = 200; //How fast to zoom or can be viewed as forward/backward movement | ||
|
||
this.offsetX = box.left; //Help calc global x,y mouse cords. | ||
this.offsetY = box.top; | ||
|
||
this.initX = 0; //Starting X,Y position on mouse down | ||
this.initY = 0; | ||
this.prevX = 0; //Previous X,Y position on mouse move | ||
this.prevY = 0; | ||
|
||
this.onUpHandler = function(e){ oThis.onMouseUp(e); }; //Cache func reference that gets bound and unbound a lot | ||
this.onMoveHandler = function(e){ oThis.onMouseMove(e); } | ||
|
||
this.canvas.addEventListener("mousedown",function(e){ oThis.onMouseDown(e); }); //Initializes the up and move events | ||
this.canvas.addEventListener("mousewheel", function(e){ oThis.onMouseWheel(e); }); //Handles zoom/forward movement | ||
} | ||
|
||
//Transform mouse x,y cords to something useable by the canvas. | ||
getMouseVec2(e){ return {x:e.pageX - this.offsetX, y:e.pageY - this.offsetY}; } | ||
|
||
//Begin listening for dragging movement | ||
onMouseDown(e){ | ||
this.initX = this.prevX = e.pageX - this.offsetX; | ||
this.initY = this.prevY = e.pageY - this.offsetY; | ||
|
||
this.canvas.addEventListener("mouseup",this.onUpHandler); | ||
this.canvas.addEventListener("mousemove",this.onMoveHandler); | ||
} | ||
|
||
//End listening for dragging movement | ||
onMouseUp(e){ | ||
this.canvas.removeEventListener("mouseup",this.onUpHandler); | ||
this.canvas.removeEventListener("mousemove",this.onMoveHandler); | ||
} | ||
|
||
onMouseWheel(e){ | ||
var delta = Math.max(-1, Math.min(1, (e.wheelDelta || -e.detail))); //Try to map wheel movement to a number between -1 and 1 | ||
this.camera.panZ(delta * (this.zoomRate / this.canvas.height)); //Keep the movement speed the same, no matter the height diff | ||
} | ||
|
||
onMouseMove(e){ | ||
var x = e.pageX - this.offsetX, //Get X,y where the canvas's position is origin. | ||
y = e.pageY - this.offsetY, | ||
dx = x - this.prevX, //Difference since last mouse move | ||
dy = y - this.prevY; | ||
|
||
//When shift is being helt down, we pan around else we rotate. | ||
if(!e.shiftKey){ | ||
this.camera.transform.rotation.y += dx * (this.rotateRate / this.canvas.width); | ||
this.camera.transform.rotation.x += dy * (this.rotateRate / this.canvas.height); | ||
}else{ | ||
this.camera.panX( -dx * (this.panRate / this.canvas.width) ); | ||
this.camera.panY( dy * (this.panRate / this.canvas.height) ); | ||
} | ||
|
||
this.prevX = x; | ||
this.prevY = y; | ||
} | ||
} |
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,249 @@ | ||
class LineDebugger{ | ||
constructor(gl){ | ||
this.transform = new Transform(); | ||
|
||
this.gl = gl; | ||
this.mColor = []; | ||
this.mVerts = []; | ||
this.mVertBuffer = 0; | ||
this.mVertCount = 0; | ||
this.mVertexComponentLen = 4; | ||
} | ||
|
||
addColor(){ | ||
if(arguments.length == 0) return this; | ||
|
||
for(var i=0,c,p; i < arguments.length; i++){ | ||
if(arguments[i].length < 6) continue; | ||
c = arguments[i]; //Just an alias(copy really) of the color text, make code smaller. | ||
p = (c[0] == "#")?1:0; //Determine starting position in char array to start pulling from | ||
|
||
this.mColor.push( | ||
parseInt(c[p] +c[p+1],16) / 255.0, | ||
parseInt(c[p+2] +c[p+3],16) / 255.0, | ||
parseInt(c[p+4] +c[p+5],16) / 255.0 | ||
); | ||
} | ||
return this; | ||
} | ||
|
||
addLine(x1,y1,z1,x2,y2,z2,cIndex){ | ||
this.mVerts.push(x1,y1,z1,cIndex,x2,y2,z2,cIndex); | ||
this.mVertCount = this.mVerts.length / this.mVertexComponentLen; | ||
return this; | ||
} | ||
|
||
addMeshNormal(cIndex,nLen,mesh){ | ||
if(mesh.aVert === undefined || mesh.aNorm === undefined) return this; | ||
|
||
var len = mesh.aVert.length,n=0; | ||
for(var i=0; i < len; i+=mesh.vertexComponentLen){ | ||
this.mVerts.push( | ||
mesh.aVert[i], | ||
mesh.aVert[i+1], | ||
mesh.aVert[i+2], | ||
cIndex, | ||
mesh.aVert[i] + mesh.aNorm[n] * nLen, | ||
mesh.aVert[i+1] + mesh.aNorm[n+1] * nLen, | ||
mesh.aVert[i+2] + mesh.aNorm[n+2] * nLen, | ||
cIndex | ||
); | ||
n+=3; | ||
} | ||
|
||
this.mVertCount = this.mVerts.length / this.mVertexComponentLen; | ||
return this; | ||
} | ||
|
||
createShader(){ | ||
var vShader = '#version 300 es\n'+ | ||
'layout(location=0) in vec4 a_position;'+ | ||
'uniform mat4 uPMatrix;'+ | ||
'uniform mat4 uCameraMatrix;'+ | ||
'uniform mat4 uMVMatrix;'+ | ||
'uniform vec3 uColorAry[6];'+ | ||
'out lowp vec4 color;'+ | ||
'void main(void){'+ | ||
'color = vec4(uColorAry[ int(a_position.w) ],1.0);'+ | ||
'gl_Position = uPMatrix * uCameraMatrix * uMVMatrix * vec4(a_position.xyz, 1.0);'+ | ||
'}'; | ||
|
||
var fShader = '#version 300 es\n'+ | ||
'precision mediump float;'+ | ||
'in vec4 color;'+ | ||
'out vec4 finalColor;'+ | ||
'void main(void){ finalColor = color; }'; | ||
|
||
//........................................ | ||
this.mShader = ShaderUtil.createProgramFromText(this.gl,vShader,fShader,true); | ||
this.mUniformColor = this.gl.getUniformLocation(this.mShader,"uColorAry"); | ||
this.mUniformProj = this.gl.getUniformLocation(this.mShader,"uPMatrix"); | ||
this.mUniformCamera = this.gl.getUniformLocation(this.mShader,"uCameraMatrix"); | ||
this.mUniformModelV = this.gl.getUniformLocation(this.mShader,"uMVMatrix"); | ||
|
||
//........................................ | ||
//Save colors in the shader. Should only need to render once. | ||
this.gl.useProgram(this.mShader); | ||
this.gl.uniform3fv(this.mUniformColor, new Float32Array( this.mColor )); | ||
this.gl.useProgram(null); | ||
} | ||
|
||
finalize(){ | ||
this.mVertBuffer = this.gl.fCreateArrayBuffer(new Float32Array(this.mVerts),true); | ||
this.createShader(); | ||
return this; | ||
} | ||
|
||
render(camera){ | ||
//Update Transform Matrix (Modal View) | ||
this.transform.updateMatrix(); | ||
|
||
//Start up the Shader | ||
this.gl.useProgram(this.mShader); | ||
|
||
//Push Uniform Data | ||
this.gl.uniformMatrix4fv(this.mUniformProj, false, camera.projectionMatrix); | ||
this.gl.uniformMatrix4fv(this.mUniformCamera, false, camera.viewMatrix); | ||
this.gl.uniformMatrix4fv(this.mUniformModelV, false, this.transform.getViewMatrix()); | ||
|
||
//Activate Vertice Buffer Array | ||
this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.mVertBuffer); | ||
this.gl.enableVertexAttribArray(0); | ||
this.gl.vertexAttribPointer(0,this.mVertexComponentLen,this.gl.FLOAT,false,0,0); | ||
|
||
//Draw | ||
this.gl.drawArrays(this.gl.LINES,0,this.mVertCount); | ||
|
||
//Cleanup | ||
this.gl.disableVertexAttribArray(0); | ||
this.gl.useProgram(null); | ||
this.gl.bindBuffer(this.gl.ARRAY_BUFFER, null); | ||
} | ||
} | ||
|
||
|
||
class VertexDebugger{ | ||
constructor(gl,pntSize){ | ||
this.transform = new Transform(); | ||
this.gl = gl; | ||
this.mColor = []; | ||
this.mVerts = []; | ||
this.mVertBuffer = 0; | ||
this.mVertCount = 0; | ||
this.mVertexComponentLen = 4; | ||
this.mPointSize = pntSize; | ||
} | ||
|
||
addColor(){ | ||
if(arguments.length == 0) return this; | ||
|
||
for(var i=0,c,p; i < arguments.length; i++){ | ||
if(arguments[i].length < 6) continue; | ||
c = arguments[i]; //Just an alias(copy really) of the color text, make code smaller. | ||
p = (c[0] == "#")?1:0; //Determine starting position in char array to start pulling from | ||
|
||
this.mColor.push( | ||
parseInt(c[p] +c[p+1],16) / 255.0, | ||
parseInt(c[p+2] +c[p+3],16) / 255.0, | ||
parseInt(c[p+4] +c[p+5],16) / 255.0 | ||
); | ||
} | ||
return this; | ||
} | ||
|
||
addPoint(x1,y1,z1,cIndex){ | ||
this.mVerts.push(x1,y1,z1,cIndex || 0); | ||
this.mVertCount = this.mVerts.length / this.mVertexComponentLen; | ||
return this; | ||
} | ||
|
||
addMeshPoints(cIndex,mesh){ | ||
if(mesh.aVert === undefined) return this; | ||
|
||
var len = mesh.aVert.length; | ||
for(var i=0; i < len; i+=3){ | ||
this.mVerts.push( | ||
mesh.aVert[i], | ||
mesh.aVert[i+1], | ||
mesh.aVert[i+2], | ||
cIndex | ||
); | ||
} | ||
|
||
this.mVertCount = this.mVerts.length / this.mVertexComponentLen; | ||
return this; | ||
} | ||
|
||
createShader(){ | ||
var vShader = '#version 300 es\n'+ | ||
'layout(location=0) in vec4 a_position;'+ | ||
'uniform mat4 uPMatrix;'+ | ||
'uniform mat4 uCameraMatrix;'+ | ||
'uniform mat4 uMVMatrix;'+ | ||
'uniform vec3 uColorAry[6];'+ | ||
'uniform vec3 uCameraPos;'+ | ||
'uniform float uPointSize;'+ | ||
'out lowp vec4 color;'+ | ||
'void main(void){'+ | ||
'vec4 pos = uMVMatrix * vec4(a_position.xyz, 1.0);'+ | ||
'color = vec4(uColorAry[ int(a_position.w) ],1.0);'+ | ||
'gl_PointSize = (1.0 - distance( uCameraPos, pos.xyz ) / 10.0 ) * uPointSize;'+ | ||
'gl_Position = uPMatrix * uCameraMatrix * pos;'+ | ||
'}'; | ||
|
||
var fShader = '#version 300 es\n'+ | ||
'precision mediump float;'+ | ||
'in vec4 color;'+ | ||
'out vec4 finalColor;'+ | ||
'void main(void){ finalColor = color; }'; | ||
|
||
//........................................ | ||
this.mShader = ShaderUtil.createProgramFromText(this.gl,vShader,fShader,true); | ||
this.mUniformColor = this.gl.getUniformLocation(this.mShader,"uColorAry"); | ||
this.mUniformProj = this.gl.getUniformLocation(this.mShader,"uPMatrix"); | ||
this.mUniformCamera = this.gl.getUniformLocation(this.mShader,"uCameraMatrix"); | ||
this.mUniformModelV = this.gl.getUniformLocation(this.mShader,"uMVMatrix"); | ||
this.mUniformPointSize = this.gl.getUniformLocation(this.mShader,"uPointSize"); | ||
this.mUniformCameraPos = this.gl.getUniformLocation(this.mShader,"uCameraPos"); | ||
|
||
//........................................ | ||
//Save colors in the shader. Should only need to render once. | ||
this.gl.useProgram(this.mShader); | ||
this.gl.uniform3fv(this.mUniformColor, new Float32Array( this.mColor )); | ||
this.gl.uniform1f(this.mUniformPointSize, this.mPointSize); | ||
this.gl.useProgram(null); | ||
} | ||
|
||
finalize(){ | ||
this.mVertBuffer = this.gl.fCreateArrayBuffer(new Float32Array(this.mVerts),true); | ||
this.createShader(); | ||
return this; | ||
} | ||
|
||
render(camera){ | ||
//Update Transform Matrix (Modal View) | ||
this.transform.updateMatrix(); | ||
|
||
//Start up the Shader | ||
this.gl.useProgram(this.mShader); | ||
|
||
//Push Uniform Data | ||
this.gl.uniformMatrix4fv(this.mUniformProj, false, camera.projectionMatrix); | ||
this.gl.uniformMatrix4fv(this.mUniformCamera, false, camera.viewMatrix); | ||
this.gl.uniformMatrix4fv(this.mUniformModelV, false, this.transform.getViewMatrix()); | ||
this.gl.uniform3fv(this.mUniformCameraPos, new Float32Array( camera.transform.position.getArray() )); | ||
|
||
//Activate Vertice Buffer Array | ||
this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.mVertBuffer); | ||
this.gl.enableVertexAttribArray(0); | ||
this.gl.vertexAttribPointer(0,this.mVertexComponentLen,this.gl.FLOAT,false,0,0); | ||
|
||
//Draw | ||
this.gl.drawArrays(this.gl.POINTS,0,this.mVertCount); | ||
|
||
//Cleanup | ||
this.gl.disableVertexAttribArray(0); | ||
this.gl.useProgram(null); | ||
this.gl.bindBuffer(this.gl.ARRAY_BUFFER, null); | ||
} | ||
} |
Oops, something went wrong.