CS460 Computer Graphics - University of Massachusetts Boston
Old Assignment 4
will be updated!
Due Monday 10/2!
Quiz 4 Due Today!!
<html>
<head>
<meta content="text/html;charset=utf-8" http-equiv="Content-Type">
<meta content="utf-8" http-equiv="encoding">
<title>Vanilla WebGL!</title>
<style>
html, body {
background-color:#000;
margin: 0;
padding: 0;
height: 100%;
overflow: hidden !important;
background-image: url(https://cs460.org/gfx/bg.gif);
background-repeat: no-repeat;
background-size: 100% 100%;
}
#c {
width: 100%;
height: 100%;
}
#scoreboard {
position: absolute;
top: 10px;
right: 10px;
};
</style>
</head>
<script type="text/javascript" src="https://cs460.org/js/glmatrix.js"></script>
<script id="vertexshader" type="glsl">
attribute vec3 a_position;
uniform vec3 u_offset;
void main(void) {
vec3 final_position = a_position;
final_position.x += u_offset.x;
final_position.y += u_offset.y;
final_position.z += u_offset.z;
gl_Position = vec4( final_position, 1.);
}
</script>
<script id="fragmentshader" type="glsl">
precision mediump float;
uniform vec4 u_color;
void main(void) {
gl_FragColor = u_color;
}
</script>
<script>
var c, gl;
var v_shader, f_shader, shaderprogram;
var vertices, indices, v_buffer, i_buffer;
var step_x = 0.0;
var step_y = 0.0;
var obstacle_factor = 3; // Hint for the bonus!
var direction_y = 0;
var direction_x = 0;
window.onload = function() {
//************************************************************//
//
// INITIALIZE WEBGL
//
c = document.getElementById( 'c' ); // setup canvas
c.width = window.innerWidth;
c.height = window.innerHeight;
gl = c.getContext( 'webgl' ); // setup GL context
gl.viewport(0, 0, c.width, c.height );
//************************************************************//
//
// SHADERS
//
v_shader = gl.createShader( gl.VERTEX_SHADER );
f_shader = gl.createShader( gl.FRAGMENT_SHADER );
// compile vertex shader
gl.shaderSource( v_shader, document.getElementById( 'vertexshader' ).innerText );
gl.compileShader( v_shader );
if (!gl.getShaderParameter( v_shader, gl.COMPILE_STATUS)) {
console.log(gl.getShaderInfoLog( v_shader ));
}
// compile fragment shader
gl.shaderSource( f_shader, document.getElementById( 'fragmentshader' ).innerText );
gl.compileShader( f_shader );
if (!gl.getShaderParameter( f_shader, gl.COMPILE_STATUS)) {
console.log(gl.getShaderInfoLog( f_shader ));
}
// attach and link the shaders
shaderprogram = gl.createProgram();
gl.attachShader( shaderprogram, v_shader );
gl.attachShader( shaderprogram, f_shader );
gl.linkProgram( shaderprogram );
gl.useProgram( shaderprogram );
// create multiple objects
objects = [];
objects.push( createAirplane());
objects.push( createObstacle());
objects.push( createObstacle());
objects.push( createObstacle());
objects.push( createObstacle());
objects.push( createObstacle());
objects.push( createObstacle());
objects.push( createObstacle());
objects.push( createObstacle());
objects.push( createObstacle());
animate();
};
function createAirplane() {
//
// Part 1 Starts
//
var vertices;
var v_buffer;
//
// Part 1 Ends
//
var offset = [0.,0.,0.];
var color = [0.,0.,0.,1.];
//
// Bonus Part 3!
//
return ['airplane', v_buffer, vertices, offset, color, gl.TRIANGLES];
}
function createObstacle() {
var vertices = new Float32Array( [ 0.0, 0.0, 0.0 ]);
var v_buffer = gl.createBuffer(); // create
gl.bindBuffer( gl.ARRAY_BUFFER, v_buffer ); // bind
gl.bufferData( gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW ); // put data in
gl.bindBuffer( gl.ARRAY_BUFFER, null ); // unbind
//
// Part 2 Starts
//
var offset = [0., 0., 0.];
//
// Part 2 Ends
//
var color = [Math.random(),Math.random(),Math.random(),1.];
return ['obstacle', v_buffer, vertices, offset, color, gl.POINTS];
}
//
// Part 3 Starts (no coding required, just explanations in PDF)
//
function calculateBoundingBox(vertices, offset) {
var minx = 1000;
var maxx = -1000;
var miny = 1000;
var maxy = -1000;
var minz = 1000;
var maxz = -1000;
for (var v=0; v<vertices.length; v+=3) {
var currentx = vertices[v] + offset[0];
var currenty = vertices[v+1] + offset[1];
var currentz = vertices[v+2] + offset[2];
minx = Math.min( minx, currentx );
miny = Math.min( miny, currenty );
minz = Math.min( minz, currentz );
maxx = Math.max( maxx, currentx );
maxy = Math.max( maxy, currenty );
maxz = Math.max( maxz, currentz );
}
return [minx, maxx, miny, maxy, minz, maxz];
}
function detectCollision(bbox, point) {
var collision = false;
if (point[0] >= bbox[0] && point[0] <= bbox[1]) {
if (point[1] >= bbox[2] && point[1] <= bbox[3]) {
if (point[2] >= bbox[4] && point[2] <= bbox[5]) {
collision = true;
}
}
}
return collision;
}
//
// Part 3 Ends
//
//
// Part 4 Starts
//
window.onkeyup = function(e) {
if ( e.keyCode == 38 ) {
// player pressed up
} else if (e.keyCode == 40 ) {
// player pressed down
} else if (e.keyCode == 37 ) {
// player pressed left
} else if (e.keyCode == 39 ) {
// player pressed right
}
};
//
// Part 4 Ends
//
var framecounter = 0;
function animate() {
framecounter += 1;
if (framecounter > 150) {
// roughly every five seconds with 30 FPS
// update score
document.getElementById('scoreboard').innerHTML = parseInt(document.getElementById('scoreboard').innerHTML) + 100;
//
// Bonus Part 2!
//
framecounter = 0;
}
gl.clearColor( 0., 0., 0., 0.)
gl.clear( gl.COLOR_BUFFER_BIT );
for( var o = 0; o < objects.length; o++ ) {
var current_objecttype = objects[o][0];
var current_v_buffer = objects[o][1];
var current_vertices = objects[o][2];
var current_offset = objects[o][3];
var current_color = objects[o][4];
var current_drawtype = objects[o][5];
var current_v_count = current_vertices.length;
if (current_objecttype == 'airplane') {
// update offsets
if ( current_offset[0] <= -1. ) {
// bumped into left end of screen
direction_x = 1;
} else if ( current_offset[0] >= 1. ) {
// bumped into right end of screen
direction_x = -1;
}
current_offset[0] += direction_x*step_x;
if ( current_offset[1] <= -1. ) {
// bumped into left end of screen
direction_y = 1;
} else if ( current_offset[1] >= 1. ) {
// bumped into right end of screen
direction_y = -1;
}
current_offset[1] += direction_y*step_y;
// get the bounding box of this airplane
var bbox_plane = calculateBoundingBox( current_vertices, current_offset);
} else if (current_objecttype == 'obstacle') {
//
// Bonus Part 1!
//
// collision detection using the bounding box of this airplane
if (detectCollision(bbox_plane, current_offset)) {
document.getElementById('scoreboard').innerHTML += ' AND...GAME OVER!'
return;
}
}
//************************************************************//
//
// CONNECT SHADER WITH GEOMETRY
//
gl.bindBuffer( gl.ARRAY_BUFFER, current_v_buffer );
// gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, current_i_buffer );
// find the attribute in the shader source
var a_position = gl.getAttribLocation( shaderprogram, 'a_position' );
gl.vertexAttribPointer( a_position, 3, gl.FLOAT, false, 0, 0 );
gl.enableVertexAttribArray ( a_position );
// find the uniform in the shader source
var u_offset = gl.getUniformLocation( shaderprogram, 'u_offset' );
gl.uniform3fv( u_offset, current_offset)
var u_color = gl.getUniformLocation( shaderprogram, 'u_color' );
gl.uniform4fv( u_color, new Float32Array(current_color) );
//************************************************************//
//
// DRAW!
//
//
// Bonus Part 3!
//
gl.drawArrays( current_drawtype, 0, current_v_count/3, 0 );
}
requestAnimationFrame(animate);
};
</script>
<body>
<canvas id="c"></canvas>
<div id="scoreboard">0</div>
</body>
</html>
c = document.getElementById( 'c' ); // setup canvas
c.width = window.innerWidth;
c.height = window.innerHeight;
gl = c.getContext( 'webgl' ); // setup GL context
gl.viewport(0, 0, c.width, c.height );
GPU
Vertex Shader
Fragment Shader
Viewport
The Rendering Pipeline
Rasterization
XTK
X.renderer3D
X.cube
Three.js
THREE.WebGLRenderer
THREE.Scene
THREE.TrackballControls
THREE.PerspectiveCamera
THREE.AmbientLight
THREE.DirectionalLight
WebGL
gl.viewport
gl.createShader
gl.shaderSource
gl.compileShader
gl.getShaderInfoLog
gl.createProgram
gl.attachShader
gl.linkProgram
gl.useProgram
gl.createBuffer
gl.bindBuffer
gl.BufferData
gl.getAttribLocation
gl.vertexAttribPointer
gl.enableVertexAttribArray
gl.clearColor
gl.clear
gl.drawArrays
THREE.Geometry
THREE.Material
THREE.Mesh
Vertex Shader
attribute vec4 a_position;
void main() {
gl_Position = a_position;
}
This shader does nothing besides passing through positions.
Vertex Shader
attribute vec4 a_position;
void main() {
gl_Position = a_position;
}
attribute vec3 position;
void main(void) {
gl_Position = vec4( position, 1.);
}
same thing!
Fragment Shader
precision mediump float;
void main() {
gl_FragColor = vec4(1., 1., 1., 1.);
}
This shader colors every fragment (pixel) white.
Fragment Shader
Vertex Shader
gl_Position
gl_FragColor
for every vertex
for every pixel
gl_PointSize
Shader Input Types
attribute: changes per vertex
uniform: changes per draw call
varying: transfer info to fragment shader
Let's continue!
grab the starter code!
Quiz 4 due tonight!
submit your music
More next time!
1. Initialize WebGL
2. Shaders
3. Create Geometry
4. Connect Shader with Geometry
5. Draw!
setup Canvas
setup GL Context
compile vertex shader
compile fragment shader
attach and link shaders
create vertices
create and bind buffer
put data in
unbind buffer
bind buffer
find vertex attribute in shader source
configure vertex attribute
enable vertex attribute array
clear viewport
clear color buffer
draw vertex arrays
V0
V1
V2
V3
V4
V5
vertices = new Float32Array( [
-0.5, 0.5, 0.0, // V0
-0.5, -0.5, 0.0, // V1
0.5, 0.5, 0.0, // V2
0.5, 0.5, 0.0, // V3
-0.5, -0.5, 0.0, // V4
0.5, -0.5, 0.0 // V5
] );
gl.TRIANGLES
V0
V1
V2
V3
V4
V5
vertices = new Float32Array( [
-0.5, 0.5, 0.0, // V0
-0.5, -0.5, 0.0, // V1
0.5, 0.5, 0.0, // V2
0.5, 0.5, 0.0, // V3
-0.5, -0.5, 0.0, // V4
0.5, -0.5, 0.0 // V5
] );
gl.POINTS
gl_PointSize = 10.;
V0
V1
V2
V3
V4
V5
vertices = new Float32Array( [
-0.5, 0.5, 0.0, // V0
-0.5, -0.5, 0.0, // V1
0.5, 0.5, 0.0, // V2
0.5, 0.5, 0.0, // V3
-0.5, -0.5, 0.0, // V4
0.5, -0.5, 0.0 // V5
] );
gl.LINES
Rendering Primitives
V0
V1
V2
V3
V4
V5
vertices = new Float32Array( [
-0.5, 0.5, 0.0, // V0
-0.5, -0.5, 0.0, // V1
0.5, 0.5, 0.0, // V2
0.5, 0.5, 0.0, // V3
-0.5, -0.5, 0.0, // V4
0.5, -0.5, 0.0 // V5
] );
vertices = new Float32Array( [
-0.5, 0.5, 0.0, // V0
-0.5, -0.5, 0.0, // V1, V4
0.5, 0.5, 0.0, // V2, V3
0.5, -0.5, 0.0 // V5
] );
18 * 32 bit == 18 * 4 bytes == 72 bytes
12 * 32 bit == 12 * 4 bytes == 48 bytes
V0
V1
V2
V3
V4
V5
vertices = new Float32Array( [
-0.5, 0.5, 0.0, // V0 // 0
-0.5, -0.5, 0.0, // V1, V4 // 1
0.5, 0.5, 0.0, // V2, V3 // 2
0.5, -0.5, 0.0 // V5 // 3
] );
var indices = new Uint8Array( [ 0, 1, 2, // Triangle 1
2, 1, 3 ] ); // Triangle 2
0
1
2
3
Indexed Geometry
48 bytes
6 * 8 bit == 6 bytes
we now use 48 + 6 == 54 bytes instead of 72 bytes!
<html>
<head>
<meta content="text/html;charset=utf-8" http-equiv="Content-Type">
<meta content="utf-8" http-equiv="encoding">
<title>Default WebGL!</title>
<style>
html, body {
background-color:#000;
margin: 0;
padding: 0;
height: 100%;
overflow: hidden !important;
}
#c {
width: 100%;
height: 100%;
}
</style>
</head>
<script type="text/javascript" src="https://cs460.org/js/glmatrix.js"></script>
<script id="vertexshader" type="glsl">
// input for the shader
attribute vec3 position; // each vertex position
// actual shader code
void main(void) {
gl_PointSize = 10.;
gl_Position = vec4( position, 1. );
}
</script>
<script id="fragmentshader" type="glsl">
precision mediump float;
void main(void) {
gl_FragColor = vec4(1., 1., 1., 1.); // r g b a
}
</script>
<script>
// VARIABLE DECLARATIONS
window.onload = function() {
//************************************************************//
//
// INITIALIZE WEBGL
//
c = document.getElementById('c');
c.width = window.innerWidth;
c.height = window.innerHeight;
// grab WebGL API
gl = c.getContext( 'webgl' );
gl.viewport(0, 0, c.width, c.height);
//************************************************************//
//
// SHADERS
//
v_shader = gl.createShader( gl.VERTEX_SHADER );
f_shader = gl.createShader( gl.FRAGMENT_SHADER );
// compile vertex shader
var vshaderDom = document.getElementById( 'vertexshader' );
gl.shaderSource( v_shader, vshaderDom.innerText );
gl.compileShader( v_shader );
// check if it was compiled
if (!gl.getShaderParameter( v_shader, gl.COMPILE_STATUS)) {
// if not, print error
console.log( gl.getShaderInfoLog( v_shader ));
}
// compile fragment shader
gl.shaderSource( f_shader, document.getElementById( 'fragmentshader' ).innerText );
gl.compileShader( f_shader );
// check if it was compiled
if (!gl.getShaderParameter( f_shader, gl.COMPILE_STATUS)) {
// if not, print error
console.log( gl.getShaderInfoLog( f_shader ));
}
// attach and link shaders
shaderprogram = gl.createProgram();
gl.attachShader( shaderprogram, v_shader );
gl.attachShader( shaderprogram, f_shader );
gl.linkProgram( shaderprogram );
gl.useProgram( shaderprogram );
//************************************************************//
//
// CREATE GEOMETRY
//
vertices = new Float32Array( [
-0.5, 0.5, 0.0, // V0
-0.5, -0.5, 0.0, // V1
0.5, 0.5, 0.0, // V2
0.5, 0.5, 0.0, // V3
-0.5, -0.5, 0.0, // V4
0.5, -0.5, 0.0 // V5
] );
v_buffer = gl.createBuffer(); // CREATE
gl.bindBuffer( gl.ARRAY_BUFFER, v_buffer ); // BIND
gl.bufferData( gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW ); // PUT DATA IN
gl.bindBuffer( gl.ARRAY_BUFFER, null ); // UNBIND
//************************************************************//
//
// CONNECT SHADER WITH GEOMETRY
//
gl.bindBuffer( gl.ARRAY_BUFFER, v_buffer );
// find the attribute in the shader source
// ("finds the correct index for the input")
var a_position = gl.getAttribLocation( shaderprogram, 'position' );
gl.vertexAttribPointer( a_position, 3, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray( a_position );
//************************************************************//
//
// DRAW!
//
gl.clearColor( 0., 0., 0., 0.);
gl.clear( gl.COLOR_BUFFER_BIT );
gl.drawArrays( gl.POINTS, 0, 6 ); // from vertex 0 to vertex 6
};
</script>
<body>
<canvas id="c"></canvas>
</body>
</html>
Uniforms
createRectangle()
Rendering Loop
And, they move!
Fragment Shader
Vertex Shader
attribute vec3 position;
different data for each vertex
uniform vec3 offset;
different data for each gl.drawArray or gl.drawElements call
uniform vec4 color;
Shaderprogram
That's it for today!
1. Initialize WebGL
2. Shaders
3. Create Geometry
4. Connect Shader with Geometry
5. Draw!
1 Frame
multiple Frames
animate()
1. Initialize WebGL
2. Shaders
3. Create Geometry
4. Connect Shader with Geometry
5. Draw!
1 Frame
multiple Frames
animate()
1 Rectangle
multiple Rectangles
createRectangle()
createRectangle()
And, they move!
1. Initialize WebGL
2. Shaders
3. Create Geometry
4. Connect Shader with Geometry
5. Draw!
1 Frame
multiple Frames
animate()
1 Rectangle
multiple Rectangles
createRectangle()
createRectangle()
change Offsets!
<html>
<head>
<meta content="text/html;charset=utf-8" http-equiv="Content-Type">
<meta content="utf-8" http-equiv="encoding">
<title>Vanilla WebGL!</title>
<style>
html, body {
background-color:#000;
margin: 0;
padding: 0;
height: 100%;
overflow: hidden !important;
}
#c {
width: 100%;
height: 100%;
}
</style>
</head>
<script type="text/javascript" src="https://cs460.org/js/glmatrix.js"></script>
<script id="vertexshader" type="glsl">
attribute vec3 position;
uniform vec3 offset;
void main(void) {
vec3 final_position = position;
final_position.x += offset.x;
final_position.y += offset.y;
final_position.z += offset.z;
gl_Position = vec4( final_position, 1.);
gl_PointSize = 10.;
}
</script>
<script id="fragmentshader" type="glsl">
precision mediump float;
uniform vec4 color;
void main(void) {
gl_FragColor = color; //vec4(1., 1., 1., 1.);
}
</script>
<script>
// VARIABLE DECLARATIONS
var c, gl;
var v_shader, f_shader, shaderprogram;
var vertices, v_buffer, indices, i_buffer;
window.onload = function() {
//************************************************************//
//
// INITIALIZE WEBGL
//
c = document.getElementById( 'c' );
c.width = window.innerWidth;
c.height = window.innerHeight;
gl = c.getContext( 'webgl' );
gl.viewport(0, 0, c.width, c.height);
//************************************************************//
//
// SHADERS
//
v_shader = gl.createShader( gl.VERTEX_SHADER );
f_shader = gl.createShader( gl.FRAGMENT_SHADER );
// compile vertex shader
gl.shaderSource( v_shader, document.getElementById( 'vertexshader' ).innerText );
gl.compileShader( v_shader );
if (!gl.getShaderParameter( v_shader, gl.COMPILE_STATUS )) {
console.log(gl.getShaderInfoLog( v_shader ));
}
// compile fragment shader
gl.shaderSource( f_shader, document.getElementById( 'fragmentshader' ).innerText );
gl.compileShader( f_shader );
if (!gl.getShaderParameter( f_shader, gl.COMPILE_STATUS )) {
console.log(gl.getShaderInfoLog( f_shader ));
}
// attach and link the shaders
shaderprogram = gl.createProgram();
gl.attachShader( shaderprogram, v_shader );
gl.attachShader( shaderprogram, f_shader );
gl.linkProgram( shaderprogram );
gl.useProgram( shaderprogram );
//************************************************************//
//
// CREATE GEOMETRY
//
vertices = new Float32Array( [
-0.5, 0.5, 0.0, // V0. // 0
-0.5, -0.5, 0.0, // V1, V4. // 1
0.5, 0.5, 0.0, // V2, V3. // 2
0.5, -0.5, 0.0 // V5. // 3
] );
indices = new Uint8Array( [
0, 1, 2, 2, 1, 3
] );
v_buffer = gl.createBuffer(); // create
gl.bindBuffer( gl.ARRAY_BUFFER, v_buffer ); // bind
gl.bufferData( gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW ); // put data in
gl.bindBuffer( gl.ARRAY_BUFFER, null ); // unbind
i_buffer = gl.createBuffer(); // create
gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, i_buffer ); // bind
gl.bufferData( gl.ELEMENT_ARRAY_BUFFER, indices, gl.STATIC_DRAW ); // put data in
gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, null ); // unbind
//************************************************************//
//
// CONNECT SHADER WITH GEOMETRY
//
gl.bindBuffer( gl.ARRAY_BUFFER, v_buffer );
gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, i_buffer );
var a_position = gl.getAttribLocation( shaderprogram, 'position' );
gl.vertexAttribPointer( a_position, 3, gl.FLOAT, false, 0, 0 );
gl.enableVertexAttribArray( a_position );
var u_color = gl.getUniformLocation( shaderprogram, 'color' );
gl.uniform4fv( u_color, new Float32Array( [1., 1., 0., 1.] ) );
var u_offset = gl.getUniformLocation( shaderprogram, 'offset' );
gl.uniform3fv( u_offset, new Float32Array( [-.2, -.2, 0 ] ) );
//************************************************************//
//
// DRAW!
//
gl.clearColor( 0., 0., 0., 0. );
gl.clear( gl.COLOR_BUFFER_BIT );
// gl.drawArrays( gl.LINE_LOOP, 0, 6);
gl.drawElements( gl.TRIANGLES, 6, gl.UNSIGNED_BYTE, 0);
};
</script>
<body>
<canvas id="c"></canvas>
</body>
</html>
This code shows 1 rectangle with an offset!
Quiz 4 due tonight!
submit your music