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