CS248 Final Projet -- Basketball Shootout Jichun Zhu (zhu@pangea.stanford.edu) and Ting-I Cheng (ticheng@leland.stanford.edu) The Basketball Shootout is a simple 3D graphic game to simulate shooting of a basketball. It was developed on SGI. The environment of the basketball shooting game is a stadium with a standard basketball court. The user can move the ball around in the stadium, choose a position and an angle and try to put the basketball in the hoop. How to Run ========== To run the executable, type "bball.sgi &". How to Control Movement ======================= The game window is splitted into 3 subwindows. One big window on top shows from the player's point of view. A small window below to the left is the view from a camera fixed at the roof the stadium to the right hand side. The small window below to the right is the control panel. On-Screen Control Panel ----------------------- On the control panel, user can click a button and make a choice to move the player or the camera. Then, in order to move the player or the camera, user can click the buttons below to 1) shift the player/camera forward or backward, left or right; 2) rotate the player/camera left or right, up or down; 3) zoom in or out 4) shift the player/camera up or down The user is also provided a set of buttons to adjust the angle to shoot the basket ball and a slider to control the initial speed of the basketball. All the changes due to the player's position or point of view are displayed on the screen above. After the user has chosen proper angle and initial speed, the user can press the "Shoot" button to release the basket ball. To pick up the basket ball, press "Shoot" again. To start a new game, press "New Game" button. To quit, press "Quit". Keyboard Control ---------------- We also provide two sets of keyboard control for the impatient user, "e": shift player/camera forward with big steps "d": shift player/camera backward with big steps "s": shift player/camera to the left with big steps "f": shift player/camera to the right with big steps "E": rotate player/camera upward with big steps "D": rotate player/camera downward with big steps "S": rotate player/camera to the left with big steps "F": rotate player/camera to the right with big steps "i": shift player/camera forward with small steps "k": shift player/camera backward with small steps "j": shift player/camera to the left with small steps "l": shift player/camera to the right with small steps "I": rotate player/camera upward with small steps "K": rotate player/camera downward with small steps "J": rotate player/camera to the left with small steps "L": rotate player/camera to the right with small steps '1'-'9': Choose initial speed of the basket ball. spacebar: Shoot and pick up the ball. left arrow key: aim left right arrow key: aim right up arrow key: aim up/shift camera/player up down arrow key: aim down/shift camera/player down ***************************************** * IMPORTANT FOR THE TAs * ***************************************** For you convenience, we also implemented the following special keys. '!': brings you to the first demo position so you don't have to try. Just shoot the ball it will get in. '@': second demo position. '#': third demo posoition. '+': increase your credit so your game will not finish too soon. The biggest loop hole of the game is that once you've found a position and an angle so you can put the ball in, you basically can stand there and repeat shooting the ball and keep scoring. Need more time to correct this. Well, in the end, this is a graphics class, not a game design class. Menu Control ------------ On the big subwindow at the top, right click the mouse button, user can choose to 1) Turn on texture on the ball only in order to see the spin of the ball. 2) Turn on all texture mapping (slow but really good looking). 3) Turn off all texture mapping. The default is no texture mapping. 4) Turn on/off shadowing. The default is no shadowing. 5) Turn on/off reflection. The default is no reflection. 6) Turn on/off sound effect. The default is no sound. On the small subwindow below to the left, right click the mouse button, user can choose to move the player or the camera. Main Features ============= 1) Texture mapping ------------------ The walls/court/ceiling are 2D texture mapped. We also have the ball textured which is from a 2D image to a 3D sphere object. The texture on the wall is borrowed from a picture collection on the internet. The texture on the ball was hand drawn with photoshop. The texture on the court floor was a picture downloaded from www.nba.com, treated with photoshop and saved as ppm format. 2) Multipass rendering effects ------------------------------ The shadows and reflections are drawn using stencil buffer and blending. In both cases, the order of drawing is important to make the result correct. 2a) Shadows: For each piece of the scene that (might) have shadows on it, after drawing and setting values in the stencil buffer, we calculate where the possible shadows on it are and render the shadows (blended with black) according to the values in the stencil buffer. The drawing order of each piece of the scene is carefully arranged for the shadows to be correct. (Reasons that soft shadows are not done. 1. It is slow. 2. Somehow accumulation buffer does not work as expected on SGI.) 2b) Reflection: The court is reflective. At the beginning of drawing the stadium, the reflections of the ball and the backboards are drawn once, looking upside-down under the floor. (The walls are omitted because they could hardly be seen due to their colors, and if texture is on, it would be too slow.) Later when rendering the court, instead of direct drawing, it is blended with the underlying reflections. 3) Sound -------- We've added sound to the game by adapting the sample code from the class directory. It can be turned on/off by menu selection. The sound for the clapping, applause, the cheers are wave files borrowed from Windows 95 operating system, then converted into aiff format with soundfiler on SGI. The bouncing sound of the ball with the floor, the walls and the ring etc is the same bounce sound file, borrowed from the class directory and manipulated with soundeditor. 4) On screen control panel -------------------------- This feature was implemented with MUI. 5) Procedural modeling ---------------------- This technique was applied to the generation of the net. The shape of the net was determined by a series of parameters that determines the center of each layer and radius of each layer. If the ball goes through the net, we give up the default value of these parameters and calculate the new parameters depending on the ball's location so the net's shape will fit the ball profile and hence move with the ball. 6) Collision detection and dynamic simulation --------------------------------------------- /* This feature is extremely sophicated. Per request of David Koller, we will try to explain as much as possible. If you want more details, please send us email. */ The movement of the basketball was simulated with fine time steps. Air drag on the ball was considered in the horizontal direction but not the vertical direction. The general algorithm to handle the ball's movement --------------------------------------------------- It is a recursive function called DoBallFlying(float time): At the beginning of the given time step, check with the collision detection routine (described below) to see if we will have collisions within this time step. If yes, the collision detection routine will return the time when the collision is going to occur from now (timeToCollide) and the ball's state after the collision. Then we call DoBallFlying(time-timeToCollide) recursively to take care of the rest of this time step. If no, then If it is on the floor and has no verical speed, roll the ball by the full time step. Otherwise, the ball must be either in the air, or on the floor but with some vertical speed. Move it by the full time step. The collision detection routine ------------------------------- 6a) At the beginning of the given time step, move the ball forward by the time step using a function called BallFlying(float time). Here we assume as if there is nothing blocking the ball's path. 6b) If in the end, the ball's position intersects any of the floor, walls or ceiling, then some moment between the beginning and the end of the time step we are going to have a collision of the ball with the walls, floor or ceiling. 6b 1) By analytical method, calculate the time it takes from now until the collision occurs, named timeToHitWall. 6b 2) Fly the ball to the colliding position with a function call BallFlying(float timeToHitWall). 6b 3) Adjust the speed and spin speed of the ball to values after the collision. 6b 4) Return with the time of the collision and the ball state after the collision so we can handle the rest of the time step recursively. 6c) If in the end, the ball's position does not intersect with any of the walls, floor or ceiling, no collision with these objects will occur within this time step. However, it is still possible that the ball will hit the board or the ring within this timep step. So we go on and do the collision detection of the ball with the ring (described below). Here we made two assumptions: i) Within one time step, the ball can hit at most one of the four walls, the floor and the ceiling. ii) If the ball hits any one of the walls, floor or ceiling, it will not hit the board or the ring. Collision detection of the ball with the ring and backboard ----------------------------------------------------------- Because the board and the ring are very close to each other, it is very possible that within one tiny time step, the ball may still hit both the ring and the board. If at the end of the test, the ball's position intersects with both the ring and the board, only the first collision is effective because after the first time step, the direction of the ball's movement is reflected. What happens after the first collision is taken care of by the recursive function call. The algorithm is as follows: i) Move the ball by a full given time step using BallFlying(float time); ii) Check the ball's collision with the backboard. a) If the ball does not hit the board, go on check the collision with the ring. 1) If the ball does not hit the ring, there is no collision within this time step. Move the ball by the full time step. 2) If the ball does hit the ring. This is the only collision within this time step. Handle the collisioin, return the time for the collision to happen from now and the ball state after the collision in order for us to handle the rest of the time step. b) If the ball does hit the board, check if the ball hits the ring as well. 1) If the ball hits the ring as well, then we have two collisions within this time step. Compare which collision happens first and return the first collision time and ball state for us to handle the rest of the time step. The second collision is not likely to happen because the ball bounces into different direction after the first collision. 2) If the ball does not hit the ring. Then the collision with the board is the only collision within this time step. Return this collision time and ball state after the collision for us to handle the rest of the time step. The collision of the ball with the backboard is similar with the collision of the ball with the walls except that the board has limited area and the ball may hit the board on the edges. The collision of the ball on the board's edges can be handled but we don't have enough time. Here we made a simplification by adding a strip along the edge of the board so even the ball should hit the edge, it still looks like it is hitting the board on the front. How to detect collision with ring and how to bounce off it ---------------------------------------------------------- At the beginning of the time step, move the ball by a full time step. 1) If at the end of the time step the ball is way above or below the ring plane, then the ball is not touching the ring. No collision will have happened within this time step, return. 2) If at the end of the time step, the ball is around the height of the ring plane. Then the ring plane will cut a slice off the ball. Calculate the distance from the slice center to the ring center and the slice radius. If the slice is intersecting with the ring circle, we have a collision. Otherwise, no collision, return. 3) If we have determined that some time within this time step, the ball is going to touch the ring, then we cut the time step by half and redo the above test. (i) If in the new test the ball is not touching the ring, we've cut the time step too much. Increase the time by a quarter of the original time step and redo the test. (ii) If in the new test the ball is still touching the ring too deep, then we haven't cut the time step short enough. Reduce the time by a quarter of the original time step and redo the test. (iii) Repeat the above step until we find a moment when the ball is barely touching the ring. The spot is the collision point. The normal of the ball's reflection is the vector from the collision point to the ball's center. (iv) The ball is at the right place when the collision occurs. Reflect the ball's velocity vector by the normal, then we've got the ball's state right after the collision. 4) Now that we have the ball's state after collision and the time when the collision exactly happens. We may take care of the rest of the time step recursively. Reference ========= We learned OpenGL from the red book and lots of sample code. The only thing we borrowed directly is a function called "output", which is used to write text on the screen. This is acknowledged in the source code.