Barycentric Coordinates

BACK FRONT FRONT_AND_BACK none

The HTML file:

<html>
<head>

<script id="vertex-shader" type="x-shader/x-vertex" >
precision mediump float;

attribute vec4 vPosition;
attribute vec3 vBC;
attribute vec4 vColor;

varying vec3 f_BC;
varying vec4 f_Color;
varying vec4 e_Color;

void main() {

    gl_Position = vPosition;
    f_BC = vBC;
    f_Color = vColor;
    e_Color = vec4(0.0, 0.0, 0.0, 1.0);
}
</script>

<script id="fragment-shader" type="x-shader/x-fragment">

    precision mediump float;

    varying vec4 f_Color;
    varying vec3 f_BC;
    varying vec4 e_Color;

    uniform int vShader;

    // filled with edge shader
    void Shader0() {
       if (any(lessThan(f_BC, vec3(0.005)))) {
           // edge, draw it with the edge color
           gl_FragColor= e_Color;
       } else {
           if (gl_FrontFacing) {
	       // front face, draw it with the face color
               gl_FragColor = f_Color;
	   } else {
	       // back face, draw it grey
	       gl_FragColor = vec4(0.5, 0.5, 0.5, 1.0);
	   }
       }
    }

    // wireframe shader
    void Shader1() {
       if (gl_FrontFacing) {  
           // front face
           if (any(lessThan(f_BC, vec3(0.05)))) {
	       // wide border
               gl_FragColor= e_Color;
           } else {
	       // no interior
	       discard;
           }
       } else {
           // back facing
           if (any(lessThan(f_BC, vec3(0.005)))) {
	       // narrow border
               gl_FragColor= e_Color;
	   } else {
	      // partially obscuring
	      gl_FragColor = vec4(0.2, 0.2, 0.2, 0.3);
	   }
       }
    }

    void main(){
        if (vShader == 0) {
            Shader0(); 
	} else if (vShader == 1) {
	    Shader1();
        } else {
	      gl_FragColor = vec4(1.0, 1.0, 1.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="GLCanvas.js"></script>
<script type="text/javascript" src="triangle.js"></script>

<style>
input {
    text-align: right;
}
</style>

</head>

<body>
     <h1>Barycentric Coordinates</h1>
<script>
    var canvas = new Canvas(500, 500);
    var triangle = new Triangle(canvas.GL(), canvas.Program());

    function Redisplay() {
        canvas.Clear();
        triangle.Display(canvas.GL()); 
    }

    Redisplay();
</script>

<p>

<button type="button" onclick="canvas.FlipDir(),Redisplay()">
   Triangle Dir
</button>

<button type="button" onclick="canvas.ChangeShader(),Redisplay()">
   Change Shader
</button>

 <form >
      <input type="radio" name="face" value="0" checked
             onchange="canvas.ChangeFace(this.value), Redisplay()">
             BACK 
     </input>
      <input type="radio" name="face" value="1" 
             onchange="canvas.ChangeFace(this.value), Redisplay()">
             FRONT 
     </input>
      <input type="radio" name="face" value="2" 
             onchange="canvas.ChangeFace(this.value), Redisplay()">
             FRONT_AND_BACK 
     </input>
      <input type="radio" name="face" value="3" 
             onchange="canvas.ChangeFace(this.value), Redisplay()">
             none 
     </input>
   </form>


</body>

GLCanvas.js

'use strict'

class Canvas {
    constructor (width, height, Keypress) {
        this.height = height;
        this.width = width;

        this.MakeCanvas();
        this.canvas.addEventListener("keypress", Keypress);

        this.SetupGL();
        this.MakeShaders();

        this.Init();
    }

    MakeCanvas() {
        if (this.width == undefined || this.width < 0) {
           this.width = 300;
        }

        if (this.height == undefined || this.height < 0) {
           this.height = 300;
        }

         this.canvas = document.createElement('canvas')
	 this.canvas.tabIndex=0;
         this.canvas.height = this.height;
         this.canvas.width = this.width;
         document.body.appendChild(this.canvas);
    }

    SetupGL() {
        this.gl = WebGLUtils.setupWebGL(this.canvas);
        if (!this.gl) {
            alert ("WebGL isn't available");
	    return;
        }
	this.gl.getExtension('OES_standard_derivatives');
    }

    MakeShaders() {
        this.program = initShaders(this.gl, "vertex-shader","fragment-shader");
        this.gl.useProgram(this.program);

	this.shaderLoc = this.gl.getUniformLocation(this.program, "vShader");
    }

    Init() {
        this.gl.clearColor(1.0, 1.0, 1.0, 1.0);
        this.gl.viewport(0,0, this.width, this.height);

	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.ChangeShader();
	this.FlipDir();
        this.ChangeFace(0);
    }

    FlipDir() {
        if (this.direction == this.gl.CCW) {
            this.direction = this.gl.CW;
        } else {
            this.direction = this.gl.CCW;
        }
        this.gl.frontFace(this.direction);
    }

    ChangeShader() {
        if (this.shaderChoice === 0 || this.shaderChoice === undefined ) {
            this.shaderChoice = 1
        } else {
            this.shaderChoice = 0;
        }
        this.gl.uniform1i(this.shaderLoc, this.shaderChoice);
    }

    ChangeFace(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;
        }
    }

    Program() {
       return this.program;
    }

    GL() {
       return this.gl;
    }

    Clear() {
        this.gl.clear(this.gl.COLOR_BUFFER_BIT | this.gl.DEPTH_BUFFER_BIT);
    }
};

triangle.js

'use strict'

class Triangle {
    constructor(gl, program) {
        this.SetupBuffers(gl, program)
	this.MakeList(gl)
    }

    SetupBuffers(gl, 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);
    }

    MakeList(gl) {

        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(gl);
    }

    UpdateBuffers(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);
    }

    Display(gl) {
         gl.drawArrays(gl.TRIANGLES, 0, this.verts.length);
    }
}