Fwd: Learning WebGL lesson 2: changes from February 2011

5 views
Skip to first unread message

tomoki masuda

unread,
Feb 27, 2011, 7:43:24 PM2/27/11
to hack_...@googlegroups.com


---------- Forwarded message ----------
From: Giles Thomas <giles....@gmail.com>
Date: 2011/2/28
Subject: Learning WebGL lesson 2: changes from February 2011
To: tomoki masuda <yukipo...@gmail.com>


Compare Revisions of “WebGL Lesson 2 – Adding colour


Older: 23 August, 2010 @ 18:07Newer: 27 February, 2011 @ 20:08 [Current Revision]
Content

<span style="float: left; padding: 0px 20px 0px 0px;"><a href="http://learningwebgl.com/blog/?p=28">&lt;&lt; Lesson 1</a></span><span style="float: right; padding: 0px 20px 0px 0px;"><a href="http://learningwebgl.com/blog/?p=239">Lesson 3 &gt;&gt;</a></span><br/>
<span style="float: left; padding: 0px 20px 0px 0px;"><a href="http://learningwebgl.com/blog/?p=28">&lt;&lt; Lesson 1</a></span><span style="float: right; padding: 0px 20px 0px 0px;"><a href="http://learningwebgl.com/blog/?p=239">Lesson 3 &gt;&gt;</a></span><br/>

Welcome to my second WebGL tutorial! This time around we're going to take a look at how to get colour into the scene. It's based on <a href="http://nehe.gamedev.net/data/lessons/lesson.asp?lesson=03">number 3</a> in the NeHe OpenGL tutorials.
Welcome to my second WebGL tutorial! This time around we're going to take a look at how to get colour into the scene. It's based on <a href="http://nehe.gamedev.net/data/lessons/lesson.asp?lesson=03">number 3</a> in the NeHe OpenGL tutorials.

Here's what the lesson looks like when run on a browser that supports WebGL:
Here's what the lesson looks like when run on a browser that supports WebGL:

<img src="/lessons/lesson02/static.png" alt="A static picture of this lesson's results" />
<img src="/lessons/lesson02/static.png" alt="A static picture of this lesson's results" />

<a href="/lessons/lesson02/index.html">Click here and you'll see the live WebGL version</a>, if you've got a browser that supports it; <a href="http://learningwebgl.com/blog/?p=11">here's how to get one</a> if you don't.
<a href="/lessons/lesson02/index.html">Click here and you'll see the live WebGL version</a>, if you've got a browser that supports it; <a href="http://learningwebgl.com/blog/?p=11">here's how to get one</a> if you don't.

More on how it all works below...
More on how it all works below...

<!--more-->
<!--more-->

A quick warning: these lessons are targeted at people with a reasonable amount of programming knowledge, but no real experience in 3D graphics; the aim is to get you up and running, with a good understanding of what's going on in the code, so that you can start producing your own 3D Web pages as quickly as possible. If you haven't read <a href="http://learningwebgl.com/blog/?p=28">the first tutorial</a> already, you should do so before reading this one — here I will only explain the differences between the code for that one and the new code.
A quick warning: these lessons are targeted at people with a reasonable amount of programming knowledge, but no real experience in 3D graphics; the aim is to get you up and running, with a good understanding of what's going on in the code, so that you can start producing your own 3D Web pages as quickly as possible. If you haven't read <a href="http://learningwebgl.com/blog/?p=28">the first tutorial</a> already, you should do so before reading this one — here I will only explain the differences between the code for that one and the new code.

As before, there may be bugs and misconceptions in this tutorial. If you spot anything wrong, let me know in the comments and I'll correct it ASAP.
As before, there may be bugs and misconceptions in this tutorial. If you spot anything wrong, let me know in the comments and I'll correct it ASAP.

