09.reviewjeff chastine recap: shaders! a shader is a program has source code (text file) is compiled...
TRANSCRIPT
CS452/552; EE465/505
Review & Examples 2-05–15
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
Outline
Jeff Chastine
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
Examplesattribute 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
Normalized Device Coordinate System(-1, 1)
(-1, 0)
(-1, -1)
(0, 1)
(0, -1)
(0, 0)
(1, 1)
(1, 0)
(1, -1)8
JEFF CHASTINE
Coordinates of our triangle
9
(0.0f, 0.5f, 0.0f)
(0.5f, -0.5f, 0.0f)(-0.5f, -0.5f, 0.0f)
Jeff Chastine
! 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
Basic Problem
Jeff Chastine
Working with Buffers! To create a buffer ID:
// This will be the ID of the buffervar 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 Variablesattribute 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
15
gl.ARRAY_BUFFER gl.ELEMENT_ ARRAY_BUFFER
JavaScript
Vertex Shader
Buffers & Bindingattribute variablegl =
WebGLUtils.setupWebGL(canvas)
16
gl.ARRAY_BUFFER gl.ELEMENT_ ARRAY_BUFFER
JavaScript
Vertex Shader
Buffers & Bindingattribute variable
Buffer Object
gl = WebGLUtils.setupWebGL(canvas)
gl.createBuffer()
17
gl.ARRAY_BUFFER gl.ELEMENT_ ARRAY_BUFFER
JavaScript
Vertex Shader
Buffers & Bindingattribute variable
Buffer Object
gl = WebGLUtils.setupWebGL(canvas)
gl.createBuffer( )
gl.bindBuffer( )
18
gl.ARRAY_BUFFER gl.ELEMENT_ ARRAY_BUFFER
JavaScript
gl.createBuffer( )Vertex Shader
Buffers & Bindingattribute variable
Buffer Object
gl = WebGLUtils.setupWebGL(canvas)
gl.bindBuffer( )
gl.bufferData(… data … )
data
19
gl.ARRAY_BUFFER
JavaScript
Vertex Shader
Assign Buffer Object to Attribute Variable
attribute variable
Buffer Objectgl.vertexAttribPointer( )
data
20
gl.ARRAY_BUFFER
JavaScript
Vertex Shader
Assign Buffer Object to Attribute Variable
attribute variable
Buffer Objectgl.enableVertexAttribArray( )
data
Want to draw 3 triangles
Jeff Chastine
JEFF CHASTINE22
There are 3 triangles
T1
Vertex count: 3
JEFF CHASTINE23
There are 3 triangles
T2
Vertex count: 3+3
JEFF CHASTINE24
There are 3 triangles
T3
Vertex count: 3+3+3 = 9
JEFF CHASTINE25
Let’s count again…
“Real” vertex count = 6
1
2 3
4 5 6
JEFF CHASTINE26
These are used more than once!
JEFF CHASTINE
And, practically speaking…
T4
Vertex count: 3+3+3+3 = 12 vs.
6 “real” vertices
Jeff Chastine
! Inefficient ■ Takes up more memory ● Each vertex can be 48 bytes oPosition: 3*4 = 12 bytes oColor: 4*4 = 16 bytes oNormal: 3*4 = 12 bytes oTexture coordinate: 2*4 = 8 bytes
■ Takes up more processing! ● Must translate/rotate/scale/skew vertices ● Redundant computations!
Why This is a big deal
JEFF CHASTINE
Enter the Index Buffer1
2 3
4 5 6
JEFF CHASTINE30
Enter the Index Buffer0
1 2
3 4 5
JEFF CHASTINE31
Specify Triangle 10
1 2
3 4 5
{0, 1, 2}
T1
JEFF CHASTINE32
Specify Triangle 20
1 2
3 4 5
{0, 1, 2, 1, 3, 4}
T2
JEFF CHASTINE33
Specify Triangle 30
1 2
3 4 5
{0, 1, 2, 1, 3, 4, 2, 4, 5}
T3
JEFF CHASTINE34
And, practically speaking…0
1 2
3 4 5
{0, 1, 2, 1, 3, 4, 2, 4, 5, 1, 4, 2}
T4
Index buffer!
JEFF CHASTINE35
Index Buffer size0
1 2
3 4 5
{0, 1, 2, 1, 3, 4, 2, 4, 5, 1, 4, 2} = 48 bytes
T4
Jeff Chastine
! 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!36
Comparison
! Create a specialized kind of buffer!
// Ask the driver to create a buffer for usvar iBuffer = gl.createBuffer();
// Tell the driver that it's an index buffer. Instead of GL_ARRAY_BUFFERgl.bindBuffer (gl.ELEMENT_ARRAY_BUFFER, iBuffer);
// Send the indices into the buffer becausegl.bufferData (gl.ELEMENT_ARRAY_BUFFER, new Uint8Array(indices), gl.STATIC_DRAW);
37
Code
Jeff Chastine
Jeff Chastine
! 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
Code
JEFF CHASTINE39
This is what we wanted to make
JEFF CHASTINE40
This is what we made
JEFF CHASTINE41
Why?
Only 1 color per vertex
Example: ColoredCube
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 Vertex Shader
#ifdef GL_ES precision mediump float; #endif varying vec4 v_Color;
void main() { gl_FragColor = v_Color; }
ColoredCube Fragment Shader
// 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([ // Indices of the vertices 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 ]);
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; }
ColoredCube, cont.
lookAtLookAt(eye, at, up)
Angel and Shreiner: Interactive Computer Graphics 7E © Addison-Wesley 2015
! 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
The lookAt Function
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
! 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
Other Viewing APIs
Angel and Shreiner: Interactive Computer Graphics 7E © Addison-Wesley 2015
! 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
Projections and Normalization
xp = x yp = y zp = 0
Angel and Shreiner: Interactive Computer Graphics 7E © Addison-Wesley 2015
! Compute in JS file, send to vertex shader with gl.uniformMatrix4fv
! Dynamic: update in render() or shader
Computing Matrices
Angel and Shreiner: Interactive Computer Graphics 7E © Addison-Wesley 2015
perspective2.jsvar 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
Jeff Chastine
!How might we make the model matrix?
Back to The Big Picture
M
Translation matrix T Rotation matrix R1
Rotation matrix R2
Scale matrix S
S * R1 * R2 * 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
void main () { gl_Position = vPosition;
}
Originally we passed using NDCs (-1 to +1)
Jeff Chastine
A Better Vertex Shaderin 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;
}Original (local) positionNew position in NDC