Skip to content

Commit

Permalink
Lesson 015 : Texture Atlas
Browse files Browse the repository at this point in the history
  • Loading branch information
sketchpunk committed Mar 29, 2017
1 parent 59e4380 commit 501efe9
Show file tree
Hide file tree
Showing 15 changed files with 2,210 additions and 23 deletions.
144 changes: 144 additions & 0 deletions lesson_015/Camera.js
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;
}
}
249 changes: 249 additions & 0 deletions lesson_015/Debug.js
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);
}
}
Loading

0 comments on commit 501efe9

Please sign in to comment.