User Tools

Site Tools


Sidebar

General

Python Tutorials

WebGL Tutorials

Node.js Tutorials

Node.js in WebStorm


Martin Christen

View Martin Christen's profile on LinkedIn


Twitter

Timeline of @MartinChristen

MartinChristen avatar

RT @TFConsult: Celebrating 100th birthday of #physicist #RichardFeynman: The marvellous #Feynman lectures on #physics: https://t.co/81as7mN
About 1 week, 4 days ago by: Martin Christen (@MartinChristen)

MartinChristen avatar

RT @sergerey: Had a fantastic time giving our workshop on Spatial Data Science with PyData at @GeoPythonConf with @levijohnwolf. Looking f…
About 1 week, 5 days ago by: Martin Christen (@MartinChristen)

MartinChristen avatar

RT @fridex: Everything has an end even such an excellent conference #GeoPythonConf in Basel. Thanks to organizers for such an outstanding c…
About 1 week, 5 days ago by: Martin Christen (@MartinChristen)
webgl:tutorial02

WebGL Tutorial 2: Draw a Triangle

(unfinished: work in progress)

At first, drawing ta triangle using WebGL seems to be complicated, as we need to understand several things like vertex and fragment shaders, projections, vertex buffers, and so on.

So let's start with a very simple application and draw a 2D triangle like this:

Normalized Device Coordinates

We will draw the triangle in normalized device coordinates (NDC). This is a left handed coordinate system with range [-1,1] for all components x,y, and z:

WebGL draws triangles, lines and points in normalized device coordinates. Whatever you want to draw your coordinates must be in the range from (-1,-1,-1) to (1,1,1). WebGL will clip all primitives to this range. This means triangles, lines, and points are clipped if not in this range.

There are several famous transformations which result in NDC, like the perspective or orthographic/orthogonal projection. These transformations are not part of this tutorial: in this tutorial we don't do any transformations we create our geometries directly in normalized device coordinates.

The operation is completed by WebGL by transforming the normalized device coordinates to Window Coordinates, sometimes also called “Pixel Coordinates” or “Screen Coordinates”.

Shaders: Processing Vertices and Fragments

In WebGL you have to implement two types of so called “shaders”. The first is the vertex shader. This is a program running on the GPU which is called for each vertex. In this shader you can do operations related to vertices. In many cases this involves transforming vertices. The second is the fragment shader. This is a program which is called for each fragment. Usually the output color of the fragment is calculated here.

The Application

Now lets start implementing this application: The onload event start with the main function. In last tutorial we learned how to initialize WebGL, this is done here again.

var gl = initWebGL();

Now we get the vertex and the fragment shader source code from the DOM:

         var v = document.getElementById("vertexshader").firstChild.nodeValue;
         var f = document.getElementById("fragmentshader").firstChild.nodeValue;

The shaders are compiled:

         var vs = gl.createShader(gl.VERTEX_SHADER);
         gl.shaderSource(vs, v);
         gl.compileShader(vs);
 
         if (!gl.getShaderParameter(vs, gl.COMPILE_STATUS))
            alert(gl.getShaderInfoLog(vs));
 
         var fs = gl.createShader(gl.FRAGMENT_SHADER);
         gl.shaderSource(fs, f);
         gl.compileShader(fs);
 
         if (!gl.getShaderParameter(fs, gl.COMPILE_STATUS))
            alert(gl.getShaderInfoLog(fs));
 
         program = gl.createProgram();
         gl.attachShader(program, vs);
         gl.attachShader(program, fs);
         gl.linkProgram(program);

The whole program looks like this:

<html>
<head>
   <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
   <meta name="keywords" content="WebGL">
   <meta name="author" content="Martin Christen, martin.christen@gmail.com">
   <script id="vertexshader" type="x-shader">
      attribute vec2 aVertexPosition;

      void main() {
      gl_Position = vec4(aVertexPosition, 0.0, 1.0);
      }
   </script>
   <script id="fragmentshader" type="x-shader">
      #ifdef GL_ES
      precision highp float;
      #endif

      uniform vec4 uColor;

      void main() {
      gl_FragColor = uColor;
      }
   </script>
   <script type="text/javascript">

      function initWebGL()
      {
         var canvas = document.getElementById("canvas");
         var gl = canvas.getContext("webgl") || canvas.getContext("experimental-webgl");
         if (!gl) return null; // can't initialize WebGL
         return gl;
      }

      function main()
      {
         var gl = initWebGL();

         // Setup Shaders:
         var v = document.getElementById("vertexshader").firstChild.nodeValue;
         var f = document.getElementById("fragmentshader").firstChild.nodeValue;

         var vs = gl.createShader(gl.VERTEX_SHADER);
         gl.shaderSource(vs, v);
         gl.compileShader(vs);

         if (!gl.getShaderParameter(vs, gl.COMPILE_STATUS))
            alert(gl.getShaderInfoLog(vs));

         var fs = gl.createShader(gl.FRAGMENT_SHADER);
         gl.shaderSource(fs, f);
         gl.compileShader(fs);

         if (!gl.getShaderParameter(fs, gl.COMPILE_STATUS))
            alert(gl.getShaderInfoLog(fs));

         program = gl.createProgram();
         gl.attachShader(program, vs);
         gl.attachShader(program, fs);
         gl.linkProgram(program);


         if (!gl.getProgramParameter(program, gl.LINK_STATUS))
            alert(gl.getProgramInfoLog(program));

         // Setup Geometry
         var vertices = new Float32Array([
            -0.5,-0.5,0.5,-0.5,0.0,0.5  // Triangle-Coordinates
         ]);

         vbuffer = gl.createBuffer();
         gl.bindBuffer(gl.ARRAY_BUFFER, vbuffer);
         gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);

         itemSize = 2; // we have 2 coordinates (x,y)
         numItems = vertices.length / itemSize; // number of triangles

         // Viewport
         gl.viewport(0, 0, canvas.width, canvas.height);
         gl.clearColor(0, 0, 0, 1);
         gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);

         // Setup Geometry:
         gl.useProgram(program);

         program.uColor = gl.getUniformLocation(program, "uColor");
         gl.uniform4fv(program.uColor, [0.5, 0.0, 0.0, 1.0]);

         program.aVertexPosition = gl.getAttribLocation(program, "aVertexPosition");
         gl.enableVertexAttribArray(program.aVertexPosition);
         gl.vertexAttribPointer(program.aVertexPosition, itemSize, gl.FLOAT, false, 0, 0);

         // Draw:
         gl.drawArrays(gl.TRIANGLES, 0, numItems);
      }
   </script>
</head>
<body onload="main()">
<div style="text-align: center">
   <canvas id="canvas" width="512" height="512"></canvas>
</div>
</body>
</html>


webgl/tutorial02.txt · Last modified: 2013/09/03 15:32 by mchristen