Computer Graphics - Treasure Hunter CS 4830 Dr. Mihail September 16, 2015 1 Introduction In this assignment you will implement an old technique to simulate 3D scenes called billboarding, sometimes referred to as 2.5D graphics using sprites. A sprite is simply a textured rectangle (two triangles) that is always facing the camera. In other words, regardless of which direction the viewer is looking from, the sprite will be parallel to the view plane. Older games relied on this technique to simulate 3D objects, simply to save computation time, which was required for real-time rendering, especially in games. At a minimum, you will implement a game, which I uninterestingly call Treasure Hunt, where the goal is to navigate through a neighborhood that hides a treasure between many identical houses. The story, goal of the game and graphics are subject to creative enhancement, which I reward with extra credit. During game-play, the canvas should look (at a minimum) like Figure 2. 2 Implementation Details The concept you have to master is the idea of a camera, or, in other words, the location and direction from which the player is looking at the world. The simple projection matrix we derived in class and those generated using the perspective function from MV.js assume the camera s center of projection is on the positive Z-axis, at some focal length d. Vertices from the world are projected on the view plane, that is the XY plane, at z = 0. 2.1 Geometry In this assignment, you will generate the geometry (billboards) for every frame (or, more efficiently, when changes due to player or enemy movements occur). As the player moves through the world, you will generate the billboard triangles, as they are always parallel to the view plane. Every object in the world has a position, and lives on the XZ plane, at y = 0. An easy way to ensure all billboard triangles are parallel to the XY plane is to set all the vertices z value the same. 2.1.1 Ground and Sky The sky and ground are each made up of two triangles, and drawn using a different shader. The skyground shader uses the color attribute, while the billboard shader uses the texture coordinate attribute. You have to disable depth testing, draw sky and ground, then enable depth testing and draw everything else, in that order. 1
Figure 1: Sample canvas view during game-play Figure 2: World coordinate system and camera. Objects within the near and far clip planes and within the field of view will be displayed on the canvas through a perspective projection onto the view plane at z = 0. The pentagons are the objects which are rendered as billboards using different textures (e.g., house or enemy). 2
2.2 Camera When the player moves in the world, the camera is simulated by transforming every vertex of our objects in the world. For example, if the player walks forward to an object, the camera moves closer to the object. Equivalently, we translate (move) the object closer to the camera. Similarly, when the player turns, the direction the camera faces rotates. Equivalently, we can rotate every vertex of our objects in the world around the Y-axis, since our view plane is at z = 0. You will implement two movements: forward/backward and turning left/right. Movement forward is equivalent to translating every vertex by a small positive amount along the Z-axis; movement backward is equivalent to a small negative translation along the Z-axis. Turning left is equivalent to rotating every vertex by a small degree in a clockwise direction. Turning right is equivalent to rotating every vertex by a small degree in a counter-clockwise direction. 3 Program Requirements Your program has to follow the following specifications: Your program has to allow the player to move through the world with at least four controls: forward, backward, turn left and turn right. Your program has to have two shaders. The shaders (written in the HTML file) script tags have an id property that has to be different between shaders. For example one can have the id= vertexshader while another shader can have the id= vertex-shader-skyground. Your world has to contain billboards with at least two different textures. Note that you DO NOT need two texture images. You can put two images side-by-side inside a square texture (using MS Paint or GIMP) with a size of length power of 2. Your triangle texture coordinates can determine which part of the texture image you use for a given billboard. Your world has to have at least 20 billboards. The house billboard is posted on the course webpage. 4 Technical Considerations In order to have the billboards always face the camera, you can keep track of their positions in an array of vec4 s, with the y value as 0. To ensure that some billboards are in the view frustum, you can generate them with x values in the range ( 1, 1) and z values in the range ( 1, 1) as well. The render loop will have the following logic (or something similar): 1. Disable depth testing 2. Draw ground and sky 3. Enable depth testing 4. Create a translation matrix, set to identity 5. If W is pressed, modify the translation matrix to increase the z-values by a small amount 6. If S is pressed, modify the translation matrix to decrease the z-values by a small amount 7. Apply translation to all vertices of the objects in the world 3
8. Create a rotation matrix, set it to identity 9. If A is pressed, modify the rotation to include a small clockwise rotation around the Y-axis 10. If D is pressed, modify the rotation to include a small counter-clockwise rotation around the Y-axis 11. Apply rotation matrix to all vertices of the objects in the world 12. Do collision checking and/or other game logic 13. Generate billboard geometry using the positions of the objects in the world 14. Send geometry (vertex attributes such as position, texture coordinate, color) to GPU 15. Draw As you can see above, unless W, S, A or D is pressed, the geometry is transformed using identity matrices, i.e., nothing happens. 5 Useful Functions Below is a function that multiplies a matrix by a column vector, returning a vector. 1 function vecmatmult ( vec, mat ) { 2 var res = vec4 (); 3 res [0] = mat [0][0] * vec [0] + mat [0][1] * vec [1] + mat [0][2] * vec [2] + mat [0][3] * vec [3]; 4 res [1] = mat [1][0] * vec [0] + mat [1][1] * vec [1] + mat [1][2] * vec [2] + mat [1][3] * vec [3]; 5 res [2] = mat [2][0] * vec [0] + mat [2][1] * vec [1] + mat [2][2] * vec [2] + mat [2][3] * vec [3]; 6 res [3] = mat [3][0] * vec [0] + mat [3][1] * vec [1] + mat [3][2] * vec [2] + mat [3][3] * vec [3]; 7 return res ; 8 } Below is a function that creates a quad (billboard) and places it in the world at the position given in the argument. 1 2 function create_ billboard ( position ) { 3 // the vertices define two triangles on the z =0 plane 4 var vertices = [ new vec4 (-1, -1, 0, 1), new vec4 (1, -1, 0, 1), new vec4 (-1, 1, 0, 1), new vec4 (1, -1, 0, 1), new vec4 (-1, 1, 0, 1), new vec4 (1, 1, 0, 1) ]; 5 // we translate the billboard to the position of the object in the world 6 var trans = translate ( position [0], 0, position [ 2]) ; 7 // we shrink it using a scale matrix 8 var sc = scalem (0.02, 0.02, 0. 02) ; 9 // apply the above transformations to all 6 vertices of our billboard 10 for ( var i =0; i <6; i ++) 11 { 12 vertices [i] = vecmatmult ( vertices [i], sc); // scale 13 vertices [i] = vecmatmult ( vertices [i], trans ); // translate 14 } 15 // define texture coordinates 4
16 var texturecoords = [ new vec2 (0, 0), new vec2 (1, 0), new vec2 (0, 1), new vec2 (1, 0), new vec2 (0, 1), new vec2 (1, 1) ]; 17 // create an empty object 18 var ret = {}; 19 // add properties to object and return 20 ret. vertices = vertices ; 21 ret. texturecoords = texturecoords ; 22 return ret ; 23 } In MV.js, you will use the following functions: perspective for the perspective projection matrix, rotate for the rotation matrix, translate for translation matrices, and scalem for scale. In Javascript, you can create an array of objects as follows: 1 var myarray = []; 2 for ( var i = 0; i< nrobjects ; i ++) { 3 myarray. push ( new vec4 ( Math. random () * 2-1, 0, Math. random () * 2-1, 1); 4 } 5 myarraylength = myarray. length ; // this is how you get the length of the array Transparency is enabled using the following commands: 1 gl. blendfunc (gl. SRC_ALPHA, gl. ONE_MINUS_SRC_ALPHA ); 2 gl. enable (gl. BLEND ); Depth testing is enabled using the following command: 1 gl. enable (gl. DEPTH_TEST ); 6 Write-up In the write-up you will document the challenges you encountered and how you addressed them. You will also describe the goal of the game and make up a storyline. The write-up has to be a minimum of 1 page single spaced, 12 point font. 7 Due Date This assignment is submitted via the electronic submission form on the course web page (as a zip file) and is due before midnight on Friday, October 2nd. 8 Grading Rubric W and S keys move the camera forward/backward (by translating the positions of objects along the Z-axis) (20 pts) A and D keys rotate the camera left and right (by rotating the positions of objects clockwise and counter-clockwise) (20 pts) Ground and sky are drawn (20 pts) Interaction with the world, e.g., finding an object when you get close to it (20 pts) Write-up (20 pts) 5
9 Extra Credit It is possible to earn up to 100% extra credit. You can only get extra credit if the base requirements are met. Creative graphics, game logic and story-line (up to 25%) Billboard texture changes with respect to the angle it makes with the camera view-plane (up to 25%) AIs either chase you or run away from you (up to 25%) Multiple ways of interacting with the world (up to 25%) 6