CS460 Computer Graphics - University of Massachusetts Boston
Assignment 3
A
Assignment 3
My quick'n'dirty solution: https://cs460.org/shortcuts/15/
Assignment 4
10/02/2019!
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
Fragment Shader
Vertex Shader
gl_Position
gl_FragColor
for every vertex
for every pixel
gl_PointSize
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
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
] );
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
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
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>