Project 2 Update: Changes, Clarifications, Hints, Explanations Sat Nov 1 2003 Demo is now available on the course web site (everything but cabinet projection works.) Make sure to download the textures too, if you want to play with it. ---------- - [CHANGE] Sphere Texture Tiling. I'm hereby making the assignment easier by saying that you only have to implement a single texture tile on the sphere. So supporting repeating images on the sphere is now 2 extra credit points instead of required. ---------- - [CHANGE] Cube Texture Tiling. I'm also making the cube tiling easier: you only need to implement 3 levels of tiling instead of 9. The default is just 1 tile, return to this with the '1' key. The '2' key should make two tiles horizontally and 2 vertically, for a total of 4 copies of the texture covering the face. Similarly, the '3' key should make 3 tiles vertically and 3 horizontally, for a total of 9 copies covering the face. You don't have to implement 4-9. Hint on how to do tiling: by changing the way that you assign texture coordinates! ---------- - [CLARIFICATION] Picking Controls. If you prefer, you can just have the right mouse click trigger lineblasting or textureblasting. Then 'l' or 't' act to change modes, instead initiating the actual blast. That's what the demo does. Again, it's up to you, no points lost either way. - [CLARIFICATON] Flying Controls. Summary: you can implement the exact mappings of mouse drags to motion any way you find convenient and we won't take points off, as long as you have a way to control roll/pitch/yaw using the mouse. Apparently many people have implemented motion where when the mouse stops moving, the camera stops moving, even if the mouse is still down. The size of the drag vector does control the speed in that a big drag makes you move further than a small drag. If you did this, that's OK, you will *not* have any points taken away for this. However, let me clarify what I had in mind, just because I think it's a lot easier to get around the scene if you do it my way: as long as you're still holding a mouse button down, you're moving. When you lift up on the button, you stop. That lets you easily maintain a small amount of forward motion by dragging the mouse a little bit and keeping it held down. Then you can control your speed with the size of your vector: for example, making the vector smaller while keeping the mouse held down lets you slow down your motion. If you find another configuration of mouse mappings more convenient (for example, using switching so that left horizontal is yaw and right horizontal is roll), that's fine too. Just document what you've done in your README. ---------- - [HINT] Flying 1: As I said in class, do NOT try quaternions unless and until you have everything else working perfectly. Start with Euler angles, get flying working with that, then move on to doing the other parts of the assignment! You will get *extra credit* for solving the gimbal lock problem, it's not required to get full credit for flying. ---------- - [HINT] Flying 2: Don't try to specify your camera viewing in the perspective stack, make sure to do this in the modelview stack. It might look OK at first, but it's a recipe for trouble later on! ---------- - [HINT] Flying 3: If you're having troubles getting the camera motion to work, here's some hints. When you drag the motion, you're specifying movement with respect to the current coordinate system. So it's easier to just move with your Euler angles incrementally in current coordinate system than to compute and store the values that you'd need to apply to do a full cumulative transformation from the original world coordinate system. But, you do need to somehow keep track of where you are, so that you don't keep snapping back to your original location. So how might you do that, if you don't keep cumulative Euler angles? Well, one thing to consider is using the matrix stack itself to keep track of your position! Consider also whether you want to be postmultiplying or premultiplying. If you want to postmultiply on top of the current transformation, you would not do a glLoadIdentity: instead, just issue transformation commands that would directly change the current contents of the stack. (You would need to be careful that any other transformations you do, for example when modelling rather than viewing, are properly segregated with push/pop so that your matrix stack has just the current viewing transformation.) If you instead want to do a premultiply using the current transformation, the easiest way to do this is to just save it off into a temporary matrix using glGetDoublev (same idea as when you do this for picking, as described below). That allows you to insert a new matrix before the current set: you'd clear the stack, do your premultiply stuff, then multiply by that temporary matrix (glMultMatrix). ---------- - [HINT] Picking. You should start on picking using OpenGL picking support in order to find out what face you're picking. As we discussed in class, that means you should use the name stack (commands like glPushName, glPopName, glLoadName, glInitNames). In particular, you should use hierarchical names: which cube should be one level of the stack, and which face the higher level. Then to handle a pick, you go into select mode, make sure to insert the gluPickMatrix between the identity and your projection, and redraw things. When you return to render mode, you'll get the set of all hits. You need to process the hits to discover which object you've picked, the name is in the hit record. If you've got more than one hit, use the one with the frontmost z minimum value. In the case of a sphere, you're all set - you don't even need to worry about further interpreting z values. See the NeHe Lesson #32 for a specific example of picking code. http://nehe.gamedev.net/data/lessons/lesson.asp?lesson=32 But if it's a cube, and you're going to lineblasting, you now need to move on to phase 2. You have to compute the exact vertices where you want to place your rectangle, you can't just rely on the minimum and maximum value of the named object that's returned by the hit record. (Why? Because due the perspective distortion, you can't easily figure out the intersection point in window coordinates, it's not safe to interpolate in screen coordinates.) To compute these 4 intersection points, you need to intersect 4 lines with the plane formed by the polygon. You can figure out that plane easily, once you know from OpenGL the name of the polygon that you hit. Just take two vertex pairs, use them to construct vectors, take the cross product to get the plane normal, and then you can do a standard line-plane intersection. So lines are you intersecting? Well, you have the (x,y) location of the pick center in window coordinates. You want to come up with new (x,y) locations so that total size of the rectangle is 3x3 pixels in window coordinates. Once you have these four new (x,y) pairs, you want the world space coordinates of a ray from that point that extends through the whole scene. gluUnProject does exactly that! If you use z=0 for one endpoint and z=1 for the other endpoint, you'll get the line you need. Then you do the line-plane intersection, and the very last bit is that you should nudge the points forward in world space a bit along the positive direction of the normal (that you already computed), so that they're slightly in front of the surface. Subhint: there are a few possible pitfalls with gluUnProject. First, make sure you pass in the address of your world coordinate double variables, so that they can be updated in the procedure, instead of just the values. Second, when you get the modelview and projection matrices using glGetDoublev, make sure that you use the right parameter! You want "GL_MODELVIEW_MATRIX" and "GL_PROJECTION_MATRIX", not GL_MODELVIEW or GL_PROJECTION. Third, when you grab your modelview and projection matrices from the stack, you want to make sure that the stack is in the correct state. Consider when is the safest time to grab these values! Subhint: maybe you're wondering what's up with the z values you get back in your hit record, they're mysterious looking. They're encoded as 32-bit integers, so the values range from 0 to MAXINT. To turn them into reasonable-looking numbers ranging from 0 to 1, divide through by MAXINT. You might want to do this if you're debugging your line/plane intersection code, to check whether you're getting a z value correctly in between the min and max values of the whole named object. Subhint: what if you pick a spot that already has a line blasted on it. The individual rectangles of that line should not be pickable. Consider how you would ensure this! Finally, once you have your endpoint rectangles and know the plane that you're moving along, you should adapt Bresenham's line scan conversion algorithm to draw the rest of your rectangles in between. ---------- - [HINT] Textures. Instead of giving exhaustive hints here, I'll just point you to the quite good NeHe tutorial #6 that covers the exact mechanics of how to do textures in OpenGL. http://nehe.gamedev.net/data/lessons/lesson.asp?lesson=06 ---------- - Email. Make sure you have a working email address on file so that you get critical information updates like this one! At least 10 messages bounce every time I send mail. If you're reading this on the newsgroup anad you did not get this via email, you're one of them. I think the place you can update this is via the Student Services Center portal at https://ssc.adm.ubc.ca/. ---------- - Newsgroup. A few people have complained that although it worked for a while, newsgroup posting is blocked from the outside again. First, is this an isolated incident or a general problem? Second, if this is a problem for you, just use ssh port forwarding which is guaranteed to get through. Here are the URLs explaining how to do so: http://www.cs.ubc.ca/ugrad/facilities/remote/news/netscape.htm http://www.cs.ubc.ca/ugrad/facilities/remote/connect/ssh.htm Key idea: tell the browser to use use "localhost" for a news server, and tell it which port you've forwarded news *to* (you should pick a number greater than 1024). You always forward news *from* port 119, which is the standard news port. For example, in Linux I use the line below to set up my shell connection, I picked "5119" as the forwarded port: ssh -L 5119:news.cs.ubc.ca:119 remote.cs.ubc.ca