Click here to Skip to main content
13,043,898 members (47,091 online)
Click here to Skip to main content
Add your own
alternative version

Tagged as


2 bookmarked
Posted 17 May 2013

Line in WebGL and Why You Are Going to do this on your Own

, 17 May 2013
Rate this:
Please Sign up or sign in to vote.
Line in WebGL and why you are going to do this on your own

WebGL as a method for generating 3D graphic in browser is pretty powerful. You can do really awesome things with this, like porting Quake 2 to JavaScript or creating model of human body. But all of these 3D objects are a complex collection of hundreds or thousands of triangles. What if you just want to draw a simple thin line? Luckily, OpenES has support for that. So it is possible. Let's see how to do that.

I will use for that changed code from Minimum length WebGL code to draw least meaningful output - A straight line. What I changed was just removing of few unnecessary lines and putting all uninteresting boilerplate code into functions. First, initGl, initializes WebGl context from canvas tag. Second, initShaders, creates shaders program and initializes it with location of uniforms and attributes. Next initializes scene by clearing plane, creates model-view matrix and perspective matrix. I changed those matrices to those, which I think will help to understand line points coordinates, because Z axis is orthogonal to screen, so point (-1,-1,0) will actually at bottom-left part of canvas. To put it simply: scene viewer and you will look from the same point (more or less of course Smile). Model view matrix will also translate all Z coordinates by -7, so points with Z = 0 will be visible. Now code:

    <script type="text/javascript">

        var fragShaderSource = "\
precision highp float;\
uniform vec4 u_color;\
void main(void) {\
gl_FragColor = u_color;\

        var vtxShaderSource = "\
attribute vec3 a_position;\
uniform vec4 u_color;\
uniform mat4 u_mvMatrix;\
uniform mat4 u_pMatrix;\
void main(void) {\
gl_Position = u_pMatrix * u_mvMatrix * vec4(a_position, 1.0);\

        function get_shader(type, source) {
            var shader = gl.createShader(type);
            gl.shaderSource(shader, source);
            return shader;

        var gl, pMatrix, mvMatrix, vbuf,ibuf;

        function initGl() {
            var canvas = document.getElementsByTagName('canvas')[0];
            gl = canvas.getContext("experimental-webgl", { antialias: true });
            gl.viewport(0, 0, canvas.width, canvas.height);

        function initShaders() {
            var vertexShader = get_shader(gl.VERTEX_SHADER, vtxShaderSource);
            var fragmentShader = get_shader(gl.FRAGMENT_SHADER, fragShaderSource);
            shaderProgram = gl.createProgram();
            gl.attachShader(shaderProgram, vertexShader);
            gl.attachShader(shaderProgram, fragmentShader);
            shaderProgram.aposAttrib = gl.getAttribLocation(shaderProgram, "a_position");
            shaderProgram.colorUniform = gl.getUniformLocation(shaderProgram, "u_color");
            shaderProgram.pMUniform = gl.getUniformLocation(shaderProgram, "u_pMatrix");
            shaderProgram.mvMUniform = gl.getUniformLocation(shaderProgram, "u_mvMatrix");

        function initScene() {
            gl.clearColor(0.0, 0.0, 0.0, 0.0);
            mvMatrix =
                              [1, 0, 0, 0
                              , 0, 1, 0.00009999999747378752, 0,
                              0, -0.00009999999747378752, 1, 0,
                              0, 1.3552527156068805e-20, -8, 1];
            pMatrix =
                              [2.4142136573791504, 0, 0, 0,
                              0, 2.4142136573791504, 0, 0,
                              0, 0, -1.0020020008087158, -1,
                              0, 0, -0.20020020008087158, 0];
            gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
            gl.uniformMatrix4fv(shaderProgram.pMUniform, false, new Float32Array(pMatrix));
            gl.uniformMatrix4fv(shaderProgram.mvMUniform, false, new Float32Array(mvMatrix));

        function initBuffer(glELEMENT_ARRAY_BUFFER, data) {
            var buf = gl.createBuffer();
            gl.bindBuffer(glELEMENT_ARRAY_BUFFER, buf);
            gl.bufferData(glELEMENT_ARRAY_BUFFER, data, gl.STATIC_DRAW);
            return buf;

        function initBuffers(vtx, idx) {
            vbuf = initBuffer(gl.ARRAY_BUFFER, vtx);
            ibuf = initBuffer(gl.ELEMENT_ARRAY_BUFFER, idx);
            gl.vertexAttribPointer(shaderProgram.aposAttrib, 3, gl.FLOAT, false, 0, 0);

        function unbindBuffers() {
            gl.bindBuffer(gl.ARRAY_BUFFER, null);
            gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);

        function onready() {
            var vtx = new Float32Array(
                [-1.0, -5.0, -5.0, 
                5.0, 5.0, 5.0]
            var idx = new Uint16Array([0, 1]);
            initBuffers(vtx, idx);
            gl.uniform4f(shaderProgram.colorUniform, 0, 0, 0, 1);
            gl.drawElements(gl.LINES, 2, gl.UNSIGNED_SHORT, 0);

<body onload="onready();">
    <canvas width="400" height="300"></canvas>

As you can see, the code necessary to draw a line is put inside //# in onready function. What does that code do? First is array of 6 numbers representing 2 points with 3 coordinates (X,Y,Z). Second array is just indexes for points from the first array. We want to draw line from the first and second points so it is just 2 numbers: 0 and 1. After initializing buffers with those arrays, we are defining width of our line. Next is defined color of our line and lined is drawn to scene. Pretty straightforward. It will give something like in the image below:

You can get the live example and code for this here.

What we can change in this code?

First color. It is just RGBA format in range from 0.0 to 1.0. You can also add more points to draw now single line but whole path. Great! What about width of line? This is sadly not working how you would want it to. In Mozilla, you can set whatever value you want and width will still be constant. Why?

Answers can be found in OpenGL ES specification:

"There is a range of supported line widths. Only width 1 is guaranteed to be supported; others depend on the implementation. To query the range of supported widths, call glGet with argument GL_ALIASED_LINE_WIDTH_RANGE"

So if you are in browser development, just implement line with width = 1 and you are done. Not very helpful. So if you are looking into using this part of WebGL extensively, I bet you will write your own library for lines anyway.

Just out of curiosity, I have tried to 'query range' of available widths:

gl.getParameter( gl.ALIASED_LINE_WIDTH_RANGE)

and not for big suprise, I got this:

Float32Array { 0= 1,  1=1 }

So... range is from 1 to 1. Not very wide, I must say (I tested it in FF 18.0.2).

I wanted to have control of width of my lines, so I ended up doing it on my own. Next time, I will write how I accomplished that.


This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


About the Author

Software Developer
Poland Poland
No Biography provided

You may also be interested in...

Comments and Discussions

-- There are no messages in this forum --
Permalink | Advertise | Privacy | Terms of Use | Mobile
Web02 | 2.8.170713.1 | Last Updated 17 May 2013
Article Copyright 2013 by n.podbielski
Everything else Copyright © CodeProject, 1999-2017
Layout: fixed | fluid