Simple tutorial needed - how to draw a line

I would like to draw a simple line from (x1,y1,z1) to (x2,y2,z2). That’s all…just draw a line. I’ve spent hours and hours looking at different tutorials, and I haven’t found anywhere how to simply draw a line. I can draw polys to my hearts content, but can’t find how to set to wireframe mode, or simply how to draw a line.

Are there any simple tutorials out there that would cover something this simple, or does anyone have any code samples they would like to share?

It’s just like drawing triangles.

In your “drawElements” call, change the first parameter from gl.TRIANGLES (or whatever it is) to gl.LINES, gl.LINE_STRIP or gl.LINE_LOOP. In the gl.LINES case, every pair of vertices in your input data will be connected to make a line between them (just like every group of three are connected to make a triangle with gl.TRIANGLES). In the gl.LINE_STRIP case, the system will connect up all of the vertices into one long series of connected lines - and in the gl.LINE_LOOP case it’ll also connect the last point back to the first to make a loop.

In theory, you can use gl.lineWidth(x) to set the width of the line in pixels - but on MS Windows systems that are using Direct3D “under the hood”, the MAX_LINE_WIDTH constant is probably set to 1.0 because Direct3D doesn’t support variable width lines.

Hence it is unwise to rely on having variable width lines in practice.

I don’t think the other traditional OpenGL method (to set the fill mode for polygons to “GL_LINE”) works in OpenGL-ES or WebGL.

I tried that, but nothing appeared in the canvas. I have a triangle strip that works in the same canvas, so I’m pretty sure the environment is setup correctly.

What is confusing me is the third parameter to drawElements - ulong type. What exactly does that mean? My choices are UNSIGNED_BYTE and UNSIGNED_SHORT. Does that mean my vertices are UNSIGNED_BYTE or UNSIGNED_SHORT rather than float? That would be very strange, and a bit annoying.

Is there a good reference anywhere? I’ve looked around and all I’ve found are a couple of “cheat sheets” that don’t really tell you as much as I’d like to know.

In theory: Take your program that draws a single triangle successfully - and change the first parameter of the drawElements function to gl.LINE_LOOP…change NOTHING else. That should draw that exact same triangle as three lines.

If it doesn’t - then there is something very strange going on - probably something else entirely.

If this test doesn’t work then take one of the demo programs like “shineyteapot” over at:

http://www.khronos.org/webgl/wiki/Demo_Repository

…make a copy and change the gl.drawElements call to draw the teapot as line loops.

  • If that works - then you have a starting point for a program that draws lines.
  • If it doesn’t work, then…I dunno…maybe you’ve found a bug in the driver or something.

The third parameter of drawElements is the type of the index array. In WebGL, it should always be UNSIGNED_SHORT. It’s not the type of the vertex data itself.

As for documentation: There is (of course) a Reference Manual - the specification of WebGL - however, because WebGL is almost identical to OpenGL-ES-2.0, it mostly refers to the OpenGL-ES-2.0 spec. So the WebGL spec is mostly just a way to understand what the differences from OpenGL-ES-2 are.

Hence most of the resources you should be reading are OpenGL ES 2 documentation:

There is a nice set of “man” pages:

http://www.khronos.org/opengles/sdk/docs/man/

…a formal specification:

http://www.khronos.org/registry/gles/sp … 2.0.25.pdf

…and a printed programmers guide:

http://www.amazon.com/exec/obidos/ASIN/ … hongrou-20

…this probably the best tutorial on the API - I haven’t read it, but I presume it’s almost identical to the famous OpenGL “RedBook” which is a superb book.

I have the same problem as zootal. I’m adapting a tutorial script I found here:http://learningwebgl.com/blog/?p=28. I’m attempring to create a lot of line primitives. The idea is to make them all different colours (and I’d love to know how to do that) but I’ll settle for just making them appear!
Apologies for dumping all the code on you, but I’m a complete beginner at WebGL and I don’t know which bits are relevant.

