以文本方式查看主题 - 计算机科学论坛 (http://bbs.xml.org.cn/index.asp) -- 『 C/C++编程思想 』 (http://bbs.xml.org.cn/list.asp?boardid=61) ---- [推荐]NeHe OpenGL教程(中英文版附带VC++源码)Lesson 37-lesson 38 (http://bbs.xml.org.cn/dispbbs.asp?boardid=61&rootid=&id=54290) |
-- 作者:一分之千 -- 发布时间:10/25/2007 9:43:00 AM -- [推荐]NeHe OpenGL教程(中英文版附带VC++源码)Lesson 37-lesson 38 什么是卡通了,一个轮廓加上少量的几种颜色。使用一维纹理映射,你也可以实现这种效果。 #include <math.h> typedef struct tagMATRIX // 保存OpenGL矩阵的结构体 typedef struct tagVECTOR // 存储一个单精度向量的结构体 typedef struct tagVERTEX // 存放单一顶点的结构 typedef struct tagPOLYGON // 存储单一多边形的结构 bool outlineDraw = true; // 绘制轮廓的标记 VECTOR lightAngle; // 灯光的方向 float modelAngle = 0.0f; // 模型的Y轴角度 POLYGON *polyData = NULL; // 多边形数据 GLuint shaderTexture[1]; // 存储纹理ID BOOL ReadMesh () // 读“model.txt” 文件 if (!In) fread (&polyNum, sizeof (int), 1, In); // 读文件头,多边形的个数 polyData = new POLYGON [polyNum]; // 分配内存 fread (&polyData[0], sizeof (POLYGON) * polyNum, 1, In);// 把所有多边形的数据读入 fclose (In); // 关闭文件 return TRUE; // 工作完成 inline float DotProduct (VECTOR &V1, VECTOR &V2) //计算两个向量之间的角度 inline float Magnitude (VECTOR &V) // 计算向量的长度 void Normalize (VECTOR &V) // 创建一个单位长度的向量 if (M != 0.0f) // 确保我们没有被0隔开 void RotateVector (MATRIX &M, VECTOR &V, VECTOR &D) // 利用提供的矩阵旋转一个向量 // 一些GL 初始代码和用户初始化从这里开始 char Line[255]; // 255个字符的存储量 glShadeModel (GL_SMOOTH); // 使用色彩阴影平滑 glHint (GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); // 提高计算精度 glEnable (GL_CULL_FACE); // 启用剔除多边形功能 glDisable (GL_LIGHTING); // 使 OpenGL 灯光不可用 In = fopen ("Data\\shader.txt", "r"); // 打开阴影文件 if (In) // 检查文件是否打开 fgets (Line, 255, In); // 获得当前线条 // 从头到尾复制这个值 fclose (In); // 关闭文件 else glGenTextures (1, &shaderTexture[0]); // 获得一个自由的纹理ID glBindTexture (GL_TEXTURE_1D, shaderTexture[0]); // 绑定这个纹理。 从现在开始它变为一维 // 使用邻近点过滤 // 设置纹理 lightAngle.X = 0.0f; Normalize (lightAngle); return ReadMesh (); // 读取Mesh文件,并返回 void Deinitialize (void) delete [] polyData; // 删除多边形数据 1 = 锁定轮廓绘制 <UP> =增加线宽 void Update (DWORD milliseconds) // 这里执行动作更新 g_keys->keyDown [' '] = FALSE; if (g_keys->keyDown ['1'] == TRUE) // 1是否被按下 g_keys->keyDown ['1'] = FALSE; if (g_keys->keyDown ['2'] == TRUE) // 2是否被按下 g_keys->keyDown ['2'] = FALSE; if (g_keys->keyDown [VK_UP] == TRUE) // 上键增加线的宽度 g_keys->keyDown [VK_UP] = FALSE; if (g_keys->keyDown [VK_DOWN] == TRUE) // 下减少线的宽度 g_keys->keyDown [VK_DOWN] = FALSE; if (modelRotate) // 是否旋转 void Draw (void) float TmpShade; // 临时色度值 MATRIX TmpMatrix; // 临时 MATRIX 结构体 glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // 清除缓冲区 if (outlineSmooth) // 检查我们是否想要 Anti-Aliased 线条 else // 否则不启用 glTranslatef (0.0f, 0.0f, -2.0f); // 移入屏幕两个单位 glGetFloatv (GL_MODELVIEW_MATRIX, TmpMatrix.Data); // 获得产生的矩阵 // 卡通渲染代码 glColor3f (1.0f, 1.0f, 1.0f); // 调整模型的颜色 glBegin (GL_TRIANGLES); // 告诉 OpenGL 我们即将绘制三角形 for (i = 0; i < polyNum; i++) // 从头到尾循环每一个多边形 // 通过矩阵旋转 Normalize (TmpVector); // 规格化这个新法线 // 计算色度值 if (TmpShade < 0.0f) glTexCoord1f (TmpShade); // 规定纹理的纵坐标当作这个色度值 glEnd (); // 告诉OpenGL 完成绘制 glDisable (GL_TEXTURE_1D); // 1D 纹理不可用 // 轮廓代码 glPolygonMode (GL_BACK, GL_LINE); // 绘制轮廓线 glCullFace (GL_FRONT); // 剔出前面的多边形 glDepthFunc (GL_LEQUAL); // 改变深度模式 glColor3fv (&outlineColor[0]); // 规定轮廓颜色 glBegin (GL_TRIANGLES); // 告诉OpenGL我们想要绘制什么 for (i = 0; i < polyNum; i++) // 从头到尾循环每一个多边形 glEnd (); // 告诉 OpenGL我们已经完成 glDepthFunc (GL_LESS); // 重置深度测试模式 glCullFace (GL_BACK); // 重置剔出背面多边形 glPolygonMode (GL_BACK, GL_FILL); // 重置背面多边形绘制方式 glDisable (GL_BLEND); // 混合不可用 |
-- 作者:一分之千 -- 发布时间:10/25/2007 9:43:00 AM -- Lesson 37 Cel-Shading By Sami "MENTAL" Hamlaoui Seeing as people still e-mail me asking for source code to the article I wrote on GameDev.net a while ago, and seeing as the 2nd version of that article (with source for every API out there) isn't even close to being halfway finished, I've hacked together this tutorial for NeHe (that was actually going to be the original intention of the article) so all of you OpenGL gurus can play around with it. Sorry for the choice of model, but I've been playing Quake 2 extensivly recently... :) Note: The original article for this code can be found at: http://www.gamedev.net/reference/programming/features/celshading. This tutorial doesn't actually explain the theory, just the code. WHY it works can be found at the above link. Now for crying out loud STOP E-MAILING ME REQUESTS FOR SOURCE CODE!!!! Enjoy :). First of all, we need to include a few extra header files. The first one (math.h) is so we can use the sqrtf (square root) function, and the second (stdio.h) is for file access. #include <math.h> // Header File For The Math Library typedef struct tagMATRIX // A Structure To Hold An OpenGL Matrix typedef struct tagVECTOR // A Structure To Hold A Single Vector typedef struct tagVERTEX // A Structure To Hold A Single Vertex typedef struct tagPOLYGON // A Structure To Hold A Single Polygon bool outlineDraw = true; // Flag To Draw The Outline VECTOR lightAngle; // The Direction Of The Light float modelAngle = 0.0f; // Y-Axis Angle Of The Model POLYGON *polyData = NULL; // Polygon Data GLuint shaderTexture[1]; // Storage For One Texture BOOL ReadMesh () // Reads The Contents Of The "model.txt" File if (!In) fread (&polyNum, sizeof (int), 1, In); // Read The Header (i.e. Number Of Polygons) polyData = new POLYGON [polyNum]; // Allocate The Memory fread (&polyData[0], sizeof (POLYGON) * polyNum, 1, In);// Read In All Polygon Data fclose (In); // Close The File return TRUE; // It Worked inline float DotProduct (VECTOR &V1, VECTOR &V2) // Calculate The Angle Between The 2 Vectors inline float Magnitude (VECTOR &V) // Calculate The Length Of The Vector void Normalize (VECTOR &V) // Creates A Vector With A Unit Length Of 1 if (M != 0.0f) // Make Sure We Don't Divide By 0 void RotateVector (MATRIX &M, VECTOR &V, VECTOR &D) // Rotate A Vector Using The Supplied Matrix // Any GL Init Code & User Initialiazation Goes Here char Line[255]; // Storage For 255 Characters FILE *In = NULL; // File Pointer glShadeModel (GL_SMOOTH); // Enables Smooth Color Shading glEnable (GL_CULL_FACE); // Enable OpenGL Face Culling glDisable (GL_LIGHTING); // Disable OpenGL Lighting In = fopen ("Data\\shader.txt", "r"); // Open The Shader File if (In) // Check To See If The File Opened fgets (Line, 255, In); // Get The Current Line // Copy Over The Value fclose (In); // Close The File else glGenTextures (1, &shaderTexture[0]); // Get A Free Texture ID glBindTexture (GL_TEXTURE_1D, shaderTexture[0]); // Bind This Texture. From Now On It Will Be 1D // For Crying Out Loud Don't Let OpenGL Use Bi/Trilinear Filtering! // Upload lightAngle.X = 0.0f; // Set The X Direction Normalize (lightAngle); // Normalize The Light Direction return ReadMesh (); // Return The Value Of ReadMesh void Deinitialize (void) // Any User DeInitialization Goes Here delete [] polyData; // Delete The Polygon Data <SPACE> = Toggle rotation 1 = Toggle outline drawing 2 = Toggle outline anti-alaising <UP> = Increase line width <DOWM> = Decrease line width void Update (DWORD milliseconds) // Perform Motion Updates Here g_keys->keyDown [' '] = FALSE; if (g_keys->keyDown ['1'] == TRUE) // Is The Number 1 Being Pressed? g_keys->keyDown ['1'] = FALSE; if (g_keys->keyDown ['2'] == TRUE) // Is The Number 2 Being Pressed? g_keys->keyDown ['2'] = FALSE; if (g_keys->keyDown [VK_UP] == TRUE) // Is The Up Arrow Being Pressed? g_keys->keyDown [VK_UP] = FALSE; if (g_keys->keyDown [VK_DOWN] == TRUE) // Is The Down Arrow Being Pressed? g_keys->keyDown [VK_DOWN] = FALSE; if (modelRotate) // Check To See If Rotation Is Enabled void Draw (void) The TmpMatrix, TmpVector and TmpNormal structures are also used to calculate the vertex data. TmpMatrix is set once at the start of the function and never changed until Draw is called again. TmpVector and TmpNormal on the other hand, change when another vertex is processed. float TmpShade; // Temporary Shader Value MATRIX TmpMatrix; // Temporary MATRIX Structure glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear The Buffers if (outlineSmooth) // Check To See If We Want Anti-Aliased Lines else // We Don't Want Smooth Lines We then grab the newly created matrix from OpenGL and store it in TmpMatrix. glTranslatef (0.0f, 0.0f, -2.0f); // Move 2 Units Away From The Screen glGetFloatv (GL_MODELVIEW_MATRIX, TmpMatrix.Data); // Get The Generated Matrix // Cel-Shading Code glColor3f (1.0f, 1.0f, 1.0f); // Set The Color Of The Model glBegin (GL_TRIANGLES); // Tell OpenGL That We're Drawing Triangles for (i = 0; i < polyNum; i++) // Loop Through Each Polygon // Rotate This By The Matrix Normalize (TmpVector); // Normalize The New Normal // Calculate The Shade Value if (TmpShade < 0.0f) glTexCoord1f (TmpShade); // Set The Texture Co-ordinate As The Shade Value glEnd (); // Tell OpenGL To Finish Drawing glDisable (GL_TEXTURE_1D); // Disable 1D Textures So, we enable blending and set the blend mode. We tell OpenGL to render backfacing polygons as lines, and set the width of those lines. We cull all front facing polygons, and set the depth test to less than or equal to the current Z value. After this the color of the line is set, and we loop though each polygon, drawing its vertices. We only need to pass the vertex position, and not the normal or shade value because all we want is an outline. // Outline Code glPolygonMode (GL_BACK, GL_LINE); // Draw Backfacing Polygons As Wireframes glCullFace (GL_FRONT); // Don't Draw Any Front-Facing Polygons glDepthFunc (GL_LEQUAL); // Change The Depth Mode glColor3fv (&outlineColor[0]); // Set The Outline Color glBegin (GL_TRIANGLES); // Tell OpenGL What We Want To Draw for (i = 0; i < polyNum; i++) // Loop Through Each Polygon glEnd (); // Tell OpenGL We've Finished glDepthFunc (GL_LESS); // Reset The Depth-Testing Mode glCullFace (GL_BACK); // Reset The Face To Be Culled glPolygonMode (GL_BACK, GL_FILL); // Reset Back-Facing Polygon Drawing Mode glDisable (GL_BLEND); // Disable Blending Jeff Molofee (NeHe) |
-- 作者:一分之千 -- 发布时间:10/25/2007 9:45:00 AM -- Lesson 38 Welcome to the 38th NeHe Productions Tutorial. It's been awhile since my last tutorial, so my writing may be a little rusty. That and the fact that I've been up for almost 24 hours working on the code :) So you know how to texture map a quad, and you know how to load bitmap images, tga's, etc. So how the heck do you texture map a Triangle? And what if you want to hide your textures in the .EXE file? The two questions I'm asked on a daily basis will soon be answered, and once you see how easy it is, you'll wonder why you never thought of the solution :) Rather than trying to explain everything in great detail I'm going to include a few screenshots, so you know exactly what it is I'm talking about. I will be using the latest basecode. You can download the code from the main page under the heading "NeHeGL I Basecode" or you can download the code at the end of this tutorial. The first thing we need to do is add the images to the resource file. Alot of you have already figured out how to do this, unfortunately, you miss a few steps along the way and end up with a useless resource file filled with bitmaps that you can't use. Remember, this tutorial was written in Visual C++ 6.0. If you're using anything other than Visual C++, the resource portion of this tutorial wont make sense (especially the screenshots). * Currently you can only use 24 bit BMP images. There is alot of extra code to load 8 bit BMP files. I'd love to hear from anyone that has a tiny / optimized BMP loader. The code I have right now to load 8 and 24 bit BMP's is a mess. Something that uses LoadImage would be nice.
You are now asked what type of resource you wish to import. Select BITMAP and click the IMPORT button.
Once you are done, select FILE from the main menu and then SAVE ALL because you have just created a new resource file, windows will ask you what you want to call the file. You can save the file with the default filename or you can rename it to lesson38.rc. Once you have decided on a name click SAVE. This is the point that most people make it to. You have a resource file. It's full of Bitmap images and it's been saved to the Hard Drive. To use the images, you need to complete a few more steps.
The next thing you need to do is add the resource file to your current project. Select PROJECT from the main menu, ADD TO PROJECT, and then FILES.
Select the resource.h file, and the resource file (Lesson38.rc). Hold down control to select more than one file, or add each file individually.
The last thing to do is make sure the resource file (Lesson38.rc) was put in the RESOURCE FILES folder. As you can see in the picture above, it was put in the SOURCE FILES folder. Click it with your mouse and drag it down to the RESOURCE FILES folder. Once the resource file has been moved select FILE from the main menu and SAVE ALL. The hard part has been done! ...Way too many pictures :) So now we start on the code! The most important line in the section of code below is #include "resource.h". Without this line, you will get a bunch of undeclared identifier errors when you try to compile the code. The resource.h file declares the objects inside the resource file. So if you want to grab data from IDB_BUTTERFLY1 you had better remember to include the header file! #include <windows.h> // Header File For Windows #pragma comment( lib, "opengl32.lib" ) // Search For OpenGL32.lib While Linking #ifndef CDS_FULLSCREEN // CDS_FULLSCREEN Is Not Defined By Some GL_Window* g_window; The structure will be used to hold information about 50 different objects that we'll have moving around the screen. tex will keep track of which texture to use for the object. x is the xposition of the object, y is the y position of the object, z is the objects position on the z-axis, yi will be a random number used to control how fast the object falls. spinz will be used to rotate the object on it's z-axis as it falls, spinzi is another random number used to control how fast the object spins. flap will be used to control the objects wings (more on this later) and fi is a random value that controls how fast the wings flap. We create 50 instances of obj[ ] based on the object structure. // User Defined Variables struct object // Create A Structure Called Object object obj[50]; // Create 50 Objects Using The Object Structure We start off with a random texture from 0 to 2. This will select a random colored butterfly. We assign a random x position from -17.0f to +17.0f. The starting y position will be 18.0f, which will put the object just above the screen so we can't see it right off the start. The z position is also a random value from -10.0f to -40.0f. The spinzi value is a random value from -1.0f to 1.0f. flap is set to 0.0f (which will be the center position for the wings). Finally, the flap speed (fi) and fall speed (yi) are also given a random value. void SetObject(int loop) // Sets The Initial Value Of Each Object (Random) hBMP is a pointer to our bitmap file. It will tell our program where to get the data from. BMP is a bitmap structure that we can fill with data from our resource file. We tell our program which ID's to use in the third line of code. We want to load IDB_BUTTEFLY1, IDB_BUTTEFLY2 and IDB_BUTTERFLY3. If you wish to add more images, add the image to the resource file, and add the ID to Texture[ ]. void LoadGLTextures() // Creates Textures From Bitmaps In The Resource File // The ID Of The 3 Bitmap Images We Want To Load From The Resource File glGenTextures(sizeof(Texture), &texture[0]); // Generate 3 Textures (sizeof(Texture)=3 ID's) The next two parameters (0,0) are the desired height and width of the image in pixels. We want to use the default size so we set both to 0. The last parameter (LR_CREATEDIBSECTION) returns a DIB section bitmap, which is a bitmap without all the color information stored in the data. Exactly what we need. hBMP points to the bitmap data that is loaded by LoadImage( ). hBMP=(HBITMAP)LoadImage(GetModuleHandle(NULL),MAKEINTRESOURCE(Texture[loop]), IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION); If data exists, we use GetObject( ) to grab all of the data (sizeof(BMP)) from hBMP and store it in our BMP (bitmap structure). glPixelStorei tells OpenGL that the data is stored in word alignments (4 bytes per pixel). We then bind to our texture, set the filtering to GL_LINEAR_MIPMAP_LINEAR (nice and smooth), and generate the texture. Notice that we use BMP.bmWidth and BMP.bmHeight to get the height and width of the bitmap. We also have to swap the Red and Blue colors using GL_BGR_EXT. The actual resource data is retreived from BMP.bmBits. The last step is to delete the bitmap object freeing all system resources associated with the object. if (hBMP) // Does The Bitmap Exist? // Generate Mipmapped Texture (3 Bytes, Width, Height And Data From The BMP) BOOL Initialize (GL_Window* window, Keys* keys) // Any GL Init Code & User Initialiazation Goes Here // Start Of User Initialization glClearColor (0.0f, 0.0f, 0.0f, 0.5f); // Black Background for (int loop=0; loop<50; loop++) // Loop To Initialize 50 Objects return TRUE; // Return TRUE (Initialization Successful) void Deinitialize (void) // Any User DeInitialization Goes Here void Update (DWORD milliseconds) // Perform Motion Updates Here if (g_keys->keyDown [VK_F1] == TRUE) // Is F1 Being Pressed? The truth is, you can texture an image to any shape you want. With very little effort. The image can match the shape or it can be a completely different pattern. It really doesn't matter. First things first... we clear the screen and set up a loop to render all 50 of our butterflies (objects). void Draw (void) // Draw The Scene for (int loop=0; loop<50; loop++) // Loop Of 50 (Draw 50 Objects) We position the butterfly using glTranslatef() then rotate the buttefly 45 degrees on it's X axis. This tilts the butterfly a little more towards the viewer so it doesn't look like a flat 2D object. The final rotation spins the butterfly on it's z-axis which makes it spin as it falls down the screen. glLoadIdentity (); // Reset The Modelview Matrix In the code below, we draw the first triangle. We start at the top right corner of an invisible quad. We then move left until we get to the top left corner. From there we go to the bottom left corner. The code below will render the following image:
Notice that half the buttefly is rendered on the first triangle. The other half is rendered on the second triangle. The texture coordinates match up with the vertex coordinates and although there are only 3 texture coordinates, it's still enough information to tell OpenGL what portion of the image needs to be mapped to the triangle. glBegin(GL_TRIANGLES); // Begin Drawing Triangles
The second point of the first triangle and the third point of the second triangle move back and forth on the z-axis to create the illusion of flapping. What's really happening is that point is moving from -1.0f to 1.0f and then back, which causes the two triangles to bend in the center where the butterflies body is. If you look at the two pictures you will notice that points 2 and 3 are the tips of the wings. Creates a very nice flapping effect with minimal effort. // Second Triangle glEnd(); // Done Drawing Triangles obj[loop].y-=obj[loop].yi; // Move Object Down The Screen if (obj[loop].y<-18.0f) // Is Object Off The Screen? So if the wings were going up, and they hit 1.0f, fi will become a negative value which will make the wings go down. Sleep(15) has been added to slow the program down by 15 milliseconds. It ran insanely fast on a friends machine, and I was too lazy to modify the code to take advantage of the timer :) if ((obj[loop].flap>1.0f) || (obj[loop].flap<-1.0f)) // Time To Change Flap Direction? Sleep(15); // Create A Short Delay (15 Milliseconds) glFlush (); // Flush The GL Rendering Pipeline Jeff Molofee (NeHe) |
-- 作者:yqdrrjhan -- 发布时间:10/26/2007 10:16:00 AM -- lz好强,瞻仰中~~~~ |
-- 作者:yqdrrjhan -- 发布时间:10/26/2007 10:19:00 AM -- lz能发些关于dx的教程吗,十分感谢~~~~ |
-- 作者:长风万里 -- 发布时间:10/28/2007 5:14:00 AM -- 谢谢你的教程~~~不知道还有会下面的lesson吗? |
W 3 C h i n a ( since 2003 ) 旗 下 站 点 苏ICP备05006046号《全国人大常委会关于维护互联网安全的决定》《计算机信息网络国际联网安全保护管理办法》 |
343.750ms |