There are two ways you can get the code for this example; just "View Source" while you're looking at the live version, or if you use GitHub, you can clone it (and the other lessons) from <a href="http://github.com/gpjt/webgl-lessons">the repository there</a>. Either way, once you have the code, load it up in your favourite text editor and take a look.
There are two ways you can get the code for this example; just "View Source" while you're looking at the live version, or if you use GitHub, you can clone it (and the other lessons) from <a href="http://github.com/gpjt/webgl-lessons">the repository there</a>. Either way, once you have the code, load it up in your favourite text editor and take a look.

Most of it should look pretty similar from <a href="http://learningwebgl.com/blog/?p=28">the first tutorial</a>. Running through from top to bottom, we:
Most of it should look pretty similar from <a href="http://learningwebgl.com/blog/?p=28">the first tutorial</a>. Running through from top to bottom, we:

<ul>
<ul>

<li>Define vertex and fragment shaders, using HTML <code>&lt;script&gt;</code> tags with types <code>"x-shader/x-vertex"</code> and <code>"x-shader/x-fragment"</code></li>
<li>Define vertex and fragment shaders, using HTML <code>&lt;script&gt;</code> tags with types <code>"x-shader/x-vertex"</code> and <code>"x-shader/x-fragment"</code></li>

<li>Initialise a WebGL context in <code>initGL</code></li>
<li>Initialise a WebGL context in <code>initGL</code></li>

<li>Load the shaders into a WebGL program object using <code>getShader</code> and <code>initShaders</code>.</li>
<li>Load the shaders into a WebGL program object using <code>getShader</code> and <code>initShaders</code>.</li>
- <li>Define the model-view matrix <code>mvMatrix</code> along with utility functions called <code>loadIdentity</code>, <code>multMatrix</code>, <code>mvTranslate</code> for manipulating it.</li> + <li>Define the model-view matrix <code>mvMatrix</code> and the projection matrix <code>pMatrix</code>, along with the function <code>setMatrixUniforms</code> for pushing them over the JavaScript/WebGL divide so that the shaders can see them.</li>
- <li>Define the projection matrix <code>pMatrix</code>, and a <code>perspective</code> utility function for manipulating it.</li>  
- <li>Define <code>setMatrixUniforms</code> for pushing the model-view and projection matrices over the JavaScript/WebGL divide so that the shaders can see them.</li>  

<li>Load up buffers containing information about the objects in the scene using <code>initBuffers</code>
<li>Load up buffers containing information about the objects in the scene using <code>initBuffers</code>

<li>Draw the scene itself, in the appropriately-named <code>drawScene</code>.</li>
<li>Draw the scene itself, in the appropriately-named <code>drawScene</code>.</li>

<li>Define a function <code>webGLStart</code> to set everything up in the first place</li>
<li>Define a function <code>webGLStart</code> to set everything up in the first place</li>

<li>Finally, we provide the minimal HTML required to display it all.</li>
<li>Finally, we provide the minimal HTML required to display it all.</li>

</ul>
</ul>

The only things that have changed in this code from the first lesson are the shaders, <code>initBuffers</code>, and the <code>drawScene</code> function. In order to explain how the changes work, you need to know a little about the WebGL rendering pipeline. Here's a diagram:
The only things that have changed in this code from the first lesson are the shaders, <code>initBuffers</code>, and the <code>drawScene</code> function. In order to explain how the changes work, you need to know a little about the WebGL rendering pipeline. Here's a diagram:

<img id="pipeline" style="float: left; margin-right: 10px;" src="/lessons/lesson02/simple-rendering-pipeline.png" alt="Simplified diagram of the WebGL rendering pipeline" />The diagram shows, in a very simplified form, how the data passed to JavaScript functions in <code>drawScene</code> is turned into pixels displayed in the WebGL <code>canvas</code> on the screen. It only shows the steps needed to explain this lesson; we'll look at more detailed versions in future lessons.
<img id="pipeline" style="float: left; margin-right: 10px;" src="/lessons/lesson02/simple-rendering-pipeline.png" alt="Simplified diagram of the WebGL rendering pipeline" />The diagram shows, in a very simplified form, how the data passed to JavaScript functions in <code>drawScene</code> is turned into pixels displayed in the WebGL <code>canvas</code> on the screen. It only shows the steps needed to explain this lesson; we'll look at more detailed versions in future lessons.

