Transforming the Teapot.
- The red xwing
var a = mult(scalem(0.25, 0.25, 0.25), rotate(-90, [1,0,0]));
var b = translate(0.25, 0.25, 0.0);
var c = rotate(90, [0.0, 0.0, 1.0]);
var edge = vec4(1.0, 0.0, 0.0, 1.0);
canvas.gl.uniformMatrix4fv(canvas.mat1Pos, false, flatten(a));
canvas.gl.uniformMatrix4fv(canvas.mat2Pos, false, flatten(mat4(1.0)));
canvas.gl.uniform4fv(canvas.edgeColorPos, flatten(edge));
model.Display()
- The green xwing
var d = mult(b, a);
edge = vec4(0.0, 1.0, 0.0, 1.0);
canvas.gl.uniformMatrix4fv(canvas.mat1Pos, false, flatten(d));
canvas.gl.uniformMatrix4fv(canvas.mat2Pos, false, flatten(c));
canvas.gl.uniform4fv(canvas.edgeColorPos, flatten(edge));
model.Display();
- The blue xwing
edge = vec4(0.0, 0.0, 1.0, 1.0);
d = mult(c, a);
canvas.gl.uniformMatrix4fv(canvas.mat1Pos, false, flatten(d));
canvas.gl.uniformMatrix4fv(canvas.mat2Pos, false, flatten(b));
canvas.gl.uniform4fv(canvas.edgeColorPos, flatten(edge));
The HTML File
<html>
<head>
<script id="vertex-shader" type="x-shader/x-vertex" >
precision mediump float;
attribute vec4 aPosition;
attribute vec3 aBC;
uniform mat4 uMatrix1, uMatrix2, uWorld;
varying vec3 vBC;
void main() {
gl_Position = uWorld * uMatrix2 * uMatrix1 * aPosition;
vBC = aBC;
}
</script>
<script id="fragment-shader" type="x-shader/x-fragment">
#extension GL_OES_standard_derivatives : enable
precision mediump float;
varying vec3 vBC;
uniform vec4 uEdgeColor;
float edgeFactor(){
vec3 d = fwidth(vBC);
vec3 a3 = smoothstep(vec3(0.0), d*1.5, vBC);
return min(min(a3.x, a3.y), a3.z);
}
void main(){
vec4 tmp;
tmp = uEdgeColor;
tmp.a = (1.0-edgeFactor())*0.95;
if (gl_FrontFacing) {
gl_FragColor = tmp;
} else {
discard;
}
}
</script>
<script type="text/javascript" src="../../Common/webgl-utils.js"></script>
<script type="text/javascript" src="../../Common/initShaders.js"></script>
<script type="text/javascript" src="../../Common/MV.js"></script>
<script type="text/javascript" src="../../Models/cone.js"></script>
<script type="text/javascript" src="../../Models/cube.js"></script>
<script type="text/javascript" src="../../Models/dragon.js"></script>
<script type="text/javascript" src="../../Models/epcot.js"></script>
<script type="text/javascript" src="../../Models/lizard.js"></script>
<script type="text/javascript" src="../../Models/tank.js"></script>
<script type="text/javascript" src="../../Models/teapot.js"></script>
<script type="text/javascript" src="../../Models/xwing.js"></script>
<script type="text/javascript" src="modelDisplay.js"></script>
<script type="text/javascript" src="canvas.js"></script>
<script type="text/javascript" src="main.js"></script>
<style>
input {
text-align: right;
}
</style>
</head>
<body>
<h1>Transforming the Teapot.</h1>
<script>
// set up the canvas
var canvas = new Canvas(500, 500);
var xwing= new xwingModel();
var model = new ModelDisplay(canvas, xwing);
//add a callback for keypresses
canvas.disp.addEventListener("keypress",
function(evnt) {
KeyFunc(evnt, canvas, model);
}
);
// display it.
DoRedisplay(canvas, model);
</script>
<ul>
<Li> The red xwing
<pre class="prettyprint">
var a = mult(scalem(0.25, 0.25, 0.25), rotate(-90, [1,0,0]));
var b = translate(0.25, 0.25, 0.0);
var c = rotate(90, [0.0, 0.0, 1.0]);
var edge = vec4(1.0, 0.0, 0.0, 1.0);
canvas.gl.uniformMatrix4fv(canvas.mat1Pos, false, flatten(a));
canvas.gl.uniformMatrix4fv(canvas.mat2Pos, false, flatten(mat4(1.0)));
canvas.gl.uniform4fv(canvas.edgeColorPos, flatten(edge));
model.Display()
</pre>
<li> The green xwing
<pre class="prettyprint">
var d = mult(b, a);
edge = vec4(0.0, 1.0, 0.0, 1.0);
canvas.gl.uniformMatrix4fv(canvas.mat1Pos, false, flatten(d));
canvas.gl.uniformMatrix4fv(canvas.mat2Pos, false, flatten(c));
canvas.gl.uniform4fv(canvas.edgeColorPos, flatten(edge));
model.Display();
</pre>
<li> The blue xwing
<pre class="prettyprint">
edge = vec4(0.0, 0.0, 1.0, 1.0);
d = mult(c, a);
canvas.gl.uniformMatrix4fv(canvas.mat1Pos, false, flatten(d));
canvas.gl.uniformMatrix4fv(canvas.mat2Pos, false, flatten(b));
canvas.gl.uniform4fv(canvas.edgeColorPos, flatten(edge));
</pre>
</ul>
</body>
main.js
'use strict';
// counts on canvas and models being global.
function DoRedisplay(canvas, model) {
var i;
canvas.Redisplay();
var a = mult(mult(scalem(0.35, 0.35, 0.35), rotate(-90, [0,1,0])), rotate(90,[1,0,0]));
var b = translate(0.45, 0.45, 0.0);
var c = rotate(90, [0.0, 0.0, 1.0]);
//var c = scalem(2, 2, 2);
var edge = vec4(1.0, 0.0, 0.0, 1.0);
canvas.gl.uniformMatrix4fv(canvas.mat1Pos, false, flatten(a));
canvas.gl.uniformMatrix4fv(canvas.mat2Pos, false, flatten(mat4(1.0)));
canvas.gl.uniform4fv(canvas.edgeColorPos, flatten(edge));
model.Display();
var d = mult(b, a);
edge = vec4(0.0, 1.0, 0.0, 1.0);
canvas.gl.uniformMatrix4fv(canvas.mat1Pos, false, flatten(d));
canvas.gl.uniformMatrix4fv(canvas.mat2Pos, false, flatten(c));
canvas.gl.uniform4fv(canvas.edgeColorPos, flatten(edge));
model.Display();
edge = vec4(0.0, 0.0, 1.0, 1.0);
d = mult(c, a);
canvas.gl.uniformMatrix4fv(canvas.mat1Pos, false, flatten(d));
canvas.gl.uniformMatrix4fv(canvas.mat2Pos, false, flatten(b));
canvas.gl.uniform4fv(canvas.edgeColorPos, flatten(edge));
model.Display();
return;
};
function KeyFunc(evnt, canvas, models) {
switch(evnt.key) {
case 'X': canvas.Rotate('x', 'r'); break;
case 'Y': canvas.Rotate('y', 'r'); break;
case 'Z': canvas.Rotate('z', 'r'); break;
case 'x': canvas.Rotate('x', 'f'); break;
case 'y': canvas.Rotate('y', 'f'); break;
case 'z': canvas.Rotate('z', 'f'); break;
case 'r': canvas.Reset(); break;
}
DoRedisplay(canvas, models);
};
function MakeScene(model) {
var xwign= new xwingModel();
model = new ModelDisplay(canvas, xwing);
return;
}
canvas.js
'use strict';
function MakeCanvas(width, height, locID) {
if (width == undefined || width < 0) {
width = 300;
}
if (height == undefined || height < 0) {
height = 300;
}
var canvas = document.createElement('canvas')
canvas.tabIndex = 0;
canvas.height = height;
canvas.width = width;
canvas.style.border = "1px solid #0000FF";
if(locID == undefined) {
document.body.appendChild(canvas);
} else {
div = document.getElementById(locID);
if (null == div) {
document.body.appendChild(canvas);
} else {
div.appendChild(canvas);
}
}
document.body.appendChild(canvas);
return canvas;
}
function InitGL(canvas) {
var gl = WebGLUtils.setupWebGL(canvas,'OES_standard_derivatives');
if (!gl) {
alert ("WebGL isn't available");
}
gl.getExtension('OES_standard_derivatives');
return gl;
}
function Canvas(width, height, locID) {
this.disp = MakeCanvas(width, height, locID);
var gl = InitGL(this.disp);
this.gl = gl;
var tmpCanvas = this;
this.x = this.disp.offsetLeft;
this.y = this.disp.offsetTop;
gl.viewport(0,0, width, height);
this.program = initShaders(gl, "vertex-shader","fragment-shader");
gl.useProgram(this.program);
this.mat1Pos = gl.getUniformLocation(this.program, "uMatrix1");
this.mat2Pos = gl.getUniformLocation(this.program, "uMatrix2");
this.worldMatPos = gl.getUniformLocation(this.program, "uWorld");
this.edgeColorPos = gl.getUniformLocation(this.program, "uEdgeColor");
this.Init();
return this;
}
Canvas.prototype = {
Init: function() {
this.gl.clearColor(1.0, 1.0, 1.0, 1.0);
this.gl.enable(this.gl.BLEND);
this.gl.blendFunc(this.gl.SRC_ALPHA, this.gl.ONE_MINUS_SRC_ALPHA);
this.gl.enable(this.gl.DEPTH_TEST);
this.gl.depthFunc(this.gl.LESS);
this.gl.depthMask(this.gl.TRUE);
this.shaderChoice = false;
this.gl.uniform1f(this.shaderLoc, 0.0);
this.gl.enable(this.gl.CULL_FACE);
this.gl.frontFace(this.gl.CCW);
this.gl.cullFace(this.gl.BACK);
this.Reset();
},
Rotate: function(axis, dir) {
var change = 5;
if (dir =='r') {
change = -5;
}
switch(axis) {
case 'x': this.xr += change; break;
case 'y': this.yr += change; break;
case 'z': this.zr += change; break;
}
},
Reset: function() {
this.xr = 0;
this.yr = 0;
this.zr = 0;
},
Redisplay: function() {
this.gl.clear(this.gl.COLOR_BUFFER_BIT | this.gl.DEPTH_BUFFER_BIT);
var transform = mat4(1);
transform = mult(transform, rotate(this.xr, [1,0,0]));
transform = mult(transform, rotate(this.yr, [0,1,0]));
transform = mult(transform, rotate(this.zr, [0,0,1]));
this.gl.uniformMatrix4fv(this.worldMatPos,false, flatten(transform ));
return;
}
};
modelDisplay.js
'use strict';
/*
ModelDisplay is responsible for
Maintaining a connection between the vertex buffer and the model
Displaying the model when called.
*/
function ModelDisplay(canvas, model) {
this.gl = canvas.gl;
var gl = canvas.gl;
this.vboTriangles = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, this.vboTriangles);
this.pointCount = model.Triangles.length;
this.vPos = gl.getAttribLocation(canvas.program, "aPosition");
gl.vertexAttribPointer(this.vPos,3,gl.FLOAT, false,0,0);
gl.enableVertexAttribArray(this.vPos);
gl.bufferData(gl.ARRAY_BUFFER,flatten(model.Triangles),gl.STATIC_DRAW);
this.vboBC = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, this.vboBC);
this.vBC = gl.getAttribLocation(canvas.program, "aBC");
gl.vertexAttribPointer(this.vBC,3,gl.FLOAT, false,0,0);
gl.enableVertexAttribArray(this.vBC);
gl.bufferData(gl.ARRAY_BUFFER,flatten(model.BC),gl.STATIC_DRAW);
};
ModelDisplay.prototype= {
Display() {
var gl = this.gl;
gl.bindBuffer(gl.ARRAY_BUFFER, this.vboTriangles);
gl.vertexAttribPointer(this.vPos,3,gl.FLOAT, false,0,0);
gl.bindBuffer(gl.ARRAY_BUFFER, this.vboBC);
gl.vertexAttribPointer(this.vBC,3,gl.FLOAT, false,0,0);
this.gl.drawArrays(this.gl.TRIANGLES, 0, this.pointCount);
}
};