A Group Project
- Build a html file
- Start with this file, called HW5.html (Either save as or view source, the program produces a blank screen if you click on it)
- Note including the javascript files for the project has been commented out, you will need to put these back, but I didn't want an error on load.
-
<html lang="en"> <head> <script id="vertex-shader" type="x-shader/x-vertex" > // vertex shader goes here </script> <script id="fragment-shader" type="x-shader/x-fragment"> // fragment shader goes here </script> <script src="https://mirkwood.cs.edinboro.edu/~bennett/GraphicsCode/Common/webgl-utils.js" ></script> <script src="https://mirkwood.cs.edinboro.edu/~bennett/GraphicsCode/Common/initShaders.js"></script> <script src="https://mirkwood.cs.edinboro.edu/~bennett/GraphicsCode/Common/MV.js"></script> <!-- <script type="text/javascript" src="Widget.js"></script> <script type="text/javascript" src="Program.js"></script> <script type="text/javascript" src="GLCanvas.js"></script> --> <body> <main> <script> 'use strict' var canvas = new Canvas(500, 500,Keypress,"vertex-shader", "fragment-shader"); var Objects = []; MakeItems(); Display(); </script> </main> </body> </html>
-
- Add a vertex shader in the space provided in the html file
attribute vec4 vPosition; void main() { float d = 0.2; // translate matrix // note the matrix appears to be transposed, it is not. // GLSL is column major, not row major mat4 translate = mat4( vec4(1.0, 0.0, 0.0, 0.0), // first column vec4(0.0, 1.0, 0.0, 0.0), // second column vec4(0.0, 0.0, 1.0, 0.0), // third column vec4(0.0, 0.25, 0.75, 1.0) // last column ); // pinhole camera projection matrix. mat4 project = mat4( vec4(1.0, 0.0, 0.0, 0.0), vec4(0.0, 1.0, 0.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0/d), vec4(0.0, 0.0, 0.0, 0.0) ); // apply the transformations gl_Position = project * translate * vPosition; }- This vertex shader performs a translation and a pinhole camera projection.
- Note the matrices might look wrong.
- This is not the case.
- WebGL uses Column Major matrices
- The lines that look like rows are actually columns.
- This constantly messes me up.
- Note GLSL's support for matrix-matrix and matrix-vector multiplication.
- You need to include the .0 in all floating point numbers
- If it is not there, GLSL's compiler will assume it is an integer
- And there is not built in coercion, so it will be a syntax error.
- Add the fragment shader in the space provided in the html file
-
void main(){ gl_FragColor = vec4 (1.0, 0.0, 1.0, 1.0) ; }
-
- Build the canvas
- For this exercise I have rethought my implementation of a canvas.
- This is closer to the HTML5 canvas
- It contains the code to setup and maintain the canvas.
- We will build on this as the semester goes along.
- In a file called GLCanvas.js
- Build a constructor
-
class Canvas { constructor (width, height, Keypress, vertShader, fragShader) { this.height = height; this.width = width; this.MakeCanvas(); this.canvas.addEventListener("keypress", Keypress); this.SetupGL(); this.MakeShaders(vertShader, fragShader); this.Init(); } - The constructor takes a width, height, and the keypress handler.
- It calls four auxiliary routines.
- I am sure you already understand the code in this function.
-
- MakeCanvas
- This function builds a canvas and places it in the document.
- This allows us to build multiple canvases if we want them.
- I really am not concerned with you understanding the code in this function.
-
MakeCanvas() { if (this.width == undefined || this.width < 0) { this.width = 300; } if (this.height == undefined || this.height < 0) { this.height = 300; } this.canvas = document.createElement('canvas') this.canvas.tabIndex=0; this.canvas.height = this.height; this.canvas.width = this.width; this.canvas.style="border:1px solid #000000;" document.body.appendChild(this.canvas); }
- SetupGL
- This code performs the necessary steps to setup the WebGL context for this canvas.
- I really don't you to know the code in this function either.
- It uses functions from the library files in Common
-
SetupGL() { this.gl = WebGLUtils.setupWebGL(this.canvas); if (!this.gl) { alert ("WebGL isn't available"); return; } this.gl.getExtension('OES_standard_derivatives'); }
- MakeShaders
- This code compiles the shaders and sends them to the GPU
- You need this code.
- It uses functions from the library files in Common
-
MakeShaders(vertShader, fragShader) { this.program = initShaders(this.gl, vertShader,fragShader); this.gl.useProgram(this.program); }
- Init
- This function performs context initialization.
- The first line sets the color to clear the frame buffer to when a clear is called.
- In this case, it clears to white.
- The second line establishes the size of the viewport
- This is the "photographic plate" from the pinhole camera.
- We set the distance in the vertex shader (d)
- This is really just the size, in pixels, of the frame we are looking through.
-
Init() { this.gl.clearColor(1.0, 1.0, 1.0, 1.0); this.gl.viewport(0,0, this.width, this.height); }
- Add a few utility functions
- We will need the program, so write Program to return it
-
Program() { return this.program; }
-
- We will need access to the context, so write function GL
-
GL() { return this.gl; }
-
- Finally we will need to clear the canvas, so add Clear
- This sends a message to the GPU to clear the frame buffer.
-
Clear() { this.gl.clear(this.gl.COLOR_BUFFER_BIT); } } // closing of class
- Your final file should be close to GLCanvas.js
- We will need the program, so write Program to return it
- For this exercise I have rethought my implementation of a canvas.
- Build a Widget class in Widget.js.
- In this case a widget is a thing we will display
- To build one, we need to know
- The context it will be drawn in (gl)
- The GLSL program that will draw it (program)
- The name of the to program will use to access the buffer holding the data for the widget. (posName)
- A list of edges to draw.
- To build one, we need to know
- Make a constructor
-
class Widget { constructor(gl, program, posName, edges) { this.visible = true; this.size = edges.length; this.SetupVBO(gl, program, posName, edges); } - The visible member variable allows us to turn display of the object on and off.
- We will need to preserve the number of edges to draw for future use.
- The function SetupVBO is somewhat complex and will be discussed next.
-
- SetupVBO
- We will discuss this function in class in real detail.
- I don't expect you to master it here
- But I do expect you to look it over.
-
SetupVBO(gl, program, posName, edges) { this.vbuf = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER, this.vbuf); this.pos = gl.getAttribLocation(program, posName); gl.bufferData(gl.ARRAY_BUFFER,flatten(edges),gl.STATIC_DRAW); } - Line 1 creates a buffer on the GPU.
- This is a place to store information
- Line 2 makes the buffer active
- There is only one active buffer at a time.
- The active buffer is where all action takes place.
- Line 3 associates the data we are about to write with the variable in the program
- If you look at the vertex shader, this is the attribute "vPosition"
- this stands for vertex position.
- which is what we are going to store in the buffer.
- Line 4 tells the GPU that the thing we are sending over consists of three floating point numbers at each location.
- This is equivalent to a struct with three floats.
- Line 5 enables storage for the attribute we are creating
- We are only sending vertexes
- But we could send an array of colors for each vertex.
- Line 6 transfers the data (stored in edges) to the GPU
- Build the member functions to work with visibility
-
Show() { this.visible = true; } Hide() { this.visible = false; } Visible() { return this.visible; }
-
- Add a Display function
- This takes the context we will be drawing in.
-
Display(gl) { if (this.visible) { gl.bindBuffer(gl.ARRAY_BUFFER, this.vbuf); gl.vertexAttribPointer(this.pos, 3, gl.FLOAT, false, 0, 0); gl.enableVertexAttribArray(this.pos); gl.drawArrays(gl.LINE_LOOP, 0, this.size); } } } // closing of class. - Line 1 makes the buffer active again, We might have used another buffer between when we created this buffer and when we now.
- Line 2 makes the attribute active.
- Line 3 tells the GPU to draw the figure.
- Your final file should be close to Widget.js
- In this case a widget is a thing we will display
- Finally, download the driver routines from the file called
Program.js
- The first 28 lines of the file set up the vertexes for the two shapes we will draw.
- MakeItems builds the scene by creating instances of the Widget class with the different vertex sets created above.
- The other functions should be familiar, or easy to understand.