At the highest level, the process works like this: each time you call a function like <code>drawArrays</code>, WebGL processes the data that you have previously given it in the form of attributes (like the buffers we used for vertices in lesson 1) and uniform variables (which we used for the projection and the model-view matrices), and passes it along to the vertex shader.
At the highest level, the process works like this: each time you call a function like <code>drawArrays</code>, WebGL processes the data that you have previously given it in the form of attributes (like the buffers we used for vertices in lesson 1) and uniform variables (which we used for the projection and the model-view matrices), and passes it along to the vertex shader.

It does this by calling the vertex shader once for each vertex, each time with the attributes set up appropriately for the vertex; the uniform variables are also passed in, but as their name suggests, they don't change from call to call. The vertex shader does stuff with this data — in lesson 1, it applied the projection and model-view matrices so that the vertices would all be in perspective and moved around according to our current model-view state — and puts its results into things called <em>varying variables</em>. It can output a number of varying variables; one particular one is obligatory, <code>gl_Position</code>, which contains the coordinates of the vertex once the shader has finished messing around with it.
It does this by calling the vertex shader once for each vertex, each time with the attributes set up appropriately for the vertex; the uniform variables are also passed in, but as their name suggests, they don't change from call to call. The vertex shader does stuff with this data — in lesson 1, it applied the projection and model-view matrices so that the vertices would all be in perspective and moved around according to our current model-view state — and puts its results into things called <em>varying variables</em>. It can output a number of varying variables; one particular one is obligatory, <code>gl_Position</code>, which contains the coordinates of the vertex once the shader has finished messing around with it.

