以文本方式查看主题 - 中文XML论坛 - 专业的XML技术讨论区 (http://bbs.xml.org.cn/index.asp) -- 『 C/C++编程思想 』 (http://bbs.xml.org.cn/list.asp?boardid=61) ---- [推荐]NeHe OpenGL教程(中英文版附带VC++源码)Lesson 09-lesson 10 (http://bbs.xml.org.cn/dispbbs.asp?boardid=61&rootid=&id=53822) |
-- 作者:一分之千 -- 发布时间:10/15/2007 4:51:00 PM -- Lesson 09 Welcome to Tutorial 9. By now you should have a very good understanding of OpenGL. You've learned everything from setting up an OpenGL Window, to texture mapping a spinning object while using lighting and blending. This will be the first semi-advanced tutorial. You'll learn the following: Moving bitmaps around the screen in 3D, removing the black pixels around the bitmap (using blending), adding color to a black & white texture and finally you'll learn how to create fancy colors and simple animation by mixing different colored textures together. We'll be modifying the code from lesson one for this tutorial. We'll start off by adding a few new variables to the beginning of the program. I'll rewrite the entire section of code so it's easier to see where the changes are being made. #include <windows.h> // Header File For Windows HDC hDC=NULL; // Private GDI Device Context bool keys[256]; // Array Used For The Keyboard Routine BOOL twinkle; // Twinkling Stars const num=50; // Number Of Stars To Draw So now we have this group of data that describes the color, distance and angle of a star on the screen. Unfortunately we have more than one star to keep track of. Instead of creating 50 red values, 50 green values, 50 blue values, 50 distance values and 50 angle values, we just create an array called star. Each number in the star array will hold all of the information in our structure called stars. We make the star array in the 8th line below. If we break down the 8th line: stars star[num]. This is what we come up with. The type of array is going to be stars. stars is a structure. So the array is going to hold all of the information in the structure. The name of the array is star. The number of arrays is [num]. So because num=50, we now have an array called star. Our array stores the elements of the structure stars. Alot easier than keeping track of each star with seperate variables. Which would be a very stupid thing to do, and would not allow us to add remove stars by changing the const value of num. typedef struct // Create A Structure For Star loop is a variable we'll use in the program to draw all 50 stars, and texture[1] will be used to store the one b&w texture that we load in. If you wanted more textures, you'd increase the value from one to however many textures you decide to use. GLfloat zoom=-15.0f; // Viewing Distance Away From Stars GLuint loop; // General Loop Variable LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); // Declaration For WndProc AUX_RGBImageRec *LoadBMP(char *Filename) // Loads A Bitmap Image if (!Filename) // Make Sure A Filename Was Given File=fopen(Filename,"r"); // Check To See If The File Exists if (File) // Does The File Exist? int LoadGLTextures() // Load Bitmaps And Convert To Textures AUX_RGBImageRec *TextureImage[1]; // Create Storage Space For The Texture memset(TextureImage,0,sizeof(void *)*1); // Set The Pointer To NULL // Load The Bitmap, Check For Errors, If Bitmap's Not Found Quit glGenTextures(1, &texture[0]); // Create One Texture // Create Linear Filtered Texture if (TextureImage[0]) // If Texture Exists free(TextureImage[0]); // Free The Image Structure return Status; // Return The Status int InitGL(GLvoid) // All Setup For OpenGL Goes Here glEnable(GL_TEXTURE_2D); // Enable Texture Mapping for (loop=0; loop<num; loop++) // Create A Loop That Goes Through All The Stars You'll notice that the colors for each star are made up of random values from 0 to 255. You might be wondering how we can use such large values when normally the colors are from 0.0f to 1.0f. When we set the color we'll use glColor4ub instead of glColor4f. ub means Unsigned Byte. A byte can be any value from 0 to 255. In this program it's easier to use bytes than to come up with a random floating point value. star[loop].dist=(float(loop)/num)*5.0f; // Calculate Distance From The Center int DrawGLScene(GLvoid) // Here's Where We Do All The Drawing for (loop=0; loop<num; loop++) // Loop Through All The Stars The second line of code moves to a positive value on the x plane. Normally a positive value on x would move us to the right side of the screen (where +x usually is), but because we've rotated on the y plane, the +x could be anywhere. If we rotated by 180 degrees, it would be on the left side of the screen instead of the right. So when we move forward on the positive x plane, we could be moving left, right, forward or backward. glRotatef(star[loop].angle,0.0f,1.0f,0.0f); // Rotate To The Current Stars Angle We do this by cancelling any rotations that we've made, just before we draw the star. You cancel the rotations in reverse order. So above we tilted the screen, then we rotated to the stars current angle. In reverse order, we'd un-rotate (new word) the stars current angle. To do this we use the negative value of the angle, and rotate by that. So if we rotated the star by 10 degrees, rotating it back -10 degrees will make the star face the screen once again on that axis. So the first line below cancels the rotation on the y axis. Then we need to cancel the screen tilt on the x axis. To do that we just tilt the screen by -tilt. After we've cancelled the x and y rotations, the star will face the screen completely. glRotatef(-star[loop].angle,0.0f,1.0f,0.0f); // Cancel The Current Stars Angle If twinkle is enabled, each star will be drawn twice. This will slow down the program a little depending on what type of computer you have. If twinkle is enabled, the colors from the two stars will mix together creating some really nice colors. Also because this star does not spin, it will appear as if the stars are animated when twinkling is enabled. (look for yourself if you don't understand what I mean). Notice how easy it is to add color to the texture. Even though the texture is black and white, it will become whatever color we select before we draw the texture. Also take note that we're using bytes for the color values rather than floating point numbers. Even the alpha value is a byte. if (twinkle) // Twinkling Stars Enabled glRotatef(spin,0.0f,0.0f,1.0f); // Rotate The Star On The Z Axis spin+=0.01f; // Used To Spin The Stars if (star[loop].dist<0.0f) // Is The Star In The Middle Yet The lines below check to see if the T key has been pressed. If it has been pressed and it's not being held down the following will happen. If twinkle is FALSE, it will become TRUE. If it was TRUE, it will become FALSE. Once T is pressed tp will become TRUE. This prevents the code from running over and over again if you hold down the T key. SwapBuffers(hDC); // Swap Buffers (Double Buffering) if (!keys['T']) // Has The T Key Been Released if (keys[VK_UP]) // Is Up Arrow Being Pressed if (keys[VK_DOWN]) // Is Down Arrow Being Pressed if (keys[VK_PRIOR]) // Is Page Up Being Pressed if (keys[VK_NEXT]) // Is Page Down Being Pressed if (keys[VK_F1]) // Is F1 Being Pressed? Jeff Molofee (NeHe) |
-- 作者:一分之千 -- 发布时间:10/15/2007 4:52:00 PM -- 第十课 在这一课中,你将学会如何加载3D世界,并在3D世界中漫游。这一课使用第一课的代码,当然在课程说明中我只介绍改变了代码。 typedef struct tagSECTOR // 创建Sector区段结构 typedef struct tagTRIANGLE // 创建Triangle三角形结构 typedef struct tagVERTEX // 创建Vertex顶点结构 问题是,怎样才能从文件中取得数据资料呢?首先,创建一个叫做SetupWorld()的新函数。把这个文件定义为filein,并且使用只读方式打开文件。我们必须在使用完毕之后关闭文件。大家一起来看看现在的代码: // 先前的定义: char* worldfile = "data\\world.txt"; ... fclose(filein); // 关闭文件 void readstr(FILE *f,char *string) // 读入一个字符串 { int numtriangles; // 区段中的三角形数量 // 先前的定义: SECTOR sector1; if (keys[VK_RIGHT]) // 右方向键按下了么? if (keys[VK_LEFT]) // 左方向键按下了么? if (keys[VK_UP]) // 向上方向键按下了么? if (keys[VK_DOWN]) // 向下方向键按下了么? int DrawGLScene(GLvoid) // 绘制 OpenGL 场景 int numtriangles; // 保有三角形数量的整数 glRotatef(lookupdown,1.0f,0,0); // 上下旋转 glTranslatef(xtrans, ytrans, ztrans); // 以游戏者为中心的平移场景 numtriangles = sector1.numtriangles; // 取得Sector1的三角形数量 // 逐个处理三角形 x_m = sector1.triangle[loop_m].vertex[1].x; // 第二点的 X 分量 x_m = sector1.triangle[loop_m].vertex[2].x; // 第三点的 X 分量 |
-- 作者:一分之千 -- 发布时间:10/15/2007 4:52:00 PM -- Lesson 10 This tutorial was created by Lionel Brits (遝telgeuse). This lesson only explains the sections of code that have been added. By adding just the lines below, the program will not run. If you're interested to know where each of the lines of code below go, download the source code, and follow through it, as you read the tutorial. Welcome to the infamous Tutorial 10. By now you have a spinning cube or a couple of stars, and you have the basic feel for 3D programming. But wait! Don't run off and start to code Quake IV just yet. Spinning cubes just aren't going to make cool deathmatch opponents :-) These days you need a large, complicated and dynamic 3D world with 6 degrees of freedom and fancy effects like mirrors, portals, warping and of course, high framerates. This tutorial explains the basic "structure" of a 3D world, and also how to move around in it. Data structure While it is perfectly alright to code a 3D environment as a long series of numbers, it becomes increasingly hard as the complexity of the environment goes up. For this reason, we must catagorize our data into a more workable fashion. At the top of our list is the sector. Each 3D world is basically a collection of sectors. A sector can be a room, a cube, or any enclosed volume. typedef struct tagSECTOR // Build Our Sector Structure typedef struct tagTRIANGLE // Build Our Triangle Structure typedef struct tagVERTEX // Build Our Vertex Structure Storing our world data inside our program makes our program quite static and boring. Loading worlds from disk, however, gives us much more flexibility as we can test different worlds without having to recompile our program. Another advantage is that the user can interchange worlds and modify them without having to know the in's and out's of our program. The type of data file we are going to be using will be text. This makes for easy editing, and less code. We will leave binary files for a later date. The question is, how do we get our data from our file. First, we create a new function called SetupWorld(). We define our file as filein, and we open it for read-only access. We must also close our file when we are done. Let us take a look at the code so far: // Previous Declaration: char* worldfile = "data\\world.txt"; ... fclose(filein); // Close Our File void readstr(FILE *f,char *string) // Read In A String { NUMPOLLIES n Here's the code to read the number of triangles: int numtriangles; // Number Of Triangles In Sector // Previous Declaration: SECTOR sector1; Now that we can load our sector into memory, we need to display it on screen. So far we have done some minor rotations and translations, but our camera was always centered at the origin (0,0,0). Any good 3D engine would have the user be able to walk around and explore the world, and so will ours. One way of doing this is to move the camera around and draw the 3D environment relative to the camera position. This is slow and hard to code. What we will do is this: if (keys[VK_RIGHT]) // Is The Right Arrow Being Pressed? if (keys[VK_LEFT]) // Is The Left Arrow Being Pressed? if (keys[VK_UP]) // Is The Up Arrow Being Pressed? if (keys[VK_DOWN]) // Is The Down Arrow Being Pressed? Next you ask me: What is this walkbias? It's a word I invented :-) It's basically an offset that occurs when a person walks around (head bobbing up and down like a buoy. It simply adjusts the camera's Y position with a sine wave. I had to put this in, as simply moving forwards and backwards didn't look to great. Now that we have these variables down, we can proceed with steps two and three. This will be done in the display loop, as our program isn't complicated enough to merit a seperate function. int DrawGLScene(GLvoid) // Draw The OpenGL Scene int numtriangles; // Integer To Hold The Number Of Triangles glRotatef(lookupdown,1.0f,0,0); // Rotate Up And Down To Look Up And Down glTranslatef(xtrans, ytrans, ztrans); // Translate The Scene Based On Player Position numtriangles = sector1.numtriangles; // Get The Number Of Triangles In Sector 1 // Process Each Triangle x_m = sector1.triangle[loop_m].vertex[1].x; // X Vertex Of 2nd Point x_m = sector1.triangle[loop_m].vertex[2].x; // X Vertex Of 3rd Point So now you're probably thinking where to go next. Don't even consider using this code to make a full-blown 3D engine, since that's not what it's designed for. You'll probably want more than one sector in your game, especially if you're going to implement portals. You'll also want to have polygons with more than 3 vertices, again, essential for portal engines. My current implementation of this code allows for multiple sector loading and does backface culling (not drawing polygons that face away from the camera). I'll write a tutorial on that soon, but as it uses alot of math, I'm going to write a tutorial on matrices first. NeHe (05/01/00): I've added FULL comments to each of the lines listed in this tutorial. Hopefully things make more sense now. Only a few of the lines had comments after them, now they all do :) Please, if you have any problems with the code/tutorial (this is my first tutorial, so my explanations are a little vague), don't hesitate to email me mailto:iam@cadvision.com Until next time... Lionel Brits (遝telgeuse) Jeff Molofee (NeHe) |
-- 作者:长风万里 -- 发布时间:10/28/2007 4:58:00 AM -- 谢谢你,正在学习OpenGL,不知道我能下载附件吗? |
-- 作者:cjopengler -- 发布时间:12/8/2009 10:02:00 AM -- 第9课翻译有错误: spin+=0.01f; // 星星的公转 ===>> 星星的自转 star[loop].angle+=float(loop)/num; // 改变星星的自转角度 ===>>星星的公转角度 |
-- 作者:JL2012JL -- 发布时间:4/11/2013 1:29:00 PM -- 这教程真心不错,学习了 |
W 3 C h i n a ( since 2003 ) 旗 下 站 点 苏ICP备05006046号《全国人大常委会关于维护互联网安全的决定》《计算机信息网络国际联网安全保护管理办法》 |
203.125ms |