title: WebGL. Full screen quad or triangle for invoking fragment shader for every pixel?
body: <p>In many examples over internet (such as <a href="https://webglfundamentals.org/webgl/lessons/webgl-image-processing.html" rel="noreferrer">webglfundamentals</a> or <a href="https://github.com/paulirish/webgl-boilerplate/blob/master/index.html" rel="noreferrer">webgl-bolerplate</a>) authors used two triangles to cover full screen and invoke pixel shader for every pixel on canvas. </p>
  
  <p><div class="snippet" data-lang="js" data-hide="true" data-console="false" data-babel="false">
  <div class="snippet-code snippet-currently-hidden">
  <pre class="snippet-code-js lang-js prettyprint-override"><code>var canvas, gl, buffer, 
         vertex_shader, fragment_shader, 
         currentProgram, vertex_position,
         timeLocation, resolutionLocation,
         parameters = {  start_time  : new Date().getTime(), 
                         time        : 0, 
                         screenWidth : 0, 
                         screenHeight: 0 };
     init();
     animate();
   
     function init() {
      vertex_shader = document.getElementById('vs').textContent;
      fragment_shader = document.getElementById('fs').textContent;
      canvas = document.querySelector( 'canvas' );
      try {
       gl = canvas.getContext( 'experimental-webgl' );
      } catch( error ) { }
      if ( !gl ) 
       throw "cannot create webgl context";
  
      // Create Vertex buffer (2 triangles)
      buffer = gl.createBuffer();
      gl.bindBuffer( gl.ARRAY_BUFFER, buffer );
      gl.bufferData( gl.ARRAY_BUFFER, new Float32Array( [ - 1.0, - 1.0, 1.0, - 1.0, - 1.0, 1.0, 1.0, - 1.0, 1.0, 1.0, - 1.0, 1.0 ] ), gl.STATIC_DRAW );
   
      currentProgram = createProgram( vertex_shader, fragment_shader );
      timeLocation = gl.getUniformLocation( currentProgram, 'time' );
      resolutionLocation = gl.getUniformLocation( currentProgram, 'resolution' );
     }
   
     function createProgram( vertex, fragment ) {
      var program = gl.createProgram();
      var vs = createShader( vertex, gl.VERTEX_SHADER );
      var fs = createShader( '#ifdef GL_ES\nprecision highp float;\n#endif\n\n' + fragment, gl.FRAGMENT_SHADER );
   
      if ( vs == null || fs == null ) 
              return null;
   
      gl.attachShader( program, vs );
      gl.attachShader( program, fs );
      gl.deleteShader( vs );
      gl.deleteShader( fs );
      gl.linkProgram( program );
   
      if ( !gl.getProgramParameter( program, gl.LINK_STATUS ) ) {
       alert( "ERROR:\n" +
       "VALIDATE_STATUS: " + gl.getProgramParameter( program, gl.VALIDATE_STATUS ) + "\n" +
       "ERROR: " + gl.getError() + "\n\n" +
       "- Vertex Shader -\n" + vertex + "\n\n" +
       "- Fragment Shader -\n" + fragment );
       return null;
      }
      return program;
     }
   
     function createShader( src, type ) {
      var shader = gl.createShader( type );
      gl.shaderSource( shader, src );
      gl.compileShader( shader );
      if ( !gl.getShaderParameter( shader, gl.COMPILE_STATUS ) ) {
       alert( ( type == gl.VERTEX_SHADER ? "VERTEX" : "FRAGMENT" ) + " SHADER:\n" + gl.getShaderInfoLog( shader ) );
       return null;
      }
      return shader;
     }
   
     function resizeCanvas( event ) {
      if ( canvas.width != canvas.clientWidth ||
        canvas.height != canvas.clientHeight ) {
       canvas.width = canvas.clientWidth;
       canvas.height = canvas.clientHeight;
       parameters.screenWidth = canvas.width;
       parameters.screenHeight = canvas.height;
       gl.viewport( 0, 0, canvas.width, canvas.height );
      }
     }
   
     function animate() {
      resizeCanvas();
      render();
      requestAnimationFrame( animate );
     }
   
     function render() {
      if ( !currentProgram ) 
              return;
      parameters.time = new Date().getTime() - parameters.start_time;
      gl.clear( gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT );
      gl.useProgram( currentProgram );
      gl.uniform1f( timeLocation, parameters.time / 1000 );
      gl.uniform2f( resolutionLocation, parameters.screenWidth, parameters.screenHeight );
      gl.bindBuffer( gl.ARRAY_BUFFER, buffer );
      gl.vertexAttribPointer( vertex_position, 2, gl.FLOAT, false, 0, 0 );
      gl.enableVertexAttribArray( vertex_position );
      gl.drawArrays( gl.TRIANGLES, 0, 6 );
      gl.disableVertexAttribArray( vertex_position );
     }</code></pre>
  <pre class="snippet-code-css lang-css prettyprint-override"><code>html, body {
    background-color: #000000;
    margin: 0px;
    overflow: hidden;
    width: 100%;
    height: 100%;
  }
  canvas {
    width: 100%;
    height: 100%;
  }</code></pre>
  <pre class="snippet-code-html lang-html prettyprint-override"><code>&lt;canvas&gt;&lt;/canvas&gt;
  &lt;div id="info"&gt;&lt;/div&gt; 
  
  &lt;script id="vs" type="x-shader/vertex"&gt; 
    attribute vec3 position;
    
    void main() {
      gl_Position = vec4( position, 1.0 );
    }
  &lt;/script&gt; 
  
  &lt;script id="fs" type="x-shader/fragment"&gt; 
    uniform float time;
    uniform vec2 resolution;
  
    void main( void ) {
      vec2 position = - 1.0 + 2.0 * gl_FragCoord.xy / resolution.xy;
      float red = abs( sin( position.x * position.y + time / 5.0 ) );
      float green = abs( sin( position.x * position.y + time / 4.0 ) );
      float blue = abs( sin( position.x * position.y + time / 3.0 ) );
      gl_FragColor = vec4( red, green, blue, 1.0 );
    }
  &lt;/script&gt;</code></pre>
  </div>
  </div>
  </p>
  
  <p>this code uses buffer with 6 vertices for render something like this:</p>
  
  <p><a href="https://i.stack.imgur.com/ox90c.png" rel="noreferrer"><img src="https://i.stack.imgur.com/ox90c.png" alt="full screen quad"></a></p>
  
  <blockquote>
    <p>does this method has any advantages or not?</p>
  </blockquote>
  
  <p>comparing to method, where we render one triangle (3 vertices) covering full screen like on this picture:</p>
  
  <p><a href="https://i.stack.imgur.com/5Ny6k.png" rel="noreferrer"><img src="https://i.stack.imgur.com/5Ny6k.png" alt="full screen triangle"></a></p>
  
  <p><div class="snippet" data-lang="js" data-hide="false" data-console="true" data-babel="false">
  <div class="snippet-code">
  <pre class="snippet-code-css lang-css prettyprint-override"><code>body{
    margin: 0;
    overflow: hidden;
  }</code></pre>
  <pre class="snippet-code-html lang-html prettyprint-override"><code>&lt;canvas&gt;&lt;/canvas&gt;
  
  &lt;script type='glsl/vertex'&gt;
    attribute vec2 coords;
    
    void main(void) {
      gl_Position = vec4(coords.xy, 0.0, 1.0);
    }
  &lt;/script&gt;
  
  &lt;script type='glsl/fragment'&gt;precision highp float;
  
     uniform vec4 mr;
     
     void main(void) {
       vec2 p = gl_FragCoord.xy;
       vec2 q = (p + p - mr.ba) / mr.b;
       for(int i = 0; i &lt; 13; i++) {
            q = abs(q)/dot(q,q) -  mr.xy/mr.zw;
       }
       gl_FragColor = vec4(q, q.x/q.y, 1.0);
     }
  &lt;/script&gt;
  
  &lt;script&gt;
    let canvas = document.querySelector('canvas');
    canvas.width = window.innerWidth;
    canvas.height = window.innerHeight;
    let gl = canvas.getContext('webgl') || canvas.getContext('experimental-webgl');
    var h = gl.drawingBufferHeight;
    var w = gl.drawingBufferWidth;
    
    let pid = gl.createProgram();
    shader('glsl/vertex', gl.VERTEX_SHADER);
    shader('glsl/fragment', gl.FRAGMENT_SHADER);
    gl.linkProgram(pid);
    gl.useProgram(pid);
  
    let array = new Float32Array([-1,  3, -1, -1, 3, -1]);
    gl.bindBuffer(gl.ARRAY_BUFFER, gl.createBuffer());
    gl.bufferData(gl.ARRAY_BUFFER, array, gl.STATIC_DRAW);
  
    let al = gl.getAttribLocation(pid, "coords");
    gl.vertexAttribPointer(al, 2 /*components per vertex */, gl.FLOAT, false, 0, 0);
    gl.enableVertexAttribArray(al);
    
    let mr = gl.getUniformLocation(pid, 'mr');
    
    window.addEventListener('mousemove', draw);
    window.addEventListener('touchmove', draw);
  
    draw();
  
    function draw(e) {
      let ev = e &amp;&amp; e.touches ? e.touches[0] : e;
      let x = ev ? ev.clientX : 250;
      let y = ev ? h - ev.clientY: 111;
      gl.uniform4f(mr, x, y, w, h);
      gl.viewport(0, 0, w, h);
      gl.clearColor(0, 0, 0, 0);
      gl.drawArrays(gl.TRIANGLES, 0, 3);
    }
  
    function shader(name, type) {
      let src = [].slice.call(document.scripts).find(s =&gt; s.type === name).innerText;
      let sid = gl.createShader(type);
      gl.shaderSource(sid, src);
      gl.compileShader(sid);
      gl.attachShader(pid, sid);
    }
  &lt;/script&gt;</code></pre>
  </div>
  </div>
  </p>