Once the vertex shader is done, WebGL does the magic required to turn the 3D image from these varying variables into a 2D image, and then it calls the fragment shader once for each pixel in the image. (In some 3D graphics systems you'll hear fragment shaders referred to as pixel shaders for that reason.) Of course, this means that it's calling the fragment shader for those pixels that don't have vertices in them &mdash; that is, the ones in between the pixels on which the vertices wind up. For these, it fills in points into the positions between the vertices via a process called linear interpolation &mdash; for the vertex positions that make up our triangle, this process "fills in" the space delimited by the vertices with points to make a visible triangle. The purpose of the fragment shader is to return the colour for each of these interpolated points, and it does this in a varying variable called <code>gl_FragColor</code>.
Once the vertex shader is done, WebGL does the magic required to turn the 3D image from these varying variables into a 2D image, and then it calls the fragment shader once for each pixel in the image. (In some 3D graphics systems you'll hear fragment shaders referred to as pixel shaders for that reason.) Of course, this means that it's calling the fragment shader for those pixels that don't have vertices in them &mdash; that is, the ones in between the pixels on which the vertices wind up. For these, it fills in points into the positions between the vertices via a process called linear interpolation &mdash; for the vertex positions that make up our triangle, this process "fills in" the space delimited by the vertices with points to make a visible triangle. The purpose of the fragment shader is to return the colour for each of these interpolated points, and it does this in a varying variable called <code>gl_FragColor</code>.

Once the fragment shader is done, its results are messed around with a little more by WebGL (again, we'll get into that in a future lesson) and they are put into the <em>frame buffer</em>, which is ultimately what is displayed on the screen.
Once the fragment shader is done, its results are messed around with a little more by WebGL (again, we'll get into that in a future lesson) and they are put into the <em>frame buffer</em>, which is ultimately what is displayed on the screen.

Hopefully, by now it's clear that the most important trick that this lesson teaches is how to get the colour for the vertices from the JavaScript code all the way over to the fragment shader, when we don't have direct access from one to the other.
Hopefully, by now it's clear that the most important trick that this lesson teaches is how to get the colour for the vertices from the JavaScript code all the way over to the fragment shader, when we don't have direct access from one to the other.

The way we do this is to make use of the fact that we can pass a number of varying variables out of the vertex shader, not just the position, and can then retrieve them in the fragment shader. So, we pass the colour to the vertex shader, which can then put it straight into a varying variable which the fragment shader will pick up.
The way we do this is to make use of the fact that we can pass a number of varying variables out of the vertex shader, not just the position, and can then retrieve them in the fragment shader. So, we pass the colour to the vertex shader, which can then put it straight into a varying variable which the fragment shader will pick up.

Conveniently, this gives us gradients of colours for free. <i>All</i> varying variables set by the vertex shader are linearly interpolated when generating the fragments between vertices, not just the positions. Linear interpolation of the colour between the vertices gives us smooth gradients, like those you can see in the triangle in the image above.
Conveniently, this gives us gradients of colours for free. <i>All</i> varying variables set by the vertex shader are linearly interpolated when generating the fragments between vertices, not just the positions. Linear interpolation of the colour between the vertices gives us smooth gradients, like those you can see in the triangle in the image above.

Let's look at the code; we'll work through the changes from lesson 1. Firstly, the vertex shader. It has changed quite a lot, so here's the new code:
Let's look at the code; we'll work through the changes from lesson 1. Firstly, the vertex shader. It has changed quite a lot, so here's the new code:

<pre> attribute vec3 aVertexPosition;
<pre> attribute vec3 aVertexPosition;

attribute vec4 aVertexColor;
attribute vec4 aVertexColor;

uniform mat4 uMVMatrix;
uniform mat4 uMVMatrix;

uniform mat4 uPMatrix;
uniform mat4 uPMatrix;

varying vec4 vColor;
varying vec4 vColor;

void main(void) {
void main(void) {

gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0);
gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0);

vColor = aVertexColor;
vColor = aVertexColor;

}</pre>
}</pre>

What this is saying is that we have two attributes — inputs that vary from vertex to vertex — called <code>aVertexPosition</code> and <code>aVertexColor</code>, two non-varying uniforms called <code>uMVMatrix</code> and <code>uPMatrix</code>, and one output in the form of a varying variable called <code>vColor</code>.
What this is saying is that we have two attributes — inputs that vary from vertex to vertex — called <code>aVertexPosition</code> and <code>aVertexColor</code>, two non-varying uniforms called <code>uMVMatrix</code> and <code>uPMatrix</code>, and one output in the form of a varying variable called <code>vColor</code>.

In the body of the shader, we calculate the <code>gl_Position</code> (which is implicitly defined as a varying variable for every vertex shader) in exactly the same way as we did in lesson 1, and all we do with the colour is pass it straight through from the input attribute to the output varying variable.
In the body of the shader, we calculate the <code>gl_Position</code> (which is implicitly defined as a varying variable for every vertex shader) in exactly the same way as we did in lesson 1, and all we do with the colour is pass it straight through from the input attribute to the output varying variable.

Once this has been executed for each vertex, the interpolation is done to generate the fragments, and these are passed on to the fragment shader:
Once this has been executed for each vertex, the interpolation is done to generate the fragments, and these are passed on to the fragment shader:

<pre>
<pre>

#ifdef GL_ES
#ifdef GL_ES

precision highp float;
precision highp float;

#endif
#endif

varying vec4 vColor;
varying vec4 vColor;

void main(void) {
void main(void) {

gl_FragColor = vColor;
gl_FragColor = vColor;

}
}

</pre>
</pre>

Here, after the floating-point precision boilerplate, we take the input varying variable <code>vColor</code> containing the smoothly blended colour that has come out of the linear interpolation, and just return it immediately as the colour for this fragment &mdash; that is, for this pixel.
Here, after the floating-point precision boilerplate, we take the input varying variable <code>vColor</code> containing the smoothly blended colour that has come out of the linear interpolation, and just return it immediately as the colour for this fragment &mdash; that is, for this pixel.

That's all of the differences in the shaders between this lesson and the last. There are two other changes. The first is very small; in <code>initShaders</code> we are now getting references to two attributes rather than one; the extra lines are highlighted in red below:
That's all of the differences in the shaders between this lesson and the last. There are two other changes. The first is very small; in <code>initShaders</code> we are now getting references to two attributes rather than one; the extra lines are highlighted in red below:

<pre>
<pre>

var shaderProgram;
var shaderProgram;

function initShaders() {
function initShaders() {

var fragmentShader = getShader(gl, "shader-fs");
var fragmentShader = getShader(gl, "shader-fs");

var vertexShader = getShader(gl, "shader-vs");
var vertexShader = getShader(gl, "shader-vs");

shaderProgram = gl.createProgram();
shaderProgram = gl.createProgram();

gl.attachShader(shaderProgram, vertexShader);
gl.attachShader(shaderProgram, vertexShader);

gl.attachShader(shaderProgram, fragmentShader);
gl.attachShader(shaderProgram, fragmentShader);

gl.linkProgram(shaderProgram);
gl.linkProgram(shaderProgram);

if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) {
if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) {

alert("Could not initialise shaders");
alert("Could not initialise shaders");

}
}

gl.useProgram(shaderProgram);
gl.useProgram(shaderProgram);

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

gl.enableVertexAttribArray(shaderProgram.vertexPositionAttribute);
gl.enableVertexAttribArray(shaderProgram.vertexPositionAttribute);

<span style="color: red">shaderProgram.vertexColorAttribute = gl.getAttribLocation(shaderProgram, "aVertexColor");
<span style="color: red">shaderProgram.vertexColorAttribute = gl.getAttribLocation(shaderProgram, "aVertexColor");

gl.enableVertexAttribArray(shaderProgram.vertexColorAttribute);</span>
gl.enableVertexAttribArray(shaderProgram.vertexColorAttribute);</span>

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

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

}
}

