以文本方式查看主题 - 计算机科学论坛 (http://bbs.xml.org.cn/index.asp) -- 『 C/C++编程思想 』 (http://bbs.xml.org.cn/list.asp?boardid=61) ---- [推荐]NeHe OpenGL教程(中英文版附带VC++源码)Lesson 11-lesson 12 (http://bbs.xml.org.cn/dispbbs.asp?boardid=61&rootid=&id=53823) |
-- 作者:一分之千 -- 发布时间:10/15/2007 4:59:00 PM -- Lesson 11 Well greetings all. For those of you that want to see what we are doing here, you can check it out at the end of my demo/hack Worthless! I am bosco and I will do my best to teach you guys how to do the animated, sine-wave picture. This tutorial is based on NeHe's tutorial #6 and you should have at least that much knowledge. You should download the source package and place the bitmap I've included in a directory called data where your source code is. Or use your own texture if it's an appropriate size to be used as a texture with OpenGL. First things first. Open Tutorial #6 in Visual C++ and add the following include statement right after the other #include statements. The #include below allows us to work with complex math such as sine and cosine. #include <math.h> // For The Sin() Function float points[ 45 ][ 45 ][3]; // The Array For The Points On The Grid Of Our "Wave" if (TextureImage[0]=LoadBMP("Data/Tim.bmp")) // Load The Bitmap glPolygonMode( GL_BACK, GL_FILL ); // Back Face Is Filled In // Loop Through The X Plane The two loops above initialize the points on our grid. I initialize variables in my loop to localize them in my mind as merely loop variables. Not sure it's kosher. We use integer loops to prevent odd graphical glitches that appear when floating point calculations are used. We divide the x and y variables by 5 ( i.e. 45 / 9 = 5 ) and subtract 4.5 from each of them to center the "wave". The same effect could be accomplished with a translate, but I prefer this method. The final value points[x][y][2] statement is our sine value. The sin() function requires radians. We take our degree value, which is our float_x multiplied by 40.0f. Once we have that, to convert to radians we take the degree, divide by 360.0f, multiply by pi, or an approximation and then multiply by 2.0f. I'm going to re-write the DrawGLScene function from scratch so clean it out and it replace with the following code. int DrawGLScene(GLvoid) // Draw Our GL Scene glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear The Screen And Depth Buffer glTranslatef(0.0f,0.0f,-12.0f); // Translate 17 Units Into The Screen glRotatef(xrot,1.0f,0.0f,0.0f); // Rotate On The X Axis glBindTexture(GL_TEXTURE_2D, texture[0]); // Select Our Texture glBegin(GL_QUADS); // Start Drawing Our Quads float_x = float(x)/44.0f; // Create A Floating Point X Value glTexCoord2f( float_x, float_y); // First Texture Coordinate (Bottom Left) glTexCoord2f( float_x, float_yb ); // Second Texture Coordinate (Top Left) glTexCoord2f( float_xb, float_yb ); // Third Texture Coordinate (Top Right) glTexCoord2f( float_xb, float_y ); // Fourth Texture Coordinate (Bottom Right) If you drew in a counter clockwise order the face you'd initially see would be the front face, meaning you would see the grid type texture instead of the filled in face. if( wiggle_count == 2 ) // Used To Slow Down The Wave (Every 2nd Frame Only) for( y = 0; y < 45; y++ ) // Loop Through The Y Plane The above code was modified by NeHe (Feb 2000), to fix a flaw in the ripple going across the surface of the texture. The ripple is now smooth. xrot+=0.3f; // Increase The X Rotation Variable return TRUE; // Jump Back This was a blast, but very energy/time consuming. It makes me appreciate the likes of NeHe ALOT more now. Thanks all. Bosco (bosco4@home.com) Jeff Molofee (NeHe) |
-- 作者:一分之千 -- 发布时间:10/15/2007 5:16:00 PM -- 第十二课 想知道如何加速你的OpenGL程序么?这一课将告诉你如何使用OpenGL的显示列表,它通过预编译OpenGL命令来加速你的程序,并可以为你省去很多重复的代码。 当你在制作游戏里的小行星场景时,每一层上至少需要两个行星,你可以用OpenGL中的多边形来构造每一个行星。聪明点的做法是做一个循环,每个循环画出行星的一个面,最终你用几十条语句画出了一个行星。每次把行星画到屏幕上都是很困难的。当你面临更复杂的物体时你就会明白了。 那么,解决的办法是什么呢?用现实列表,你只需要一次性建立物体,你可以贴图,用颜色,想怎么弄就怎么弄。给现实列表一个名字,比如给小行星的显示列表命名为“asteroid”。现在,任何时候我想在屏幕上画出行星,我只需要调用glCallList(asteroid)。之前做好的小行星就会立刻显示在屏幕上了。因为小行星已经在显示列表里建造好了,OpenGL不会再计算如何构造它。它已经在内存中建造好了。这将大大降低CPU的使用,让你的程序跑的更快。 那么,开始学习咯。我称这个DEMO为Q-Bert显示列表。最终这个DEMO将在屏幕上画出15个立方体。每个立方体都由一个盒子和一个顶部构成,顶部是一个单独的显示列表,盒子没有顶。 这一课是建立在第六课的基础上的,我将重写大部分的代码,这样容易看懂。下面的这些代码在所有的课程中差不多都用到了。 然后用两个变量xloop,yloop表示屏幕上立方体的位置,两个变量xrot,yrot表示立方体的旋转。 GLuint box; // 保存盒子的显示列表 static GLfloat boxcol[5][3]= // 盒子的颜色数组 static GLfloat topcol[5][3]= // 顶部的颜色数组 GLvoid BuildLists() // 创建盒子的显示列表 box=glGenLists(2); // 创建两个显示列表的名称 我们用glNewList()命令来做这个事情。你一定注意到了box是第一个参数,这表示OpenGL将把列表存储到box所指向的内存空间。第二个参数GL_COMPILE告诉OpenGL我们想预先在内存中构造这个列表,这样每次画的时候就不必重新计算怎么构造物体了。 GL_COMPILE类似于编程。在你写程序的时候,把它装载到编译器里,你每次运行程序都需要重新编译。而如果他已经编译成了.exe文件,那么每次你只需要点击那个.exe文件就可以运行它了,不需要编译。当OpenGL编译过显示列表后,就不需要再每次显示的时候重新编译它了。这就是为什么用显示列表可以加快速度。 glNewList(box,GL_COMPILE); // 创建第一个显示列表 你可以在glNewList()和glEngList()中间加上任何你想加上的代码。可以设置颜色,贴图等等。唯一不能加进去的代码就是会改变显示列表的代码。显示列表一旦建立,你就不能改变它。 比如你想加上glColor3ub(rand()%255,rand()%255,rand()%255),使得每一次画物体时都会有不同的颜色。但因为显示列表只会建立一次,所以每次画物体的时候颜色都不会改变。物体将会保持第一次建立显示列表时的颜色。 如果你想改变显示列表的颜色,你只有在调用显示列表之前改变颜色。后面将详细解释这一点。 glBegin(GL_QUADS); // 开始绘制四边形 glEndList(); // 第一个显示列表结束 top=box+1; // 第二个显示列表的名称 glNewList(top,GL_COMPILE); // 盒子顶部的显示列表 glBegin(GL_QUADS); // 开始绘制四边形 glEndList(); // 第二个显示列表创建完毕 if (TextureImage[0]=LoadBMP("Data/Cube.bmp")) 初始化的代码只有一点改变,加入了一行BuildList()。请注意代码的顺序,先读入纹理,然后建立显示列表,这样当我们建立显示列表的时候就可以将纹理贴到立方体上了。 BuildLists(); // 创建显示列表 最后一行的GL_COLOR_MATERIAL使我们可以用颜色来贴纹理。如果没有这行代码,纹理将始终保持原来的颜色,glColor3f(r,g,b)就没有用了。总之这行代码是很有用的。 glEnable(GL_LIGHT0); // 使用默认的0号灯 接着把纹理绑定到立方体,我可以把这些代码加入到显示列表中,但我还是把它留在了显示列表外边,这样我可以随便设置纹理。 int DrawGLScene(GLvoid) // 绘制操作开始 glBindTexture(GL_TEXTURE_2D, texture[0]); // 选择纹理 for (yloop=1;yloop<6;yloop++) // 沿Y轴循环 for (xloop=0;xloop<yloop;xloop++) // 沿X轴循环 glLoadIdentity(); // 重置模型变化矩阵 // 设置盒子的位置 glColor3fv(boxcol[yloop-1]); glCallList(box); // 绘制盒子 glColor3fv(topcol[yloop-1]); // 选择顶部颜色 SwapBuffers(hDC); // 交换缓存 =================以下原帖没有翻译,是我自己翻译的 不当之处,大家指教 这节教程结束后想必你已经对显示列表是如何运行的、如何创建的以及如何把5它显示到屏幕上有了一个比较好的理解了,显示列表功能强大,不仅仅能够简化复杂工程的编码,还能提供一点额外的运行速度以保持较高的刷新率。 希望你能喜欢这节教程,如果你有什么问题或者感到什么问题不清楚,请发邮件告诉我。 |
-- 作者:一分之千 -- 发布时间:10/15/2007 5:16:00 PM -- Lesson 12 In this tutorial I'll teach you how to use Display Lists. Not only do display lists speed up your code, they also cut down on the number of lines of code you need to write when creating a simple GL scene. For example. Lets say you're making the game asteroids. Each level starts off with at least 2 asteroids. So you sit down with your graph paper (grin), and figure out how to make a 3D asteroid. Once you have everything figured out, you build the asteroid in OpenGL using Polygons or Quads. Lets say the asteroid is octagonal (8 sides). If you're smart you'll create a loop, and draw the asteroid once inside the loop. You'll end up with roughly 18 lines or more of code to make the asteroid. Creating the asteroid each time it's drawn to the screen is hard on your system. Once you get into more complex objects you'll see what I mean. So what's the solution? Display Lists!!! By using a display list, you create the object just once. You can texture map it, color it, whatever you want to do. You give the display list a name. Because it's an asteroid we'll call the display list 'asteroid'. Now any time I want to draw the textured / colored asteroid on the screen, all I have to do is call glCallList(asteroid). the premade asteroid will instantly appear on the screen. Because the asteroid has already built in the display list, OpenGL doesn't have to figure out how to build it. It's prebuilt in memory. This takes alot of strain off your processor and allows your programs to run alot faster! So are you ready to learn? :) We'll call this the Q-Bert Display List demo. What you'll end up with is a Q-Bert type screen made up of 15 cubes. Each cube is made up of a TOP, and a BOX. The top will be a seperate display list so that we can color it a darker shade. The box is a cube without the top :) This code is based around lesson 6. I'll rewrite most of the program so it's easier to see where I've made changes. The follow lines of code are standard code used in just about all the lessons. #include <windows.h> // Header File For Windows HDC hDC=NULL; // Private GDI Device Context bool keys[256]; // Array Used For The Keyboard Routine After that we have 2 variables called xloop and yloop which are used to position the cubes on the screen and 2 variables called xrot and yrot that are used to rotate the cubes on the x axis and y axis. GLuint texture[1]; // Storage For One Texture GLfloat xrot; // Rotates Cube On The X Axis The second color array we create is for Dark Red, Dark Orange, Dark Yellow, Dark Green and Dark Blue. The dark colors will be used to draw the top of the boxes. We want the lid to be darker than the rest of the box. static GLfloat boxcol[5][3]= // Array For Box Colors static GLfloat topcol[5][3]= // Array For Top Colors LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); // Declaration For WndProc GLvoid BuildLists() // Build Box Display List box=glGenLists(2); // Building Two Lists We use the command glNewList() to do the job. You'll notice box is the first parameter. This tells OpenGL to store the list in the memory location that box points to. The second parameter GL_COMPILE tells OpenGL we want to prebuild the list in memory so that OpenGL doesn't have to figure out how to create the object ever time we draw it. GL_COMPILE is similar to programming. If you write a program, and load it into your compiler, you have to compile it every time you want to run it. If it's already compiled into an .EXE file, all you have to do is click on the .exe to run it. No compiling needed. Once GL has compiled the display list, it's ready to go, no more compiling required. This is where we get the speed boost from using display lists. glNewList(box,GL_COMPILE); // New Compiled box Display List You can put just about any command you want between glNewList() and glEndList(). You can set colors, you can change textures, etc. The only type of code you CAN'T add is code that would change the display list on the fly. Once the display list is built, you CAN'T change it. If you added the line glColor3ub(rand()%255,rand()%255,rand()%255) into the code below, you might think that each time you draw the object to the screen it will be a different color. But because the list is only CREATED once, the color will not change each time you draw it to the screen. Whatever color the object was when it was first made is the color it will remain. If you want to change the color of the display list, you have to change it BEFORE you draw the display list to the screen. I'll explain more on this later. glBegin(GL_QUADS); // Start Drawing Quads glEndList(); // Done Building The box List top=box+1; // top List Value Is box List Value +1 glNewList(top,GL_COMPILE); // New Compiled top Display List glBegin(GL_QUADS); // Start Drawing Quad glEndList(); // Done Building The top Display List if (TextureImage[0]=LoadBMP("Data/Cube.bmp")) // Load The Bitmap The init code only has a few changes. I've added the line BuildList(). This will jump to the section of code that builds the display lists. Notice that BuildList() is after LoadGLTextures(). It's important to know the order things should go in. First we build the textures, so when we create our display lists, there's a texture already created that we can map onto the cube. int InitGL(GLvoid) // All Setup For OpenGL Goes Here The last line GL_COLOR_MATERIAL lets us add color to texture maps. If we don't enable material coloring, the textures will always be their original color. glColor3f(r,g,b) will have no affect on the coloring. So it's important to enable this. glEnable(GL_LIGHT0); // Quick And Dirty Lighting (Assumes Light0 Is Set Up) glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); // Nice Perspective Correction Then we bind a texture to the cube. I could have added this line inside the display list code, but by leaving it outside the display list, I can change the texture whenever I want. If I added the line glBindTexture(GL_TEXTURE_2D, texture[0]) inside the display list code, the display list would be built with whatever texture I selected permanently mapped onto it. int DrawGLScene(GLvoid) // Here's Where We Do All The Drawing glBindTexture(GL_TEXTURE_2D, texture[0]); // Select The Texture for (yloop=1;yloop<6;yloop++) // Loop Through The Y Plane for (xloop=0;xloop<yloop;xloop++) // Loop Through The X Plane glLoadIdentity(); // Reset The View We move to the right 1.4 units so that the pyramid is in the center of the screen. Then we multiply xloop by 2.8 and add the 1.4 to it. (we multiply by 2.8 so that the cubes are not on top of eachother (2.8 is roughly the width of the cubes when they're rotated 45 degrees). Finally we subtract yloop*1.4. This moves the cubes left depending on what row we're on. If we didn't move to the left, the pyramid would line up on the left side (wouldn't really look a pyramid would it). On the Y axis we subtract yloop from 6 otherwise the pyramid would be built upside down. Then we multiply the result by 2.4. Otherwise the cubes would be on top of eachother on the y axis (2.4 is roughly the height of each cube). Then we subtract 7 so that the pyramid starts at the bottom of the screen and is built upwards. Finally, on the Z axis we move into the screen 20 units. That way the pyramid fits nicely on the screen. // Position The Cubes On The Screen Finally we add xrot. This gives us keyboard control over the angle. (fun to play around with). After we've rotated on the x axis, we rotate 45 degrees on the y axis, and add yrot so we have keyboard control on the y axis. glRotatef(45.0f-(2.0f*yloop)+xrot,1.0f,0.0f,0.0f); // Tilt The Cubes Up And Down glColor3fv(boxcol[yloop-1]); // Select A Box Color The box will be drawn using the color we selected with glColor3fv(), at the position we translated to. glCallList(box); // Draw The Box glColor3fv(topcol[yloop-1]); // Select The Top Color glCallList(top); // Draw The Top SwapBuffers(hDC); // Swap Buffers (Double Buffering) if (keys[VK_F1]) // Is F1 Being Pressed? I hope you've enjoy the tutorial. If you have any questions or feel somethings not clear, please email me and let me know. Jeff Molofee (NeHe) |
-- 作者:snowtower -- 发布时间:10/16/2007 3:00:00 AM -- 顶啊 真是好东西 谢谢楼主 |
W 3 C h i n a ( since 2003 ) 旗 下 站 点 苏ICP备05006046号《全国人大常委会关于维护互联网安全的决定》《计算机信息网络国际联网安全保护管理办法》 |
140.625ms |