<html>

	<head>
		<title>Lines2</title>
		<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1">

		<script type="text/javascript" src="glMatrix-0.9.5.min.js"></script>
		<script type="text/javascript" src="Line.js"></script>
		<script type="text/javascript" src="Rand.js"></script>

		<script id="shader-fs" type="x-shader/x-fragment">
    		#ifdef GL_ES
    		precision highp float;
    		#endif

    		void main(void) {
        		gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);
    		}
		</script>

		<script id="shader-vs" type="x-shader/x-vertex">
    		attribute vec3 aVertexPosition;

    		uniform mat4 uMVMatrix;
    		uniform mat4 uPMatrix;

    		void main(void) {
        		gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0);
    		}
		</script>


		<script type="text/javascript">
	    	var auto = true;
    	    var LINES = 8000;
        	var BOUNDS = 100;
        	var FACTOR = 10.0;
        	var leader, viewer, viewing = 1, autocount = 0;
        	var centreX, centreY, centreZ;
        	var centreOX, centreOY, centreOZ;
        	var time = new Date();

        	var random = new Rand();
        	var line = new Array(LINES);
        	
    		var gl;    		
    		function initGL(canvas) {
        		try {
            		gl = canvas.getContext("experimental-webgl");
            		gl.viewportWidth = canvas.width;
            		gl.viewportHeight = canvas.height;
        		} catch (e) {
        		}
        		if (!gl) {
            		alert("Could not initialise WebGL, sorry :-(");
        		}
    		}


    		function getShader(gl, id) {
        		var shaderScript = document.getElementById(id);
        		if (!shaderScript) {
        		    return null;
        		}

        		var str = "";
        		var k = shaderScript.firstChild;
        		while (k) {
            		if (k.nodeType == 3) {
            		    str += k.textContent;
            		}
            		k = k.nextSibling;
        		}

        		var shader;
        		if (shaderScript.type == "x-shader/x-fragment") {
        		    shader = gl.createShader(gl.FRAGMENT_SHADER);
        		} else if (shaderScript.type == "x-shader/x-vertex") {
        		    shader = gl.createShader(gl.VERTEX_SHADER);
        		} else {
        		    return null;
        		}

        		gl.shaderSource(shader, str);
        		gl.compileShader(shader);

        		if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
        		    alert(gl.getShaderInfoLog(shader));
        		    return null;
        		}

        		return shader;
    		}


    		var shaderProgram;

    		function initShaders() {
    		    var fragmentShader = getShader(gl, "shader-fs");
    		    var vertexShader = getShader(gl, "shader-vs");

    		    shaderProgram = gl.createProgram();
    		    gl.attachShader(shaderProgram, vertexShader);
    		    gl.attachShader(shaderProgram, fragmentShader);
    		    gl.linkProgram(shaderProgram);

    		    if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) {
    		        alert("Could not initialise shaders");
    		    }

    		    gl.useProgram(shaderProgram);

    		    shaderProgram.vertexPositionAttribute = gl.getAttribLocation(shaderProgram, "aVertexPosition");
    		    gl.enableVertexAttribArray(shaderProgram.vertexPositionAttribute);

    		    shaderProgram.pMatrixUniform = gl.getUniformLocation(shaderProgram, "uPMatrix");
    		    shaderProgram.mvMatrixUniform = gl.getUniformLocation(shaderProgram, "uMVMatrix");
    		}


    		var mvMatrix = mat4.create();
    		var pMatrix = mat4.create();

    		function setMatrixUniforms() {
    		    gl.uniformMatrix4fv(shaderProgram.pMatrixUniform, false, pMatrix);
    		    gl.uniformMatrix4fv(shaderProgram.mvMatrixUniform, false, mvMatrix);
    		}



    		var lineVertexPositionBuffer;
	
		    function initBuffers() {
    		    lineVertexPositionBuffer = gl.createBuffer();
    		    gl.bindBuffer(gl.ARRAY_BUFFER, lineVertexPositionBuffer);
    		    var vertices = new Array(LINES * 6);
    		    
	    		var milliSeconds = ((time.getHours() * 3600) + (time.getMinutes() * 60) + time.getSeconds() * 1000) + time.getMilliseconds();

        		for (j = 0; j < milliSeconds; j++)
        		{
            		random.Get();
        		}

            	// Initialize the lines
        		for (var j = 0; j < LINES; j++)
        		{
            		line[j] = new Line();
            		line[j].positionX = (BOUNDS * random.Get());
            		line[j].positionY = (BOUNDS * random.Get());
            		line[j].positionZ = (BOUNDS * random.Get());
            		line[j].positionOX = line[j].positionX;
            		line[j].positionOY = line[j].positionY;
            		line[j].positionOZ = line[j].positionZ;
            		line[j].attraction = ((0.2 / (FACTOR * 5)) + ((0.1 / (FACTOR * 5)) * random.Get()));
            		line[j].velocity = ((1 / FACTOR) + ((0.5 / FACTOR) * random.Get()));
            		line[j].speedX = (random.Get() * line[j].velocity);
            		line[j].speedY = (random.Get() * line[j].velocity);
            		line[j].speedZ = (random.Get() * line[j].velocity);
            		line[j].red = (0.5 + ((random.Get() * 0.5)));
            		line[j].green = (0.5 + ((random.Get() * 0.5)));
            		line[j].blue = (0.5 + ((random.Get() * 0.5)));
            		line[j].NormalizeVelocity();
            		centreX += (line[j].positionOX / LINES);
            		centreY += (line[j].positionOY / LINES);
            		centreZ += (line[j].positionOZ / LINES);
            		
            		vertices[j * 6] = line[j].positionOX / 1280;
            		vertices[(j * 6) + 1] = line[j].positionOY / 1280;
            		vertices[(j * 6) + 1] = line[j].positionOZ / 1280;
            		vertices[(j * 6) + 1] = line[j].positionX;
            		vertices[(j * 6) + 1] = line[j].positionY;
            		vertices[(j * 6) + 1] = line[j].positionZ;
            	}	

        		leader = Math.round((LINES / 2) + (random.Get() * (LINES / 2)));
        		viewer = Math.round((LINES / 2) + (random.Get() * (LINES / 2)));

    		    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
    		    lineVertexPositionBuffer.itemSize = 3;
    		    lineVertexPositionBuffer.numItems = 2 * LINES;
    		}


    		function drawScene() {
    		    gl.viewport(0, 0, gl.viewportWidth, gl.viewportHeight);
    		    gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
	
		        mat4.perspective(45, gl.viewportWidth / gl.viewportHeight, 0.1, 1000.0, pMatrix);

    		    mat4.identity(mvMatrix);

    		    gl.bindBuffer(gl.ARRAY_BUFFER, lineVertexPositionBuffer);
    		    gl.vertexAttribPointer(shaderProgram.vertexPositionAttribute, lineVertexPositionBuffer.itemSize, gl.FLOAT, false, 0, 0);
    		    setMatrixUniforms();
    		    gl.drawArrays(gl.LINES, 0, lineVertexPositionBuffer.numItems);
    		}



    		function webGLStart() {
   		    	var canvas = document.getElementById("lines-canvas");
        		initGL(canvas);
        		initShaders();
        		initBuffers();

        		gl.clearColor(0.0, 0.0, 0.0, 1.0);
        		gl.enable(gl.DEPTH_TEST);

        		drawScene();
    		}
		</script>
	</head>

	<body onload="webGLStart();">
	    <canvas id="lines-canvas" style="border: none;" width="1280" height="768"></canvas>
	</body>
</html>

Thanks in advance for any insight you may have!

oops I just realised a mistake. This code should read:

            		vertices[(j * 6) + 1] = line[j].positionOY / 1280;
            		vertices[(j * 6) + 2] = line[j].positionOZ / 1280;
            		vertices[(j * 6) + 3] = line[j].positionX / 1280;
            		vertices[(j * 6) + 4] = line[j].positionY / 1280;
            		vertices[(j * 6) + 5] = line[j].positionZ / 1280;

I tried running it with the correction, it makes no difference the lines still don’t show up. :x