</pre>
</pre>

This code to get the attribute locations, which we glossed over to a certain degree in the first lesson, should now be pretty clear: they are how we get a reference to the attributes that we want to pass to the vertex shader for each vertex. In lesson 1, we just got the vertex position attribute. Now, obviously enough, we get the colour attribute as well.
This code to get the attribute locations, which we glossed over to a certain degree in the first lesson, should now be pretty clear: they are how we get a reference to the attributes that we want to pass to the vertex shader for each vertex. In lesson 1, we just got the vertex position attribute. Now, obviously enough, we get the colour attribute as well.

The remainder of the changes in this lesson are in <code>initBuffers</code>, which now needs to set up buffers for both the vertex positions and the vertex colours, and in <code>drawScene</code>, which needs to pass both of these up to WebGL.
The remainder of the changes in this lesson are in <code>initBuffers</code>, which now needs to set up buffers for both the vertex positions and the vertex colours, and in <code>drawScene</code>, which needs to pass both of these up to WebGL.

Looking at <code>initBuffers</code> first, we define new global variables to hold the colour buffers for the triangle and the square:
Looking at <code>initBuffers</code> first, we define new global variables to hold the colour buffers for the triangle and the square:

<pre>
<pre>

var triangleVertexPositionBuffer;
var triangleVertexPositionBuffer;

<span style="color:red;"> var triangleVertexColorBuffer;</span>
<span style="color:red;"> var triangleVertexColorBuffer;</span>

var squareVertexPositionBuffer;
var squareVertexPositionBuffer;

<span style="color:red;"> var squareVertexColorBuffer;</span>
<span style="color:red;"> var squareVertexColorBuffer;</span>

</pre>
</pre>

Then, just after we've created the triangle's vertex position buffer, we specify its vertex colours:
Then, just after we've created the triangle's vertex position buffer, we specify its vertex colours:

<pre>
<pre>

