index previous next

Plugging in the buffer

  1. Plug in buffer into shading program
    1. set shader parameter to take values from array
    2. plug in array to the shader parameter

Recap

  1. Get webgl context from canvas
  2. Create vertex data
  3. Put data into GPU buffer
  4. Create vertex shader
  5. Create fragment shader
  6. Create shading program from vertex and fragment shader
  7. Plug in buffer into shading program
  8. Draw

We are at point 7, but before we move on let's recap what have been done.

At point 1 we have created page template with canvas on which we will diaplay our triangle.

At points 2 and 3 we have created our triangle vertex positions data and put it into GPU buffer.

At points 4-6 we have created vertex and fragment shader and made a shading program out of them. Plus our shading program is plugged into pipeline (by useProgram()), so it's (almost) ready to be useed.

All that is left, before we can draw our frist triangle is to plug in that buffer with vertices into shading program.

set shader parameter to take values from array

First let's see how our vertex shader looked like.


<script type="unknown" id="vertexShader">
attribute vec3 vertexPos;

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

As you can see, we have vertexPos variable of type attribute. We can set it to contain one value, or make it iterate over values from binded buffer. We of course want it to change its values, as triangle has three vertices, not one. So first thing to do is to tell that vertexPos should iterate over values, not have a single value.


var vertexPosLocation = gl.getAttribLocation(program, 'vertexPos')
gl.enableVertexAttribArray(vertexPosLocation)

First line gets location of vertexPos inside shading program. Every input variable in shading program has been assigned a unique number that identifies it inside shading program. When you want to do something with that variable, you use its location. It is just like id.

Next we are telling that attribute at location vertexPosLocation (ie. our vertexPos) will be taking its values from array, instead of having single value. The array is not given here anywhere, it's just saying to take values from some array that will be binded later.

plug in array to shader parameter

Now that we have said vertexPos to take its values from array, we have to plug in some array to vertexPos. And the story about state machine nature of WebGL goes again (as with clearing, or uploading data into buffer).


gl.bindBuffer(gl.ARRAY_BUFFER, triangleBuffer);
gl.vertexAttribPointer(vertexPosLocation, 3, gl.FLOAT, false, 0, 0);

First line should look familiar. It was used when we uploaded data into triangleBuffer. It says to bind given bufer to ARRAY_BUFFER. So now, everything that works on an ARRAY_BUFFER works on a triangleBuffer.

Second line says that attribute with location vertexPosLocation should take its values from buffer currently binded to ARRAY_BUFFER. Rest is description how the data looks like.

3 - because we are taking three coordinates per attribute value (which is of type vec3)

gl.FLOAT - because every coordinate is of type float

false - as we do not want to normalize data (ie. scale it to a range 0.0 - 1.0)

first 0 - there are no other values between ones we want to take (look for stride if want to know more)

second 0 - our values start without any offset in the buffer

As of now everything is set, and the only thing left is to make a draw call. Code for now:


<!DOCTYPE html> 

<html>
<head>
<meta charset="UTF-8">
<title>noniwoo webgl tutorial</title>
</head>
<body>
<canvas id="canvas1" width="640" height="480"></canvas>

<script type="unknown" id="vertexShader">
attribute vec3 vertexPos;

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


<script type="unknown" id="fragmentShader">
void main(void)
{
	gl_FragColor = vec4(0.2, 0.6, 0.2, 1.0);
}
</script>


<script>
var canvas = document.getElementById('canvas1')
if( canvas == null )
{
	throw "Could not get canvas element!"
}

var gl = canvas.getContext('webgl')
if( gl == null )
{
	gl = canvas.getContext('experimental-webgl')
	if( gl == null )
	{
		throw "Could not get webgl context"
	}
}

gl.clearColor(1.0, 1.0, 0.0, 1.0)
gl.clear(gl.COLOR_BUFFER_BIT)

var triangleVertices = new Float32Array([
	 0.0,  1.0,  0.0,  // top
	 1.0, -1.0,  0.0,  // right
	-1.0, -1.0,  0.0   // left
])

var triangleBuffer = gl.createBuffer()
gl.bindBuffer( gl.ARRAY_BUFFER, triangleBuffer )
gl.bufferData( gl.ARRAY_BUFFER, triangleVertices, gl.STATIC_DRAW )

var vertexShaderTag = document.getElementById('vertexShader')
var vertexShaderSource = vertexShaderTag.innerHTML
var vertexShader = gl.createShader(gl.VERTEX_SHADER)

gl.shaderSource(vertexShader, vertexShaderSource)
gl.compileShader(vertexShader)
if(gl.getShaderParameter(vertexShader, gl.COMPILE_STATUS) != true)
{
	throw "Vertex shader compilation failed!\n" + gl.getShaderInfoLog(vertexShader)
}


var fragmentShaderTag = document.getElementById('fragmentShader')
var fragmentShaderSource = fragmentShaderTag.innerHTML
var fragmentShader = gl.createShader(gl.FRAGMENT_SHADER)

gl.shaderSource(fragmentShader, fragmentShaderSource)
gl.compileShader(fragmentShader)
if(gl.getShaderParameter(fragmentShader, gl.COMPILE_STATUS) != true)
{
	throw "Fragment shader compilation failed!\n" + gl.getShaderInfoLog(fragmentShader)
}


var program = gl.createProgram()
gl.attachShader(program, vertexShader)
gl.attachShader(program, fragmentShader)

gl.linkProgram(program)
if(gl.getProgramParameter(program, gl.LINK_STATUS) != true)
{
	throw "Program linking failed!\n" + gl.getProgramInfoLog(program)
}

gl.useProgram(program)


var vertexPosLocation = gl.getAttribLocation(program, 'vertexPos')
gl.enableVertexAttribArray(vertexPosLocation)

gl.bindBuffer(gl.ARRAY_BUFFER, triangleBuffer);
gl.vertexAttribPointer(vertexPosLocation, 3, gl.FLOAT, false, 0, 0);

</script>

</body>
</html>

index previous next