CS452/552; EE465/505 Review & Examples 2-05 15
Outline Review and Examples:! Shaders, Buffers & Binding! Example: Draw 3 Triangles Vertex lists; gl.drawarrays( ) Edge lists: gl.drawelements( )! Example: Draw Cube with solid faces! Example: Perspective Projection Read: Angel, Chapter 5 Lab2: use ASDW to move a 2D shape around
Recap: Shaders! A shader is a program Has source code (text file) Is compiled into a program We get back IDs, which are just ints!! Vertex shader Changes the position of a vertex (trans/rot/skew) May determine color of the vertex! Fragment shader Determines the color of a pixel Uses lighting, materials, normals, etc Jeff Chastine
Making a Shader Program! Compile a vertex shader (get an ID)! Compile a fragment shader (get an ID)! Check for compilation errors! Link those two shaders together (get an ID) First, attach to a shader program Keep that ID! Use that ID before you render triangles Can have separate shaders for each model Jeff Chastine
Examples attribute vec4 s_vposition; void main () { // The value of s_vposition should be // between -1.0 and +1.0 gl_position = s_vposition; } ------------------------------------------ varying vec4 s_vcolor; void main () { // No matter what, color the pixel red! fcolor = vec4 (1.0, 0.0, 0.0, 1.0); } Jeff Chastine
Compiling Vertex and Fragment Shaders! gl.createshader (<type>) Creates an ID (an unsigned int) for a shader var vertshdr = gl.createshader(gl.vertex_shader);! gl.shadersource(<id>, <srccode>) Binds the source code to the shader Happens before compilation! gl.compileshader (<id>) Used to make part of the shader program Jeff Chastine
Creating/Linking/Using the Shader! var program = gl.createprogram() Returns an ID keep this for the life of the program! gl.attachshader (<prog ID>, <shader ID>) Do this for both the vertex and fragment shaders! gl.linkprogram(<prog ID>) Actually makes the shader program! gl.useprogram(<prog ID>) Use this shader when you re about to draw triangles Jeff Chastine
(-1, 1) (0, 1) Normalized Device Coordinate System (1, 1) (-1, 0) (0, 0) (1, 0) (-1, -1) JEFF CHASTINE (0, -1) (1, -1) 8
Coordinates of our triangle (0.0f, 0.5f, 0.0f) (-0.5f, -0.5f, 0.0f) (0.5f, -0.5f, 0.0f) JEFF CHASTINE 9
Basic Problem! Get the geometry and color to the GPU! Typically also need a normal and texture coordinate for each vertex!! Ask WebGL to create a buffer object This is just a chunk of memory (e.g. array) Located on the GPU (probably) 10 Jeff Chastine
Working with Buffers! To create a buffer ID: // This will be the ID of the buffer var vertexbuffer = gl.createbuffer();! To set this buffer as the active one and specify which buffer we re referring to: gl.bindbuffer(gl.array_buffer, vertexbuffer); Notes: That buffer is now bound and active! Any drawing will come from that buffer Any loading goes into that buffer Jeff Chastine
Two Approaches to Loading the Buffer with Data! One-shot call to load the buffer with data: gl.bufferdata(gl.array_buffer,data,gl.static_draw);! Other drawing types gl.x_y: X STREAM for infrequent use and changes STATIC for frequent use and infrequent change DYNAMIC for frequent use and frequent change Y could be DRAW, READ or COPY Jeff Chastine
Accessing Variables attribute vec4 a_position;//from the application attribute vec4 a_color; //from the application varying vec4 v_color; //to the fragment shader void main () { v_color = a_color; gl_position = a_position; } ----------------------------------------------- varying vec4 v_color; // from the vertex shader void main () { gl_fragcolor = v_color; // the final color } Jeff Chastine
Accessing Variables! Get the ID with gl.getattriblocation (shaderprogramid, variable name in shader) var posid = gl.getattriblocation( shaderprogramid, a_position"); var colid = gl.getattriblocation( shaderprogramid, a_color );! Enable those variables (once) gl.enablevertexattribarray(posid); gl.enablevertexattribarray(colid);! Tell those variables where to find their info in the currently bound buffer (once) gl.vertexattribpointer(posid, 3, gl.float, false, 0, 0); gl.vertexattribpointer(colid, 4, gl.float, false, 0, 0);! Similar calls for uniform variables Jeff Chastine
Buffers & Binding JavaScript gl = WebGLUtils.setup WebGL(canvas) gl.array_buffer gl.element_ ARRAY_BUFFER attribute variable Vertex Shader 15
Buffers & Binding JavaScript gl = WebGLUtils.setup WebGL(canvas) gl.createbuffer() gl.array_buffer Buffer Object gl.element_ ARRAY_BUFFER attribute variable Vertex Shader 16
Buffers & Binding JavaScript gl = WebGLUtils.setup WebGL(canvas) gl.createbuffer( ) gl.bindbuffer( ) gl.array_buffer Buffer Object gl.element_ ARRAY_BUFFER attribute variable Vertex Shader 17
Buffers & Binding JavaScript gl = WebGLUtils.setup WebGL(canvas) gl.createbuffer( ) gl.bindbuffer( ) gl.bufferdata( data ) gl.array_buffer gl.element_ ARRAY_BUFFER Buffer Object data attribute variable Vertex Shader 18
Assign Buffer Object to Attribute Variable JavaScript gl.array_buffer attribute variable gl.vertexattribp ointer( ) Buffer Object Vertex Shader data 19
Assign Buffer Object to Attribute Variable JavaScript gl.array_buffer attribute variable gl.enablevertex AttribArray( ) Buffer Object Vertex Shader data 20
Want to draw 3 triangles Jeff Chastine
There are 3 triangles T1 Vertex count: 3 JEFF CHASTINE 22
There are 3 triangles T2 Vertex count: 3+3 JEFF CHASTINE 23
There are 3 triangles T3 Vertex count: 3+3+3 = 9 JEFF CHASTINE 24
Let s count again 1 2 3 4 5 6 Real vertex count = 6 JEFF CHASTINE 25
These are used more than once! JEFF CHASTINE 26
And, practically speaking T4 Vertex count: 3+3+3+3 = 12 vs. 6 real vertices JEFF CHASTINE
Why This is a big deal! Inefficient Takes up more memory Each vertex can be 48 bytes o Position: 3*4 = 12 bytes o Color: 4*4 = 16 bytes o Normal: 3*4 = 12 bytes o Texture coordinate: 2*4 = 8 bytes Takes up more processing! Must translate/rotate/scale/skew vertices Redundant computations! Jeff Chastine
Enter the Index Buffer 1 2 3 4 5 6 JEFF CHASTINE
Enter the Index Buffer 0 1 2 3 4 5 JEFF CHASTINE 30
Specify Triangle 1 0 T1 1 2 3 4 5 {0, 1, 2} JEFF CHASTINE 31
Specify Triangle 2 0 1 2 T2 3 4 5 {0, 1, 2, 1, 3, 4} JEFF CHASTINE 32
Specify Triangle 3 0 1 2 T3 3 4 5 {0, 1, 2, 1, 3, 4, 2, 4, 5} JEFF CHASTINE 33
And, practically speaking 0 1 2 T4 3 4 5 Index buffer! {0, 1, 2, 1, 3, 4, 2, 4, 5, 1, 4, 2} JEFF CHASTINE 34
Index Buffer size 0 1 2 T4 3 4 5 {0, 1, 2, 1, 3, 4, 2, 4, 5, 1, 4, 2} = 48 bytes JEFF CHASTINE 35
Comparison! Without Index Buffers Each vertex takes up 48 bytes Each triangle has 3 vertices 4 triangles have 12 vertices Total size = 4 triangles * 3 vertices * 48 bytes each = 576 bytes! With Index Buffers Each vertex takes up 48 bytes Have only 6 of them Index buffer is 48 bytes Total size = 6 vertices * 48 bytes each + 48 bytes = 336 bytes! In this case, ½ the number of vertices to process! Jeff Chastine 36
Code! Create a specialized kind of buffer! // Ask the driver to create a buffer for us var ibuffer = gl.createbuffer(); // Tell the driver that it's an index buffer. Instead of GL_ARRAY_BUFFER gl.bindbuffer (gl.element_array_buffer, ibuffer); // Send the indices into the buffer because gl.bufferdata (gl.element_array_buffer, new Uint8Array(indices), gl.static_draw); Jeff Chastine 37
Code! To render the triangles: Don t use gldrawarrays (GL_TRIANGLES, 0, NUM_VERTICES); This is the non-index-buffer way! // Use both the vertex buffer and index buffer! gl.drawelements(gl.triangles, NUM_INDICES, gl.unsigned_byte, 0); 38 Jeff Chastine
This is what we wanted to make JEFF CHASTINE 39
This is what we made JEFF CHASTINE 40
Why? Only 1 color per vertex JEFF CHASTINE 41
Example: ColoredCube
ColoredCube Vertex Shader attribute vec4 a_position; attribute vec4 a_color; uniform mat4 u_mvpmatrix; varying vec4 v_color; void main() { gl_position = u_mvpmatrix * a_position; v_color = a_color; }
ColoredCube Fragment Shader #ifdef GL_ES precision mediump float; #endif varying vec4 v_color; void main() { } gl_fragcolor = v_color;
ColoredCube, cont. // Get the storage location of u_mvpmatrix var u_mvpmatrix = gl.getuniformlocation(gl.program, 'u_mvpmatrix'); // Set the eye point and the viewing volume var mvpmatrix = new Matrix4(); mvpmatrix.setperspective(30, 1, 1, 100); mvpmatrix.lookat(3, 3, 7, 0, 0, 0, 0, 1, 0); // Pass the model view projection matrix to u_mvpmatrix gl.uniformmatrix4fv(u_mvpmatrix, false, mvpmatrix.elements);
ColoredCube, cont. var colors = new Float32Array([ // Colors 0.4, 0.4, 1.0, 0.4, 0.4, 1.0, 0.4, 0.4, 1.0, 0.4, 0.4, 1.0, // v0-v1-v2-v3 front(blue) 0.4, 1.0, 0.4, 0.4, 1.0, 0.4, 0.4, 1.0, 0.4, 0.4, 1.0, 0.4, // v0-v3-v4-v5 right(green) 1.0, 0.4, 0.4, 1.0, 0.4, 0.4, 1.0, 0.4, 0.4, 1.0, 0.4, 0.4, // v0-v5-v6-v1 up(red) 1.0, 1.0, 0.4, 1.0, 1.0, 0.4, 1.0, 1.0, 0.4, 1.0, 1.0, 0.4, // v1-v6-v7-v2 left 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, // v7-v4-v3-v2 down 0.4, 1.0, 1.0, 0.4, 1.0, 1.0, 0.4, 1.0, 1.0, 0.4, 1.0, 1.0 // v4-v7-v6-v5 back ]); var indices = new Uint8Array([ 0, 1, 2, 0, 2, 3, // front 4, 5, 6, 4, 6, 7, // right 8, 9,10, 8,10,11, // up 12,13,14, 12,14,15, // left 16,17,18, 16,18,19, // down 20,21,22, 20,22,23 // back ]); // Indices of the vertices
ColoredCube, cont. // Create a buffer object var indexbuffer = gl.createbuffer() // Write the vertex coordinates and color to the buffer object if (!initarraybuffer(gl, vertices, 3, gl.float, a_position')) return -1; if (!initarraybuffer(gl, colors, 3, gl.float, 'a_color'))return -1; // Write the indices to the buffer object gl.bindbuffer(gl.element_array_buffer, indexbuffer); gl.bufferdata(gl.element_array_buffer, indices, gl.static_draw); return indices.length;
ColoredCube, cont. function initarraybuffer(gl, data, num, type, attribute) { var buffer = gl.createbuffer(); // Create a buffer object // Write data into the buffer object gl.bindbuffer(gl.array_buffer, buffer); gl.bufferdata(gl.array_buffer, data, gl.static_draw); // Assign the buffer object to the attribute variable var a_attribute = gl.getattriblocation(gl.program, attribute); gl.vertexattribpointer(a_attribute, num, type, false, 0, 0); // Enable the assignment of the buffer object to the attribute variable gl.enablevertexattribarray(a_attribute); } return true;
lookat LookAt(eye, at, up) Angel and Shreiner: Interactive Computer Graphics 7E Addison-Wesley 2015
The lookat Function! The GLU library contained the function glulookat to form the required modelview matrix through a simple interface! Note the need for setting an up direction! Replaced by lookat() in MV.js Can concatenate with modeling transformations! Example: isometric view of cube aligned with axes var eye = vec3(1.0, 1.0, 1.0); var at = vec3(0.0, 0.0, 0.0); var up = vec3(0.0, 1.0, 0.0); var mv = LookAt(eye, at, up); Angel and Shreiner: Interactive Computer Graphics 7E Addison-Wesley 2015
Other Viewing APIs! The LookAt function is only one possible API for positioning the camera! Others include View reference point, view plane normal, view up (PHIGS, GKS-3D) Yaw, pitch, roll Elevation, azimuth, twist Direction angles Angel and Shreiner: Interactive Computer Graphics 7E Addison-Wesley 2015
Projections and Normalization! The default projection in the eye (camera) frame is orthogonal! For points within the default view volume! Most graphics systems use view normalization All other views are converted to the default view by transformations that determine the projection matrix Allows use of the same pipeline for all views x p = x y p = y z p = 0 Angel and Shreiner: Interactive Computer Graphics 7E Addison-Wesley 2015
Computing Matrices! Compute in JS file, send to vertex shader with gl.uniformmatrix4fv! Dynamic: update in render() or shader Angel and Shreiner: Interactive Computer Graphics 7E Addison-Wesley 2015
perspective2.js var render = function(){ gl.clear( gl.color_buffer_bit gl.depth_buffer_bit); eye = vec3(radius*math.sin(theta)*math.cos(phi), radius*math.sin(theta)*math.sin(phi), radius*math.cos(theta)); modelviewmatrix = lookat(eye, at, up); projectionmatrix = perspective(fovy, aspect, near, far); gl.uniformmatrix4fv( modelviewmatrixloc, false, flatten(modelviewmatrix) ); gl.uniformmatrix4fv( projectionmatrixloc, false, flatten(projectionmatrix) ); gl.drawarrays( gl.triangles, 0, NumVertices ); requestanimframe(render); } Angel and Shreiner: Interactive Computer Graphics 7E Addison-Wesley 2015
Back to The Big Picture! How might we make the model matrix? M Translation matrix T Rotation matrix R 1 Rotation matrix R 2 Scale matrix S S * R 1 * R 2 * T = M Jeff Chastine
The (P)rojection Matrix! Projects from 3D into 2D! Two kinds: Orthographic: depth doesn t matter, parallel remains parallel Perspective: Used to give depth to the scene (a vanishing point)! End result: Normalized Device Coordinates (NDCs between -1.0 and +1.0) Jeff Chastine
Orthographic vs. Perspective Jeff Chastine
An Old Vertex Shader in vec4 vposition; // The vertex in NDC Originally we passed using NDCs (-1 to +1) void main () { gl_position = vposition; } Jeff Chastine
A Better Vertex Shader in vec4 vposition; // The vertex in the local coordinate system uniform mat4 mm; // The matrix for the pose of the model uniform mat4 mv; // The matrix for the pose of the camera uniform mat4 mp; // The projection matrix (perspective) void main () { gl_position = mp*mv*mm*vposition; } New position in NDC Original (local) position Jeff Chastine