function initBuffers() {
function initBuffers() {

triangleVertexPositionBuffer = gl.createBuffer();
triangleVertexPositionBuffer = gl.createBuffer();

gl.bindBuffer(gl.ARRAY_BUFFER, triangleVertexPositionBuffer);
gl.bindBuffer(gl.ARRAY_BUFFER, triangleVertexPositionBuffer);

var vertices = [
var vertices = [

0.0, 1.0, 0.0,
0.0, 1.0, 0.0,

-1.0, -1.0, 0.0,
-1.0, -1.0, 0.0,

1.0, -1.0, 0.0
1.0, -1.0, 0.0

];
];

gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);

triangleVertexPositionBuffer.itemSize = 3;
triangleVertexPositionBuffer.itemSize = 3;

triangleVertexPositionBuffer.numItems = 3;
triangleVertexPositionBuffer.numItems = 3;

<span style="color:red;"> triangleVertexColorBuffer = gl.createBuffer();
<span style="color:red;"> triangleVertexColorBuffer = gl.createBuffer();

gl.bindBuffer(gl.ARRAY_BUFFER, triangleVertexColorBuffer);
gl.bindBuffer(gl.ARRAY_BUFFER, triangleVertexColorBuffer);

var colors = [
var colors = [

1.0, 0.0, 0.0, 1.0,
1.0, 0.0, 0.0, 1.0,

0.0, 1.0, 0.0, 1.0,
0.0, 1.0, 0.0, 1.0,

0.0, 0.0, 1.0, 1.0,
0.0, 0.0, 1.0, 1.0,

];
];

gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(colors), gl.STATIC_DRAW);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(colors), gl.STATIC_DRAW);

triangleVertexColorBuffer.itemSize = 4;
triangleVertexColorBuffer.itemSize = 4;

triangleVertexColorBuffer.numItems = 3;</span>
triangleVertexColorBuffer.numItems = 3;</span>

</pre>
</pre>
- So, the values we provide for the the colours are in an list, one set of values for each vertex, just like the positions. However, there is one interesting difference between the two array buffers: while the vertices' positions are specified as three numbers each, for X, Y and Z coordinates, their colours are specified as four elements each &mdash; red, green, blue and alpha. Alpha, if you're not familiar with it, is a measure of opaqueness (0 is transparent, 1 totally opaque) and will be useful in later lessons. This change in the number of elements per item in the buffer necessitates a change to the <code>itemSize</code> that we associate with it. + So, the values we provide for the the colours are in a list, one set of values for each vertex, just like the positions. However, there is one interesting difference between the two array buffers: while the vertices' positions are specified as three numbers each, for X, Y and Z coordinates, their colours are specified as four elements each &mdash; red, green, blue and alpha. Alpha, if you're not familiar with it, is a measure of opaqueness (0 is transparent, 1 totally opaque) and will be useful in later lessons. This change in the number of elements per item in the buffer necessitates a change to the <code>itemSize</code> that we associate with it.

Next, we do the the equivalent code for the square; this time, we're using the same colour for every vertex, so we generate the values for the buffer using a loop:
Next, we do the the equivalent code for the square; this time, we're using the same colour for every vertex, so we generate the values for the buffer using a loop:

<pre>
<pre>

squareVertexPositionBuffer = gl.createBuffer();
squareVertexPositionBuffer = gl.createBuffer();

gl.bindBuffer(gl.ARRAY_BUFFER, squareVertexPositionBuffer);
gl.bindBuffer(gl.ARRAY_BUFFER, squareVertexPositionBuffer);

vertices = [
vertices = [

1.0, 1.0, 0.0,
1.0, 1.0, 0.0,

-1.0, 1.0, 0.0,
-1.0, 1.0, 0.0,

1.0, -1.0, 0.0,
1.0, -1.0, 0.0,

-1.0, -1.0, 0.0
-1.0, -1.0, 0.0

];
];

gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);

squareVertexPositionBuffer.itemSize = 3;
squareVertexPositionBuffer.itemSize = 3;

squareVertexPositionBuffer.numItems = 4;
squareVertexPositionBuffer.numItems = 4;

