Press x,y,z to rotate.
<html>
<head>
<script id="vertex-shader" type="x-shader/x-vertex" >
precision mediump float;
attribute vec4 vPosition;
attribute vec3 vBC;
attribute vec4 vColor;
//uniform float vFillType;
varying vec3 f_BC;
varying vec4 f_Color;
void main() {
gl_Position = vPosition;
f_BC = vBC;
f_Color = vColor;
}
</script>
<script id="fragment-shader" type="x-shader/x-fragment">
#extension GL_OES_standard_derivatives : enable
precision mediump float;
uniform float vFillType;
varying vec4 f_Color;
varying vec3 f_BC;
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 (vFillType >= 1.0) {
if(gl_FrontFacing){
gl_FragColor = vec4(0.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);
// gl_FragColor = vec4(1.0, 0.0, 0.0, 0.5);
}
} else {
if(gl_FrontFacing){
gl_FragColor = f_Color;
} else {
gl_FragColor = vec4(0.0, 0.0, 0.0, 0.5);
}
}
}
</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="bary.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>It's a Hollow Feeling</h1>
This code is based on a discussion <a href="http://codeflow.org/entries/2012/aug/02/easy-wireframe-display-with-barycentric-coordinates/">here</a>.
<script>
var canvas = new Canvas(500, 500);
canvas.Redisplay();
</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;
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;
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,2,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);
// a buffer for the colors
this.cBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, this.cBuffer);
var colorAttribute = gl.getAttribLocation(program, "vColor");
gl.vertexAttribPointer(colorAttribute,3,gl.FLOAT, false,0,0);
gl.enableVertexAttribArray(colorAttribute);
this.shaderLoc = gl.getUniformLocation(program, "vFillType");
gl.uniform1f(this.shaderLoc, 0.0);
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.RestartList();
this.shaderChoice = false;
this.gl.uniform1f(this.shaderLoc, 0.0);
this.direction = this.gl.CCW;
this.gl.frontFace(this.direction);
this.gl.cullFace(this.gl.BACK);
this.gl.enable(this.gl.CULL_FACE);
},
FlipDir: function() {
if (this.direction == this.gl.CCW) {
this.direction = this.gl.CW;
} else {
this.direction = this.gl.CCW;
}
this.gl.frontFace(this.direction);
this.Redisplay();
},
RestartList: function() {
var p1 = vec2(-0.8, -0.8);
var p2 = vec2(-0.1, -0.1);
var p3 = vec2(-0.8, -0.1);
this.verts= [p1, p2, p3] ;
p1 = vec2(0.1, 0.1);
p3 = vec2(0.8, 0.1);
p2 = vec2(0.8, 0.8);
this.verts.push(p1);
this.verts.push(p2);
this.verts.push(p3);
var c1 = vec3(Math.random(), Math.random(),Math.random())
var c2 = vec3(Math.random(), Math.random(),Math.random())
var c3 = vec3(Math.random(), Math.random(),Math.random())
this.colors = [c1, c2, c3];
c1 = vec3(Math.random(), Math.random(),Math.random())
c2 = vec3(Math.random(), Math.random(),Math.random())
c3 = vec3(Math.random(), Math.random(),Math.random())
this.colors.push(c1);
this.colors.push(c2);
this.colors.push(c3);
this.bc = [[1,0,0],[0,1,0],[0,0,1],[1,0,0],[0,1,0],[0,0,1]];
this.UpdateBuffers();
this.Redisplay();
},
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);
gl.bindBuffer(gl.ARRAY_BUFFER, this.cBuffer);
gl.bufferData(gl.ARRAY_BUFFER,flatten(this.colors),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);
this.Redisplay();
},
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;
}
this.Redisplay();
},
Redisplay: function() {
this.gl.clear(this.gl.COLOR_BUFFER_BIT );
this.gl.drawArrays(this.gl.TRIANGLES, 0, this.verts.length);
return;
}
};