Press x,y,z to rotate.
<html> <head> <script id="vertex-shader" type="x-shader/x-vertex" > attribute vec4 vPosition; attribute vec3 vBC; attribute vec4 vColor; uniform mat4 Transform; uniform float vFillType; varying vec3 f_BC; varying vec4 f_Color; varying float f_FillType; void main() { gl_Position = Transform * vPosition; f_BC = vBC; f_Color = vec4(1.0, 0.0, 0.0, 1.0); f_FillType = vFillType; } </script> <script id="fragment-shader" type="x-shader/x-fragment"> #extension GL_OES_standard_derivatives : enable precision mediump float; varying vec4 f_Color; varying vec3 f_BC; varying float f_FillType; float edgeFactor(){ vec3 d = fwidth(f_BC); vec3 a3 = smoothstep(vec3(0.0), d*1.5, f_BC); return min(min(a3.x, a3.y), a3.z); } void main(){ if (f_FillType >= 1.0) { // alpha by edge if(gl_FrontFacing){ gl_FragColor = vec4(0,0.0,0.0, (1.0-edgeFactor())*0.95); } else { gl_FragColor = vec4(0.0, 0.0, 0.0, (1.0-edgeFactor())*0.7); } } else { if (gl_FrontFacing) { gl_FragColor = f_Color; } else { gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0); } } } </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="../offs/oldTeapot.js"></script> <!-- <script type="text/javascript" src="../offs/oldLizard.js"></script> --!> <!-- <script type="text/javascript" src="../offs/oldTank.js"></script> --!> <!-- <script type="text/javascript" src="../offs/oldDragon.js"></script> --!> <script type="text/javascript" src="offTeapot.js"></script> <script src="https://cdn.rawgit.com/google/code-prettify/master/loader/run_prettify.js"></script> <style> input { text-align: right; } </style> </head> <body> <h1>Care for Tea?</h1> <script> var canvas = new Canvas(500, 500); </script> <p> <button type="button" onclick="canvas.FlipDir(),canvas.Redisplay()"> Triangle Dir </button> <button type="button" onclick="canvas.ChangeShader(),canvas.Redisplay()"> Change Shader </button> <form > <input type="radio" name="face" value="0" checked onchange="canvas.ChangeFace(this.value), canvas.Redisplay()"> BACK </input> <input type="radio" name="face" value="1" onchange="canvas.ChangeFace(this.value), canvas.Redisplay()"> FRONT </input> <input type="radio" name="face" value="2" onchange="canvas.ChangeFace(this.value), canvas.Redisplay()"> FRONT_AND_BACK </input> <input type="radio" name="face" value="3" onchange="canvas.ChangeFace(this.value), canvas.Redisplay()"> none </input> </form> Press x,y,z to rotate. </body>
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"); } // required to turn on fwidth and such. gl.getExtension('OES_standard_derivatives'); return gl; } function Canvas(width, height, locID) { var canvas = MakeCanvas(width, height, locID); var gl = InitGL(canvas); this.gl = gl; var tmpCanvas = this; this.x = canvas.offsetLeft; this.y = canvas.offsetTop; canvas.addEventListener("keypress", function(evnt) { tmpCanvas.KeyFunc(tmpCanvas, evnt); } ); gl.viewport(0,0, width, height); var program = initShaders(gl, "vertex-shader","fragment-shader"); gl.useProgram(program); this.vPos = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER, this.vPos); var vPos = gl.getAttribLocation(program, "vPosition"); gl.vertexAttribPointer(vPos,3,gl.FLOAT, false,0,0); gl.enableVertexAttribArray(vPos); this.vBC = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER, this.vBC); var vBC = gl.getAttribLocation(program, "vBC"); gl.vertexAttribPointer(vBC,3,gl.FLOAT, false,0,0); gl.enableVertexAttribArray(vBC); this.shaderLoc = gl.getUniformLocation(program, "vFillType"); gl.uniform1f(this.shaderLoc, 0.0); this.transformLoc = gl.getUniformLocation(program, "Transform"); 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.RestartList(); this.shaderChoice = false; this.gl.uniform1f(this.shaderLoc, 0.0); this.Reset(); this.Redisplay(); }, Reset: function() { this.xr = 0; this.yr = 0; this.zr = 0; // make these switchable this.gl.enable(this.gl.CULL_FACE); this.direction = this.gl.CCW; this.gl.frontFace(this.direction); this.gl.cullFace(this.gl.BACK); }, FlipDir: function() { if (this.direction == this.gl.CCW) { this.direction = this.gl.CW; } else { this.direction = this.gl.CCW; } this.gl.frontFace(this.direction); }, RestartList: function() { this.verts= teapotTriangles ; this.bc = teapotBC this.UpdateBuffers(); }, UpdateBuffers: function() { var gl = this.gl; // change the vertex data gl.bindBuffer(gl.ARRAY_BUFFER, this.vBC); gl.bufferData(gl.ARRAY_BUFFER,flatten(this.bc),gl.STATIC_DRAW); gl.bindBuffer(gl.ARRAY_BUFFER, this.vPos); gl.bufferData(gl.ARRAY_BUFFER,flatten(this.verts),gl.STATIC_DRAW); }, ChangeShader: function() { this.shaderChoice = ! this.shaderChoice; var shader = 0.0; if (this.shaderChoice) { shader = 1.0 } this.gl.uniform1f(this.shaderLoc, shader); }, ChangeFace: function(value) { switch(value) { default: case '0': this.gl.enable(this.gl.CULL_FACE); this.gl.cullFace(this.gl.BACK); break; case '1': this.gl.enable(this.gl.CULL_FACE); this.gl.cullFace(this.gl.FRONT); break; case '2': this.gl.enable(this.gl.CULL_FACE); this.gl.cullFace(this.gl.FRONT_AND_BACK); break; case '3': this.gl.disable(this.gl.CULL_FACE); break; } }, KeyFunc: function(me, evnt) { switch(evnt.key) { case 'X': me.xr += -5; break; case 'Y': me.yr += -5; break; case 'Z': me.zr += -5; break; case 'x': me.xr += 5; break; case 'y': me.yr += 5; break; case 'z': me.zr += 5; break; case 'r': me.Reset(); break; } me.Redisplay(); }, Redisplay: function() { var transform = mat4(1); // this probably doesn't belong here 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.transformLoc,false, flatten(transform )); this.gl.clear(this.gl.COLOR_BUFFER_BIT | this.gl.DEPTH_BUFFER_BIT); this.gl.drawArrays(this.gl.TRIANGLES, 0, this.verts.length); return; } };