<span style="color:red;"> squareVertexColorBuffer = gl.createBuffer();
<span style="color:red;"> squareVertexColorBuffer = gl.createBuffer();

gl.bindBuffer(gl.ARRAY_BUFFER, squareVertexColorBuffer);
gl.bindBuffer(gl.ARRAY_BUFFER, squareVertexColorBuffer);

colors = []
colors = []

for (var i=0; i < 4; i++) {
for (var i=0; i < 4; i++) {

colors = colors.concat([0.5, 0.5, 1.0, 1.0]);
colors = colors.concat([0.5, 0.5, 1.0, 1.0]);

}
}

gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(colors), gl.STATIC_DRAW);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(colors), gl.STATIC_DRAW);

squareVertexColorBuffer.itemSize = 4;
squareVertexColorBuffer.itemSize = 4;

squareVertexColorBuffer.numItems = 4;</span>
squareVertexColorBuffer.numItems = 4;</span>

</pre>
</pre>

Now we have all of the data for our objects in a set of four buffers, so the next change is to make <code>drawScene</code> use the new data. The new code is in red again, and should be easy to understand:
Now we have all of the data for our objects in a set of four buffers, so the next change is to make <code>drawScene</code> use the new data. The new code is in red again, and should be easy to understand:

<pre>
<pre>

function drawScene() {
function drawScene() {

gl.viewport(0, 0, gl.viewportWidth, gl.viewportHeight);
gl.viewport(0, 0, gl.viewportWidth, gl.viewportHeight);

gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
- perspective(45, gl.viewportWidth / gl.viewportHeight, 0.1, 100.0); + mat4.perspective(45, gl.viewportWidth / gl.viewportHeight, 0.1, 100.0, pMatrix);
- loadIdentity();  
  + mat4.identity(mvMatrix);
- mvTranslate([-1.5, 0.0, -7.0]) + mat4.translate(mvMatrix, [-1.5, 0.0, -7.0]);

gl.bindBuffer(gl.ARRAY_BUFFER, triangleVertexPositionBuffer);
gl.bindBuffer(gl.ARRAY_BUFFER, triangleVertexPositionBuffer);

gl.vertexAttribPointer(shaderProgram.vertexPositionAttribute, triangleVertexPositionBuffer.itemSize, gl.FLOAT, false, 0, 0);
gl.vertexAttribPointer(shaderProgram.vertexPositionAttribute, triangleVertexPositionBuffer.itemSize, gl.FLOAT, false, 0, 0);

<span style="color:red;"> gl.bindBuffer(gl.ARRAY_BUFFER, triangleVertexColorBuffer);
<span style="color:red;"> gl.bindBuffer(gl.ARRAY_BUFFER, triangleVertexColorBuffer);

gl.vertexAttribPointer(shaderProgram.vertexColorAttribute, triangleVertexColorBuffer.itemSize, gl.FLOAT, false, 0, 0);</span>
gl.vertexAttribPointer(shaderProgram.vertexColorAttribute, triangleVertexColorBuffer.itemSize, gl.FLOAT, false, 0, 0);</span>

setMatrixUniforms();
setMatrixUniforms();

gl.drawArrays(gl.TRIANGLES, 0, triangleVertexPositionBuffer.numItems);
gl.drawArrays(gl.TRIANGLES, 0, triangleVertexPositionBuffer.numItems);
- mvTranslate([3.0, 0.0, 0.0]) + mat4.translate(mvMatrix, [3.0, 0.0, 0.0]);

gl.bindBuffer(gl.ARRAY_BUFFER, squareVertexPositionBuffer);
gl.bindBuffer(gl.ARRAY_BUFFER, squareVertexPositionBuffer);

gl.vertexAttribPointer(shaderProgram.vertexPositionAttribute, squareVertexPositionBuffer.itemSize, gl.FLOAT, false, 0, 0);
gl.vertexAttribPointer(shaderProgram.vertexPositionAttribute, squareVertexPositionBuffer.itemSize, gl.FLOAT, false, 0, 0);

<span style="color:red;"> gl.bindBuffer(gl.ARRAY_BUFFER, squareVertexColorBuffer);
<span style="color:red;"> gl.bindBuffer(gl.ARRAY_BUFFER, squareVertexColorBuffer);

gl.vertexAttribPointer(shaderProgram.vertexColorAttribute, squareVertexColorBuffer.itemSize, gl.FLOAT, false, 0, 0);</span>
gl.vertexAttribPointer(shaderProgram.vertexColorAttribute, squareVertexColorBuffer.itemSize, gl.FLOAT, false, 0, 0);</span>

setMatrixUniforms();
setMatrixUniforms();

gl.drawArrays(gl.TRIANGLE_STRIP, 0, squareVertexPositionBuffer.numItems);
gl.drawArrays(gl.TRIANGLE_STRIP, 0, squareVertexPositionBuffer.numItems);

}
}

