以文本方式查看主题 - 计算机科学论坛 (http://bbs.xml.org.cn/index.asp) -- 『 C/C++编程思想 』 (http://bbs.xml.org.cn/list.asp?boardid=61) ---- [推荐]NeHe OpenGL教程(中英文版附带VC++源码)Lesson 07-lesson 08 (http://bbs.xml.org.cn/dispbbs.asp?boardid=61&rootid=&id=53709) |
-- 作者:一分之千 -- 发布时间:10/13/2007 10:06:00 AM -- [推荐]NeHe OpenGL教程(中英文版附带VC++源码)Lesson 07-lesson 08 第七课 中文
在这一课里,我们将添加光照和键盘控制,它让程序看起来更美观。 BOOL light; // 光源的开/关 GLfloat xrot; // X 旋转 GLfloat z=-5.0f; // 深入屏幕的距离 GLfloat LightAmbient[]= { 0.5f, 0.5f, 0.5f, 1.0f }; // 环境光参数 GLfloat LightDiffuse[]= { 1.0f, 1.0f, 1.0f, 1.0f }; // 漫射光参数 GLfloat LightPosition[]= { 0.0f, 0.0f, 2.0f, 1.0f }; // 光源位置 GLuint filter; // 滤波类型 int LoadGLTextures() // 载入位图并转换成纹理 AUX_RGBImageRec *TextureImage[1]; // 创建纹理的存储空间 memset(TextureImage,0,sizeof(void *)*1); // 将指针设为 NULL // 载入位图,检查有错,或位图不存在的话退出 glGenTextures(3, &texture[0]); // 创建纹理 // 创建 Nearest 滤波贴图 // 创建线性滤波纹理 // 创建 MipMapped 纹理 gluBuild2DMipmaps(GL_TEXTURE_2D, 3, TextureImage[0]->sizeX, TextureImage[0]->sizeY, GL_RGB, GL_UNSIGNED_BYTE, TextureImage[0]->data); if (TextureImage[0]) // 纹理是否存在 free(TextureImage[0]); // 释放图像结构 return Status; // 返回 Status 变量 glLightfv(GL_LIGHT1, GL_AMBIENT, LightAmbient); // 设置环境光 glLightfv(GL_LIGHT1, GL_DIFFUSE, LightDiffuse); // 设置漫射光 glLightfv(GL_LIGHT1, GL_POSITION,LightPosition); // 设置光源位置 glEnable(GL_LIGHT1); // 启用一号光源 int DrawGLScene(GLvoid) // 从这里开始进行所有的绘制 glTranslatef(0.0f,0.0f,z); // 移入/移出屏幕 z 个单位 glRotatef(xrot,1.0f,0.0f,0.0f); // 绕X轴旋转 glBindTexture(GL_TEXTURE_2D, texture[filter]); // 选择由filter决定的纹理 glBegin(GL_QUADS); // 开始绘制四边形 看着木箱的前面您会注意到法线与Z轴正向同向。这意味着法线正指向观察者-您自己。这正是我们所希望的。对于木箱的背面,也正如我们所要的,法线背对着观察者。如果立方体沿着X或Y轴转个180度的话,前侧面的法线仍然朝着观察者,背面的法线也还是背对着观察者。换句话说,不管是哪个面,只要它朝着观察者这个面的法线就指向观察者。由于光源紧邻观察者,任何时候法线对着观察者时,这个面就会被照亮。并且法线越朝着光源,就显得越亮一些。如果您把观察点放到立方体内部,你就会法线里面一片漆黑。因为法线是向外指的。如果立方体内部没有光源的话,当然是一片漆黑。 // 前侧面 xrot+=xspeed; // xrot 增加 xspeed 单位 SwapBuffers(hDC); // 交换缓存 lp=TRUE; // lp 设为 TRUE if (!light) // 如果没有光源 if (!keys['L']) // L键松开了么? if (keys['F'] && !fp) // F键按下了么? if (keys[VK_PRIOR]) // PageUp按下了? if (keys[VK_NEXT]) // PageDown按下了么 if (keys[VK_UP]) // Up方向键按下了么? if (keys[VK_F1]) // F1按下了么? // 关闭 |
-- 作者:一分之千 -- 发布时间:10/13/2007 10:08:00 AM -- Lesson 07 In this tutorial I'll teach you how to use three different texture filters. I'll teach you how to move an object using keys on the keyboard, and I'll also teach you how to apply simple lighting to your OpenGL scene. Lots covered in this tutorial, so if the previous tutorials are giving you problems, go back and review. It's important to have a good understanding of the basics before you jump into the following code. We're going to be modifying the code from lesson one again. As usual, if there are any major changes, I will write out the entire section of code that has been modified. We'll start off by adding a few new variables to the program. #include <windows.h> // Header File For Windows HDC hDC=NULL; // Private GDI Device Context bool keys[256]; // Array Used For The Keyboard Routine BOOL light; // Lighting ON / OFF GLfloat xrot; // X Rotation GLfloat z=-5.0f; // Depth Into The Screen Light is created the same way color is created. If the first number is 1.0f, and the next two are 0.0f, we will end up with a bright red light. If the third number is 1.0f, and the first two are 0.0f, we will have a bright blue light. The last number is an alpha value. We'll leave it at 1.0f for now. So in the line below, we are storing the values for a white ambient light at half intensity (0.5f). Because all the numbers are 0.5f, we will end up with a light that's halfway between off (black) and full brightness (white). Red, blue and green mixed at the same value will create a shade from black(0.0f) to white(1.0f). Without an ambient light, spots where there is no diffuse light will appear very dark. GLfloat LightAmbient[]= { 0.5f, 0.5f, 0.5f, 1.0f }; // Ambient Light Values ( NEW ) GLfloat LightDiffuse[]= { 1.0f, 1.0f, 1.0f, 1.0f }; // Diffuse Light Values ( NEW ) There's no real easy way to explain the third parameter. You should know that -2.0f is going to be closer to you than -5.0f. and -100.0f would be WAY into the screen. Once you get to 0.0f, the image is so big, it fills the entire monitor. Once you start going into positive values, the image no longer appears on the screen cause it has "gone past the screen". That's what I mean when I say out of the screen. The object is still there, you just can't see it anymore. Leave the last number at 1.0f. This tells OpenGL the designated coordinates are the position of the light source. More about this in a later tutorial. GLfloat LightPosition[]= { 0.0f, 0.0f, 2.0f, 1.0f }; // Light Position ( NEW ) GLuint texture[3] creates storage space for the three different textures. The textures will be stored at texture[0], texture[1] and texture[2]. GLuint filter; // Which Filter To Use LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); // Declaration For WndProc Immediately after the above code, and before ReSizeGLScene(), we want to add the following section of code. This is the same code we used in lesson 6 to load in a bitmap file. Nothing has changed. If you're not sure what any of the following lines do, read tutorial six. It explains the code below in detail. 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(3, &texture[0]); // Create Three Textures You'll notice we're using GL_NEAREST for both the MIN and MAG. You can mix GL_NEAREST with GL_LINEAR, and the texture will look a bit better, but we're intested in speed, so we'll use low quality for both. The MIN_FILTER is the filter used when an image is drawn smaller than the original texture size. The MAG_FILTER is used when the image is bigger than the original texture size. // Create Nearest Filtered Texture // Create Linear Filtered Texture I had said in tutorial six there was a way around the 64,128,256,etc limit that OpenGL puts on texture width and height. gluBuild2DMipmaps is it. From what I've found, you can use any bitmap image you want (any width and height) when building mipmapped textures. OpenGL will automatically size it to the proper width and height. Because this is texture number three, we're going to store this texture in texture[2]. So now we have texture[0] which has no filtering, texture[1] which uses linear filtering, and texture[2] which uses mipmapped textures. We're done building the textures for this tutorial. // Create MipMapped Texture gluBuild2DMipmaps(GL_TEXTURE_2D, 3, TextureImage[0]->sizeX, TextureImage[0]->sizeY, GL_RGB, GL_UNSIGNED_BYTE, TextureImage[0]->data); ( NEW ) 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 glLightfv(GL_LIGHT1, GL_AMBIENT, LightAmbient); // Setup The Ambient Light glLightfv(GL_LIGHT1, GL_DIFFUSE, LightDiffuse); // Setup The Diffuse Light glLightfv(GL_LIGHT1, GL_POSITION,LightPosition); // Position The Light glEnable(GL_LIGHT1); // Enable Light One int DrawGLScene(GLvoid) // Here's Where We Do All The Drawing glTranslatef(0.0f,0.0f,z); // Translate Into/Out Of The Screen By z glRotatef(xrot,1.0f,0.0f,0.0f); // Rotate On The X Axis By xrot glBindTexture(GL_TEXTURE_2D, texture[filter]); // Select A Texture Based On filter glBegin(GL_QUADS); // Start Drawing Quads Looking at the front face you'll notice that the normal is positive on the z axis. This means the normal is pointing at the viewer. Exactly the direction we want it pointing. On the back face, the normal is pointing away from the viewer, into the screen. Again exactly what we want. If the cube is spun 180 degrees on either the x or y axis, the front will be facing into the screen and the back will be facing towards the viewer. No matter what face is facing the viewer, the normal of that face will also be pointing towards the viewer. Because the light is close to the viewer, any time the normal is pointing towards the viewer it's also pointing towards the light. When it does, the face will light up. The more a normal points towards the light, the brighter that face is. If you move into the center of the cube you'll notice it's dark. The normals are point out, not in, so there's no light inside the box, exactly as it should be. // Front Face xrot+=xspeed; // Add xspeed To xrot This code checks to see if the letter 'L' has been pressed on the keyboard. The first line checks to see if 'L' is being pressed. If 'L' is being pressed, but lp isn't false, meaning 'L' has already been pressed once or it's being held down, nothing will happen. SwapBuffers(hDC); // Swap Buffers (Double Buffering) Once lp has been set to true, telling the computer that 'L' is being held down, we toggle lighting off and on. The variable light can only be true of false. So if we say light=!light, what we are actually saying is light equals NOT light. Which in english translates to if light equals true make light not true (false), and if light equals false, make light not false (true). So if light was true, it becomes false, and if light was false it becomes true. lp=TRUE; // lp Becomes TRUE if (!light) // If Not Light if (!keys['L']) // Has L Key Been Released? if (keys['F'] && !fp) // Is F Key Being Pressed? if (keys[VK_PRIOR]) // Is Page Up Being Pressed? if (keys[VK_NEXT]) // Is Page Down Being Pressed? if (keys[VK_UP]) // Is Up Arrow Being Pressed? if (keys[VK_F1]) // Is F1 Being Pressed? // Shutdown Jeff Molofee (NeHe) |
-- 作者:一分之千 -- 发布时间:10/13/2007 10:11:00 AM -- 第八课 在这一课里,我们在纹理的基础上加上了混合,它看起具有透明的效果,当然解释它不是那么容易,当希望你喜欢它。 OpenGL中的混色 bool blend; // 是否混合? if (TextureImage[0]=LoadBMP("Data/glass.bmp")) // 载入玻璃位图 glColor4f(1.0f,1.0f,1.0f,0.5f); // 全亮度, 50% Alpha 混合 if (keys[VK_LEFT]) // Left方向键按下了么? if (keys['B'] && !bp) // B 健按下且bp为 FALSE么? 原文注 (11/13/99) 纹理贴图的Alpha混合 |
-- 作者:一分之千 -- 发布时间:10/13/2007 10:12:00 AM -- Lesson 08 Simple Transparency Most special effects in OpenGL rely on some type of blending. Blending is used to combine the color of a given pixel that is about to be drawn with the pixel that is already on the screen. How the colors are combined is based on the alpha value of the colors, and/or the blending function that is being used. Alpha is a 4th color component usually specified at the end. In the past you have used GL_RGB to specify color with 3 components. GL_RGBA can be used to specify alpha as well. In addition, we can use glColor4f() instead of glColor3f(). Most people think of Alpha as how opaque a material is. An alpha value of 0.0 would mean that the material is completely transparent. A value of 1.0 would be totally opaque. The Blending Equation If you are uncomfortable with math, and just want to see how to do transparency, skip this section. If you want to understand how blending works, this section is for you. (Rs Sr + Rd Dr, Gs Sg + Gd Dg, Bs Sb + Bd Db, As Sa + Ad Da) OpenGL will calculate the result of blending two pixels based on the above equation. The s and r subscripts specify the source and destination pixels. The S and D components are the blend factors. These values indicate how you would like to blend the pixels. The most common values for S and D are (As, As, As, As) (AKA source alpha) for S and (1, 1, 1, 1) - (As, As, As, As) (AKA one minus src alpha) for D. This will yield a blending equation that looks like this: (Rs As + Rd (1 - As), Gs As + Gd (1 - As), Bs As + Bs (1 - As), As As + Ad (1 - As)) This equation will yield transparent/translucent style effects. Blending in OpenGL We enable blending just like everything else. Then we set the equation, and turn off depth buffer writing when drawing transparent objects, since we still want objects behind the translucent shapes to be drawn. This isn't the proper way to blend, but most the time in simple projects it will work fine. Rui Martins Adds: The correct way is to draw all the transparent (with alpha < 1.0) polys after you have drawn the entire scene, and to draw them in reverse depth order (farthest first). This is due to the fact that blending two polygons (1 and 2) in different order gives different results, i.e. (assuming poly 1 is nearest to the viewer, the correct way would be to draw poly 2 first and then poly 1. If you look at it, like in reality, all the light comming from behind these two polys (which are transparent) has to pass poly 2 first and then poly 1 before it reaches the eye of the viewer. You should SORT THE TRANSPARENT POLYGONS BY DEPTH and draw them AFTER THE ENTIRE SCENE HAS BEEN DRAWN, with the DEPTH BUFFER ENABLED, or you will get incorrect results. I know this sometimes is a pain, but this is the correct way to do it. We'll be using the code from the last tutorial. We start off by adding two new variables to the top of the code. I'll rewrite the entire section of code for clarity. #include <windows.h> // Header File For Windows HDC hDC=NULL; // Private GDI Device Context bool keys[256]; // Array Used For The Keyboard Routine GLfloat xrot; // X Rotation GLfloat z=-5.0f; // Depth Into The Screen GLfloat LightAmbient[]= { 0.5f, 0.5f, 0.5f, 1.0f }; // Ambient Light Values GLuint filter; // Which Filter To Use LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); // Declaration For WndProc if (TextureImage[0]=LoadBMP("Data/glass.bmp")) // Load The Glass Bitmap ( MODIFIED ) Rui Martins Adds: An alpha value of 0.0 would mean that the material is completely transparent. A value of 1.0 would be totally opaque. glColor4f(1.0f,1.0f,1.0f,0.5f); // Full Brightness, 50% Alpha ( NEW ) if (keys[VK_LEFT]) // Is Left Arrow Being Pressed? if (keys['B'] && !bp) // Is B Key Pressed And bp FALSE? Thats it! Blending is actually quite simple to do in OpenGL. Note (11/13/99) I ( NeHe ) have modified the blending code so the output of the object looks more like it should. Using Alpha values for the source and destination to do the blending will cause artifacting. Causing back faces to appear darker, along with side faces. Basically the object will look very screwy. The way I do blending may not be the best way, but it works, and the object appears to look like it should when lighting is enabled. Thanks to Tom for the initial code, the way he was blending was the proper way to blend with alpha values, but didn't look as attractive as people expected :) The code was modified once again to address problems that some video cards had with glDepthMask(). It seems this command would not effectively enable and disable depth buffer testing on some cards, so I've changed back to the old fashioned glEnable and Disable of Depth Testing. Alpha From Texture Map. The alpha value that is used for transparency can be read from a texture map just like color, to do this, you will need to get alpha into the image you want to load, and then use GL_RGBA for the color format in calls to glTexImage2D(). Questions? If you have any questions, feel free to contact me at stanis@cs.wisc.edu. Tom Stanis Jeff Molofee (NeHe) |
-- 作者:walthouse -- 发布时间:2/22/2008 9:35:00 AM -- 学习了,谢谢楼主. |
-- 作者:freewind -- 发布时间:7/12/2010 12:02:00 PM -- 好像最后一段翻译有个小问题吧 缺省应该是1.0f即不透明 还是0.0f?(alpha is assumed to be 1.0 if not specified). (alpha参数在没有指定时,缺省为零)。
|
W 3 C h i n a ( since 2003 ) 旗 下 站 点 苏ICP备05006046号《全国人大常委会关于维护互联网安全的决定》《计算机信息网络国际联网安全保护管理办法》 |
187.500ms |