By the end of this lab, you will have prodded at some WebGL code a little bit, and written a tiny bit of your own. Hopefully along the way, you'll get a feel for how attributes, uniforms, varyings, and buffers interact with shaders.
All you need to work on this lab is a computer with a web browser and a text editor; I've tested this in Firefox, but it should work in any modern browser. This lab is not graded and does not need to be submitted, so you'll create your own repository from my template. Grab the code by going to https://github.com/csci480-22f/gllab_skel and clicking the green "Use this template" button. Create a repository from the template and clone it to your local system.
Open hellogl.html
in your browser of choice. You should see a white canvas on a white background. Actually, you're looking at a white triangle on a white canvas on a white background! Your first task involving code changes will be to change the triangle color so it's visible on the white background.
Open up glDemo.js
in a text editor of your choice. In glDemo.js
, there are four sections:
1. WebGL Mechanics Helper Functions
2. Source Code for Shaders
3. Triangle Code
4. GLDemo - main code
I'd like you to scroll past the first section as quickly as possible. Don't look! Okay you can look, but the stuff there is details that I'd rather you not focus on first. You will be writing code in only the second, third, and fourth sections, which hides details by using the helpers from the first section.
-1. I suggest opening the developer console of your browser of choice right now, so you will see any errors that come up in the console. In Firefox, you can access it via the menu at the top-right > Web Developer > Web Console. The A3 handout links to instructions for other browsers.
Starting at the glDemo
function, read through the code in the GLDEMO - main code
and TRIANGLE CODE
sections in the following order:
glDemo
is called first to set things up; it in turn calls the Triangle
's constructorTriangle
constructor; don't dive into the helper functions it callsglDemo.prototype.render
function is called to draw things to the screen. The main render function calls the Triangle
's render
function.Triangle.prototype.render
function, which draws the geometry to the screen. Again, don't dive into the helpers yet.In the fragment shader source code, set the fragment color to black instead of white so the triangle actually shows up on the canvas. Remember that the fourth color channel represents transparency, with 0 being transparent and 1 being opaque.
Now we'll add a uniform
that allows us to transform the triangle's geometry.
Uncomment the two lines indicated in Triangle.prototype.render
to set the matrix
javasript variable to the shaders as a uniform
called Matrix
.
Add this line at the beginning of the vertex shader source code to declare the uniform:
xxxxxxxxxx
uniform mat4 Matrix;
Change the vertex shader's main
function so it sets the vertex's position (gl_Position
) to the product of Matrix
with the Position
attribute. At this point you should be able to refresh the page and see the triangle enlarged by a factor of 1.5, with the right-most corner of the triangle cut off a bit.
Adjust the matrix's entries in glDemo.prototype.render
to shift the triangle to the left a bit so it fits in the canvas again.
Make the triangle multi-colored. We'll do this by (1) specifying a Color
attribute at each vertex; (2) passing this into a varying
parameter so it gets interpolated and passed into the fragment shader; and (3) setting the color in the fragment shader. Here are the steps you should take:
Create a VBO for color data in the Triangle
constructor function. Use the code above that creates the positionVbo
above as a template.
Modify the Triangle
's render
function to bind the VBO you just created, then link the Color
attribute to the VBO. Use the code directly above, which does this same thing for the Position
attribute, as a template. Note that you need to bind the color VBO, but you don't need to re-bind the IBO.
What is this whole if-statement situation doing? It's setting things up so the data in our buffers ends up having the right variable names in our shaders. The inputs to our vertex shaders are packed into ordered slots; we start by setting
positionAttrib
to the index of the slot for thePosition
attribute. If it's not zero, we need to alert GL to that fact;enableVertexAttribArray
says "hey let me tell you something about where to find the data for this attribute index", thenvertexAttribPointer
says "okay here's the pointer, you can interpret the data as 3-vectors of floats".
In the vertex shader source code, add a delaration for the Color
attribute underneath the delcaration for the Position
attribute.
Also in the vertex shader source code (still outside the main
method), add a declaration for a varying
parameter called vColor
:
xxxxxxxxxx
varying vec3 vColor;
In the vertex shader's main function, set the vColor
varying parameter to the value of the Color
attribute.
Declare vColor
in the fragment shader, just as you did in the vertex shader. Although the name is the same, remember that the value given to the fragment shader has been interpolated from the nearby vertices so it smoothly varies across the triangle.
Finally, assign the varying's value to gl_FragColor
. Refresh the page and you should see a much more colorful triangle!
If you have extra time: The glDemo
render
function is actually called repeatedly. This means that if you change the values in Matrix
over time, you can animate the triangle. Use javascript's Datetime.now() to make changes to the matrix
change over time and animate the triangle's shape or pose over time. Can you also change the data in the buffers (e.g., the color VBO) over time?