</pre>
</pre>

And the next change... hang on, there <i>is</i> no next change! That was all that was necessary to add colour to our WebGL scene, and hopefully you are now also comfortable with the basics of shaders and how data is passed between them.
And the next change... hang on, there <i>is</i> no next change! That was all that was necessary to add colour to our WebGL scene, and hopefully you are now also comfortable with the basics of shaders and how data is passed between them.

That's it for this lesson &mdash; hopefully it was easier going than the first! If you have any questions, comments, or corrections, please do leave a comment below.
That's it for this lesson &mdash; hopefully it was easier going than the first! If you have any questions, comments, or corrections, please do leave a comment below.

Next time, <a href="http://learningwebgl.com/blog/?p=239">we'll add code to animate the scene by rotating the triangle and the square</a>.
Next time, <a href="http://learningwebgl.com/blog/?p=239">we'll add code to animate the scene by rotating the triangle and the square</a>.

<span style="float: left; padding: 0px 20px 0px 0px;"><a href="http://learningwebgl.com/blog/?p=28">&lt;&lt; Lesson 1</a></span><span style="float: right; padding: 0px 20px 0px 0px;"><a href="http://learningwebgl.com/blog/?p=239">Lesson 3 &gt;&gt;</a></span><br/>
<span style="float: left; padding: 0px 20px 0px 0px;"><a href="http://learningwebgl.com/blog/?p=28">&lt;&lt; Lesson 1</a></span><span style="float: right; padding: 0px 20px 0px 0px;"><a href="http://learningwebgl.com/blog/?p=239">Lesson 3 &gt;&gt;</a></span><br/>
- <em>Acknowledgments: working out exactly what was going on in the rendering pipeline was made much easier by reference to the <a href="http://www.amazon.com/OpenGL-ES-2-0-Programming-Guide/dp/0321502795/ref=sr_1_1?ie=UTF8&s=books&qid=1255637843&sr=8-1">OpenGL ES 2.0 Programming Guide</a>, which Jim Pick recommended on his <a href="http://euclid.jimpick.com/">WebGL blog</a>. As ever, I'm deeply in debt to <a href="http://nehe.gamedev.net/">NeHe</a> for his <a href="http://nehe.gamedev.net/data/lessons/lesson.asp?lesson=03">OpenGL tutorial</a> for the script for this lesson.</em> + <em>Acknowledgments: working out exactly what was going on in the rendering pipeline was made much easier by reference to the <a href="http://www.amazon.com/dp/0321502795?tag=lewe-20&camp=14573&creative=327641&linkCode=as1&creativeASIN=0321502795&adid=1EX6T4SCR6T8P7D5P7WC&">OpenGL ES 2.0 Programming Guide</a>, which Jim Pick recommended on his <a href="http://euclid.jimpick.com/">WebGL blog</a>. As ever, I'm deeply in debt to <a href="http://nehe.gamedev.net/">NeHe</a> for his <a href="http://nehe.gamedev.net/data/lessons/lesson.asp?lesson=03">OpenGL tutorial</a> for the script for this lesson.</em>


Reply all
Reply to author
Forward
0 new messages