Skip to main content
GameDev.net gamedev.net
🔒 Locked

Lesson Texts

Started by BBB Feb 18, 2007 at 4:00 PM 1 replies 100+ views
Original Post
BBB
BBB
Here is my text-additions I have mentioned in previous posts and on IRC: "How does it all work?" you probably think. As mentioned in the intro-lesson you basicly tell OpenGL what things you want rendered (rendered = image drawn) and it then does it for you. However, before we start talking about the actual rendering we have to explain some things (don't worry, it won't take long). First lets talk about which systems are involved in OpenGL-rendering. There are several subsystems that act as middle-hands. You won't need to bother much with them, but you need to know what they are and where they fit in. Take a look at this figure: Graphics-card <-> Driver <-> OS & Window-layer <-> Application Graphics-card: the hardware in the computer that does the actual rendering. Driver: the driver for the graphics-card that takes care of all the card-specific things (see lesson-intro for more info on what a driver is). OS: the operating system your application runs on. Windows, Mac, Linux, *BSD et.c. . Most of the time you will need to deal with the issues of each OS you code for (read on for more info). Window-layer: There are essentially two main parts of OpenGL. One that takes care of the "real" work (meaning you tell this part what colour you want, where you want your 3D-objects to be placed et.c.). This part is OS-independant and is basicly called OpenGL. Then there is the second-part: the window-layer. While the actualy OpenGL-calls are OS-independant (meaning they will work on every OS without having to write specialized code for each of them), the creation and handling of windows are OS-specific. Windows has its own APIs to deal with window-management, Linux and *BSD has theirs, Mac has its et.c. On windows you have whats called wGL, Linux and *BSD uses GLX and has aGL. If you look at the old Nehe-tutorials they are written using wGL (and then later ported to other system). "This sounds troublesome" you might think, and it is. If you want your software to work on more then one platform you need to deal with all the window-systems. However, there are ways around this problem. Remember that we talked about how in the old days you needed to deal with the specifics of each hardware and that this was solved by creating abstract APIs? Well, you can do the same with the various window-systems. You create a common API and then use "drivers" to deal with the OS-specific issues. "Do I have to write such a system?" No you don't [smile]. There already are finished ones that you can simply use. A handfull of years there was a system called GLUT (stands for Graphics Library Utility Toolkit) that was common. Nowadays another one called SDL (Simple Direct-media Layer) is the most common. Fact is, the new Nehe-code is such a system! You only need to learn how to use the interface-code and then just select a backend (backend = driver) we wrote for the appropriate OS. That way your code will work on all platforms we have backends for! So you get this: Graphics-card <-> Driver <-> OS & Window-layer <-> Nehe Introcode <-> Application We also have an SDL-backend (which is the preferd backend) so you get this: Graphics-card <-> Driver <-> OS & Window-layer <-> SDL <-> Nehe Introcode <-> Application "You then get two abstraction layers, isn't that a bit of a waste? Why didnt you just use SDL?". Both yes and no. When we started updating Nehe we considered the possibilty of just binding all our code to SDL. Then our system would have been much simpler. However, we choose not to as we didn't want to be locked into one system. Also, making the system we now have made gave us the opportonity to teach new programmers what an API really is (as NeheIntro is a very simple API but at the same time shows the fundamentals) and one of your goals with the new Nehe was to teach good and important programming-practices. Of course, there is always a choice to be made on this. You either take the fast and simple but not very agile approach (which, in our case, was to just use SDL) or the more complex one that takes more time to write but is more powerfull and agile (writing our own abstractation-system, which we choose to do). Some development-studios prefer the first approach, others the second. There is no definate answer, you have to judge it case by case and the skill of good judgement comes with experience. If you are a beginner then our advise is to first take the simple approach, in this case just use SDL or NeheIntro (so that you faster get a finished application), then the second time make your own abstractation-system as it teachers you a lot (just be prepared that its going to require more time), then after that we would recommend to generally use the first approach, as its the final product that counts. Who cares if you made a uber-powerfull abstractation-system? There already are a dozen of them and what people are interested is the final program you deliver (whetever its a game or another form of application). Modern graphics use whats called "Raster-graphics". There is also whats called "Voxels" and "Raytracing" but we will mainly use Raster as its the industry-standard and what most GFX-cards are built for. Raster-graphics are built upon whats called a polygon. A polygon is basicly a geometric-shape, for example a cube, a pyramid, a sphere et.c. Polygons consist mainly of 3 things: vertices, lines and faces. Lets take a look at a simple 2D-polygon: a triangle. Each corner of the triangle has a vertex, so the triangle has 3 vertices. Their locations are: However, if we only use the vertices we only get 3 dots, so we need something more. If we draw lines between these vertices we get a wireframe-triangle. We don't directly create lines, we simply place the vertices and OpenGL creates lines between the vertices automatically. Now we have a triangle, but there is nothing in it! This is called a wireframe. Now if we fill the inside of the triangle with, lets say a colour, we get this: The stuff inside the triangle is called a face. Like with the lines we don't directly create the face, OpenGL does it for us automaticly when we place vertices. You can, of course, tell OpenGL to just place vertices without drawing any lines or a face between them, and then you get a set of dots: You can also tell OpenGL to create lines but no face, and then you get: Normally you want a face of course, as the latest Quake-game wouldn't be so nice-looking with just a bunch of wireframes [smile]. Also note that you can't have a face without lines; that would be like having a table without a table-edge! In this tutorial our face just has a simple colour. You can also add texturing: and/or light and lots of other cools effects like fog, but we will cover those in later tutorials. Now, lets explain exactly how you make these polygons. As we mentioned you make a polygon by placing vertices. The first thing you need to do is call glBegin(GL_POLYGONS); (and after you have finished creating your polygon call glEnd(); to tell OpenGL that this polygon is done.) This tells OpenGL that you are about to create a polygon. You then, for each vertex, call glVertex3f(); glVertex3f() takes 3 float-variables as an argument. These 3 arguments form the position of the vertex. To use glVertex3f() (and OpenGL in general) you need to understand 3D-positioning so listen up. Imagine a checkboard. Then imagine that you want to tell someone which position a piece is on. Thats easy, you simply say, for example 3F, and the other person then knows what position you are refering to. The checkboard is a 2 dimensional-space. That means that you can specify a position with two values. If you had a 3 dimensional-space you would need 3 values, 4 values for 4 dimensions and so on. On the checkboard the first value is 3, the second if F. With these two you can specify a direct position. Now imagine that the other person is OpenGL and it needs to know where to put vertices. Just like with the checkboard you use a set of values to specify a position. OpenGL is 3 dimensional so you obviously need 3 values, but for simplicity lets asume it only has two dimensions. Now think of the checkboard again. Now imagine that instead of the screen you somehow could make OpenGL place vertices on a checkboard, lets say position 5A you would then call glVertex(5, A); If you wanted to specify 4G you would call glVertex(4, G); It works the same way with computer-graphics. Of course, OpenGL has 3 dimensions so you need 3 values. Futhermore, OpenGL normally uses floats so instead of fixed-point values like 5, 47, 3 et.c. you have 0.3f, 50.8f, -12.0f and so on. So to make this image: The code would be: glBeing(GL_POLYGONS); glVertex3f( ); // Vertex 1 glVertex3f( ); // Vertex 2 glVertex3f( ); // Vertex 3 glEnd(); Note that the polygon is built clock-wise: Lets learn how to practicly use glVertex3f() . The first argument of glVertex3f() is the X-coordinate (left and right), the second argument is the Y-coordinate (up and down), and the last the Z-coordinate (back and forward). So if we wanted to mess with the X-coordinate we could change the first glVertex-call: glVertex3f(-2.0f, -2.0f, 0.0f); from our previous example to glVertex3f(-6.0f, -2.0f, 0.0f); it would look like: Likewise, if we wanted to modify the Y-coordinate we would change glVertex3f(-2.0f, -2.0f, 0.0f); from our previous example to glVertex3f(-2.0f, -4.0f, 0.0f); and we would get this: Now go ahead and play around with the values to fully understand how this works. Note that if you are making a polygon with more then 3 vertices you need to keep all the vertices in a so-called "plane" meaning the polygon needs to be straight. Let me explain: imagine that you have a piece of paper. You just got it so it isnt't bent or anything. Imagine that this paper is your 4-vertex polygon and each corner is a vertex. Now look on it from the side: This means all the vertices are on the same plane. Now if you would bend one of the corners: that vertex would "stick out". In OpenGL you cannot do that! A polygon needs to be perfectly flat, otherwise you will mess up the rendering! "But what if I want the corner of the paper to be bent?" you might ask yourself. Well, in that case you will need 2 polygons and they will have to look like this: X---X / | X | | | X-----X X-X |/ X so you end up with 9 vertices. You then place them togheter like: X-X---X |/ | X | | | X-----X Because they are two separate polygons you can now bend the corner! This is because none of the two actually get bent, they are both still straight. The small is just tipped slightly, and it does appears that the model is bent. Also note that you don't get this problem with triangles. Why? Cause triangles only have 3 vertices and therefore it doesn't matter where you place the vertices, the polygon will always end up as a so-called "plane". Its only when your polygon has more then 3 vertices that you need to worry about this. "This sounds very annoying" you probably think, and it is. Not for the programmer, cause in real 3D-applications you don't specify the coordinates in code, you store them in a file and then load them during run-time, but it is for the 3D-modeller as he/she to make the actual 3D-model and thus has to worry about this. Now lets play a bit with colours! As we mentioned earlier you use for example glColour3f() to select a colour. You select colour per vertex by calling glColour3f() before you call glVertex3f(). For example this code: glColour3f(1.0f, 0.0f, 0.0f); glVertex3f(-2.0f, -2.0f, 0.0f); glColour3f(0.0f, 1.0f, 0.0f); glVertex3f(0.0f, 1.0f, 0.0f); glColour3f(0.0f, 0.0f, 1.0f); glVertex3f(2.0f, -2.0f, 0.0f); will create this: Each argument of glColour3f() can be between something from 0.0f to 1.0f (so no negative values or anything more then 1.0f). The first argument to glColour3f() specifies the amount of red, the second the amount of green and the third the amount of blue. These three are then mixed to form the final colour. So if you use: glColour3f(0.0f, 0.0f, 0.0f); the colour will end up as completely black. glColour3f(1.0f, 1.0f, 1.0f); will make it completely white and finally: glColour3f(0.5f, 0.5f, 0.5f); will make it grey. Try changing the values yourselfs, its easy.
Ravuya
Ravuya
I have completed editing your lesson. Link

I did it in a Wiki, but I can easily get it converted to HTML.
BBB
BBB
Quote:
Original post by Ravuya
I have completed editing your lesson. Link

I did it in a Wiki, but I can easily get it converted to HTML.


Looks great!

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.