以文本方式查看主题 - 计算机科学论坛 (http://bbs.xml.org.cn/index.asp) -- 『 C/C++编程思想 』 (http://bbs.xml.org.cn/list.asp?boardid=61) ---- [推荐]NeHe OpenGL教程(中英文版附带VC++源码)Lesson 45-lesson 46 (http://bbs.xml.org.cn/dispbbs.asp?boardid=61&rootid=&id=54729) |
-- 作者:一分之千 -- 发布时间:11/1/2007 11:42:00 AM -- [推荐]NeHe OpenGL教程(中英文版附带VC++源码)Lesson 45-lesson 46
你想更快地绘制么?直接操作显卡吧,这可是当前的图形技术,不要犹豫,我带你入门。接下来,你自己向前走吧。 #define MESH_RESOLUTION 4.0f // 每个顶点使用的像素#define MESH_HEIGHTSCALE 1.0f // 高度的缩放比例//#define NO_VBOS // 如果定义将不使用VBO扩展 class CVert // 顶点类 class CTexCoord // 纹理坐标类 //网格类 unsigned int m_nVBOVertices; // 顶点缓存对象的名称 AUX_RGBImageRec* m_pTextureImage; // 高度数据 public: // 载入高度图 下面我们来定义一些全局变量: bool g_fVBOSupported = false; // 是否支持顶点缓存对象 //加载高度图 FILE* fTest = fopen( szPath, "r" ); // 加载图像文件 // 读取顶点数据 m_pVertices[nIndex].x = flX - ( m_pTextureImage->sizeX / 2 ); m_pTexCoords[nIndex].u = flX / m_pTextureImage->sizeX; nIndex++; // 载入纹理,它和高度图是同一副图像 // 释放纹理数据 //计算(x,y)处的亮度 void CMesh :: BuildVBOs(){ glGenBuffersARB( 1, &m_nVBOVertices ); // 创建一个顶点缓存,并把顶点数据绑定到缓存 glBindBufferARB( GL_ARRAY_BUFFER_ARB, m_nVBOVertices ); glBufferDataARB( GL_ARRAY_BUFFER_ARB, m_nVertexCount*3*sizeof(float), m_pVertices, GL_STATIC_DRAW_ARB ); // 删除分配的内存 } //初始化 // 载入纹理数据 // 检测是否支持VBO扩展 return TRUE; // 返回是否支持指定的扩展 pszWhere = (unsigned char *) strchr( szTargetExtension, ' ' ); // 返回扩展字符串 // 在扩展字符串中搜索 void Draw (void){ glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glLoadIdentity (); char szTitle[256]={0}; // 设置视口 // 使用顶点,纹理坐标数组 // 如果支持VBO扩展 if( g_fVBOSupported ) { glBindBufferARB( GL_ARRAY_BUFFER_ARB, g_pMesh->m_nVBOVertices ); glVertexPointer( 3, GL_FLOAT, 0, (char *) NULL ); // 设置顶点数组的指针为顶点缓存 glBindBufferARB( GL_ARRAY_BUFFER_ARB, g_pMesh->m_nVBOTexCoords ); glTexCoordPointer( 2, GL_FLOAT, 0, (char *) NULL ); // 设置顶点数组的指针为纹理坐标缓存 } // 不支持VBO扩展 else { glVertexPointer( 3, GL_FLOAT, 0, g_pMesh->m_pVertices ); glTexCoordPointer( 2, GL_FLOAT, 0, g_pMesh->m_pTexCoords ); } // 渲染 glDrawArrays( GL_TRIANGLES, 0, g_pMesh->m_nVertexCount ); glDisableClientState( GL_VERTEX_ARRAY ); glDisableClientState( GL_TEXTURE_COORD_ARRAY ); } 好了,那就是这次的课程,如果你发现任何问题,请联系我. |
-- 作者:一分之千 -- 发布时间:11/1/2007 11:43:00 AM -- Lesson: 45 One of the largest goals of any 3d application is speed. You should always limit the amount of polygons actually rendered, whether by sorting, culling, or level-of-detail algorithms. However, when all else fails and you simply need raw polygon-pushing power, you can always utilize the optimizations provided by OpenGL. Vertex Arrays are one good way to do that, plus a recent extension to graphics cards named Vertex Buffer Objects adds the FPS boost everybody dreams of. The extension, ARB_vertex_buffer_object, works just like vertex arrays, except that it loads the data into the graphics card's high-performance memory, significantly lowering rendering time. Of course, the extension being relatively new, not all cards will support it, so we will have to write in some technology scaling. In this tutorial, we will Load data from a heightmap Use Vertex Arrays to send mesh data to OpenGL more efficiently Load data into high-performance memory via the VBO extension So let's get started! First we are going to define a few application parameters. #define MESH_RESOLUTION 4.0f // Pixels Per Vertex#define MESH_HEIGHTSCALE 1.0f // Mesh Height Scale//#define NO_VBOS // If Defined, VBOs Will Be Forced Off // VBO Extension Definitions, From glext.h#define GL_ARRAY_BUFFER_ARB 0x8892#define GL_STATIC_DRAW_ARB 0x88E4typedef void (APIENTRY * PFNGLBINDBUFFERARBPROC) (GLenum target, GLuint buffer);typedef void (APIENTRY * PFNGLDELETEBUFFERSARBPROC) (GLsizei n, const GLuint *buffers);typedef void (APIENTRY * PFNGLGENBUFFERSARBPROC) (GLsizei n, GLuint *buffers);typedef void (APIENTRY * PFNGLBUFFERDATAARBPROC) (GLenum target, int size, const GLvoid *data, GLenum usage); class CVert // Vertex Class{public: float x; // X Component float y; // Y Component float z; // Z Component};typedef CVert CVec; // The Definitions Are Synonymous class CMesh // Vertex Buffer Object Names // Temporary Data public: // Heightmap Loader bool g_fVBOSupported = false; // ARB_vertex_buffer_object supported?CMesh* g_pMesh = NULL; // Mesh Datafloat g_flYRot = 0.0f; // Rotationint g_nFPS = 0, g_nFrames = 0; // FPS and FPS CounterDWORD g_dwLastFPS = 0; // Last FPS Check Time bool CMesh :: LoadHeightmap( char* szPath, float flHeightScale, float flResolution ){ // Error-Checking FILE* fTest = fopen( szPath, "r" ); // Open The Image if( !fTest ) // Make Sure It Was Found return false; // If Not, The File Is Missing fclose( fTest ); // Done With The Handle // Generate Vertex Field m_nVertexCount = (int) ( m_pTextureImage->sizeX * m_pTextureImage->sizeY * 6 / ( flResolution * flResolution ) ); m_pVertices = new CVec[m_nVertexCount]; // Allocate Vertex Data m_pTexCoords = new CTexCoord[m_nVertexCount]; // Allocate Tex Coord Data int nX, nZ, nTri, nIndex=0; // Create Variables float flX, flZ; for( nZ = 0; nZ < m_pTextureImage->sizeY; nZ += (int) flResolution ) { for( nX = 0; nX < m_pTextureImage->sizeX; nX += (int) flResolution ) { for( nTri = 0; nTri < 6; nTri++ ) { // Using This Quick Hack, Figure The X,Z Position Of The Point flX = (float) nX + ( ( nTri == 1 || nTri == 2 || nTri == 5 ) ? flResolution : 0.0f ); flZ = (float) nZ + ( ( nTri == 2 || nTri == 4 || nTri == 5 ) ? flResolution : 0.0f ); // Stretch The Texture Across The Entire Mesh // Increment Our Index // Load The Texture Into OpenGL glGenTextures( 1, &m_nTextureId ); // Get An Open ID glBindTexture( GL_TEXTURE_2D, m_nTextureId ); // Bind The Texture glTexImage2D( GL_TEXTURE_2D, 0, 3, m_pTextureImage->sizeX, m_pTextureImage->sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, m_pTextureImage->data ); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); float CMesh :: PtHeight( int nX, int nY ){ // Calculate The Position In The Texture, Careful Not To Overflow int nPos = ( ( nX % m_pTextureImage->sizeX ) + ( ( nY % m_pTextureImage->sizeY ) * m_pTextureImage->sizeX ) ) * 3; float flR = (float) m_pTextureImage->data[ nPos ]; // Get The Red Component float flG = (float) m_pTextureImage->data[ nPos + 1 ]; // Get The Green Component float flB = (float) m_pTextureImage->data[ nPos + 2 ]; // Get The Blue Component return ( 0.299f * flR + 0.587f * flG + 0.114f * flB ); // Calculate The Height Using The Luminance Algorithm} void CMesh :: BuildVBOs(){ // Generate And Bind The Vertex Buffer glGenBuffersARB( 1, &m_nVBOVertices ); // Get A Valid Name glBindBufferARB( GL_ARRAY_BUFFER_ARB, m_nVBOVertices ); // Bind The Buffer // Load The Data glBufferDataARB( GL_ARRAY_BUFFER_ARB, m_nVertexCount*3*sizeof(float), m_pVertices, GL_STATIC_DRAW_ARB ); // Our Copy Of The Data Is No Longer Necessary, It Is Safe In The Graphics Card // Load The Mesh Data g_pMesh = new CMesh(); // Instantiate Our Mesh if( !g_pMesh->LoadHeightmap( "terrain.bmp", // Load Our Heightmap MESH_HEIGHTSCALE, MESH_RESOLUTION ) ) { MessageBox( NULL, "Error Loading Heightmap", "Error", MB_OK ); return false; } bool IsExtensionSupported( char* szTargetExtension ){ const unsigned char *pszExtensions = NULL; const unsigned char *pszStart; unsigned char *pszWhere, *pszTerminator; // Get Extensions String // Search The Extensions String For An Exact Copy void Draw (void){ glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear Screen And Depth Buffer glLoadIdentity (); // Reset The Modelview Matrix char szTitle[256]={0}; // Build The Title String // Move The Camera To set a pointer for a certain data type, you have to use the appropriate function - glVertexPointer and glTexCoordPointer, in our case. The usage is pretty easy - pass the amount of variables in a point (three for a vertex, two for a texcoord), the data cast (float), the stride between the desired data (in the event that the vertices are not stored alone in their structure), and the pointer to the data. You can actually use glInterleavedArrays and store all of your data in one big memory buffer, but I chose to keep it seperate to show you how to use multiple VBOs. Speaking of VBOs, implementing them isn't much different. The only real change is that instead of providing a pointer to the data, we bind the VBO we want and set the pointer to zero. Take a look. // Set Pointers To Our Data if( g_fVBOSupported ) { glBindBufferARB( GL_ARRAY_BUFFER_ARB, g_pMesh->m_nVBOVertices ); glVertexPointer( 3, GL_FLOAT, 0, (char *) NULL ); // Set The Vertex Pointer To The Vertex Buffer glBindBufferARB( GL_ARRAY_BUFFER_ARB, g_pMesh->m_nVBOTexCoords ); glTexCoordPointer( 2, GL_FLOAT, 0, (char *) NULL ); // Set The TexCoord Pointer To The TexCoord Buffer } else { glVertexPointer( 3, GL_FLOAT, 0, g_pMesh->m_pVertices ); // Set The Vertex Pointer To Our Vertex Data glTexCoordPointer( 2, GL_FLOAT, 0, g_pMesh->m_pTexCoords ); // Set The Vertex Pointer To Our TexCoord Data } // Render glDrawArrays( GL_TRIANGLES, 0, g_pMesh->m_nVertexCount ); // Draw All Of The Triangles At Once Now all we have left is to disable vertex arrays, and we are finished. // Disable Pointers glDisableClientState( GL_VERTEX_ARRAY ); // Disable Vertex Arrays glDisableClientState( GL_TEXTURE_COORD_ARRAY ); // Disable Texture Coord Arrays} |
-- 作者:一分之千 -- 发布时间:11/1/2007 11:44:00 AM -- 第四十六课 当今显卡的强大功能,你几乎什么都不用做,只需要在创建窗口的时候该一个数据。看看吧,驱动程序为你做完了一切。 Vid_mem = sizeof(Front_buffer) + sizeof(Back_buffer) + num_samples * (sizeof(Front_buffer) +sizeof(ZS_buffer)) 下面我们来介绍如何使用多重采样,不向其他的扩展,我们在使用多重采样时,必须在窗口创建时告诉它使用多重采样,典型的步骤如下: 了解了上面,我们从头说明如何使用多重采样,并介绍ARB_Multisample的实现方法: #include <windows.h>#include <gl.h>#include <glu.h>#include "arb_multisample.h" // 声明我们将要使用#define WGL_SAMPLE_BUFFERS_ARB 0x2041#define WGL_SAMPLES_ARB 0x2042 // 判断是否支持这个扩展bool WGLisExtensionSupported(const char *extension){ const size_t extlen = strlen(extension); const char *supported = NULL; if (wglGetExtString) //在OpenGL的扩展中查找是否支持特定的扩展 // 如果都不支持,则返回失败 // 查找是否包含需要的扩展名 if (p == NULL) if ((p==supported || p[-1]==' ') && (p[extlen]=='\0' || p[extlen]==' '))
// 初始化多重渲染bool InitMultisample(HINSTANCE hInstance,HWND hWnd,PIXELFORMATDESCRIPTOR pfd){ // 检测是否支持多重渲染 if (!WGLisExtensionSupported("WGL_ARB_multisample")) { arbMultisampleSupported=false; return false; } HDC hDC = GetDC(hWnd); int pixelFormat; //下面的代码设置多重采样的像素格式 // 首先我们测试是否支持4个采样点的多重采样 // 接着我们测试是否支持2个采样点的多重采样 // 返回支持多重采样
#include <windows.h> #include <gl/gl.h> #include <gl/glu.h> #include "NeHeGL.h" //如果不启用多重采样 if(!arbMultisampleSupported) { PixelFormat = ChoosePixelFormat (window->hDC, &pfd); // 选择一种相容的像素格式 if (PixelFormat == 0) // 是否获得相容的像素格式 { ReleaseDC (window->hWnd, window->hDC); // 释放设备描述表 window->hDC = 0; // 设置窗口设备描述表为0 DestroyWindow (window->hWnd); // 删除窗口 window->hWnd = 0; // 设置窗口句柄为0 return FALSE; // 返回错误 } //检测是否支持多重采样 if(!arbMultisampleSupported && CHECK_FOR_MULTISAMPLE) { //如果是,初始化多重采样 if(InitMultisample(window->init.application->hInstance,window->hWnd,pfd)) { //消耗当前窗口 DestroyWindowGL (window); //创建一个支持多重采样的窗口 return CreateWindowGL(window); } } glEnable(GL_MULTISAMPLE_ARB); glDisable(GL_MULTISAMPLE_ARB); |
-- 作者:一分之千 -- 发布时间:11/1/2007 11:45:00 AM -- Lesson: 46 Howdy all, the Friendly Neighborhood Roach here with an interesting tutorial that will help you get your apps top notch. In the realm of getting your OpenGL programs to look better, a big problem we all run into is aliasing. That is, the square edged "jaggies" that exist on diagonal lines in relation to the square pixels that exist on your screen. Ie, Bad Mojo. The answer, termed Anti-Aliasing, is used to smudge those "jaggies" in order to create a smoother edge for objects. One process used to achieve anti-aliasing is called "Multisampling." The idea is that for each pixel, we sample the pixels around it to determine if this edge needs to be anti-aliased, basically, we discard the jaggies by "smudging" the pixel itself. Fullscreen AntiAliasing is something that non-realtime rendering programs have always had an advantage in. However, with current hardware, we're able to pull off the same effect real time. The ARB_MULTISAMPLE extension allows us to do this. Essentially, each pixel is sampled by it's neighbors to find out the optimal antialias to perform. This comes at a cost however, and can slow down performance. Vid_mem = sizeof(Front_buffer) + sizeof(Back_buffer) + num_samples * (sizeof(Front_buffer) +sizeof(ZS_buffer)) With that being said, a brief overview of how our process is going to work. Unlike other extensions, which relate to OpenGL rendering, the ARB_MULTISAMPLE extension must be dealt with during the creation of your rendering window. Our process shall go as follows: #include <windows.h>#include <gl/gl.h>#include <gl/glu.h>#include "arb_multisample.h" // Declarations We'll Use#define WGL_SAMPLE_BUFFERS_ARB 0x2041#define WGL_SAMPLES_ARB 0x2042 bool WGLisExtensionSupported(const char *extension){ const size_t extlen = strlen(extension); const char *supported = NULL; if (wglGetExtString) // If That Failed, Try Standard Opengl Extensions String // If That Failed Too, Must Be No Extensions Supported // Begin Examination At Start Of String, Increment By 1 On False Match if (p == NULL) // Make Sure That Match Is At The Start Of The String Or That // Also, Make Sure That The Following Character Is Space Or NULL bool InitMultisample(HINSTANCE hInstance,HWND hWnd,PIXELFORMATDESCRIPTOR pfd){ // See If The String Exists In WGL! if (!WGLisExtensionSupported("WGL_ARB_multisample")) { arbMultisampleSupported=false; return false; } if (!wglChoosePixelFormatARB) // Get Our Current Device Context. We Need This In Order To Ask The OpenGL Window What Attributes We Have int pixelFormat; // These Attributes Are The Bits We Want To Test For In Our Sample // First We Check To See If We Can Get A Pixel Format For 4 Samples // if We Returned True, And Our Format Count Is Greater Than 1 // Our Pixel Format With 4 Samples Failed, Test For 2 Samples // Return The Valid Format #include <windows.h> // Header File For The Windows Library#include <gl/gl.h> // Header File For The OpenGL32 Library#include <gl/glu.h> // Header File For The GLu32 Library#include "NeHeGL.h" // Header File For The NeHeGL Basecode BOOL DestroyWindowGL (GL_Window* window); window->hDC = GetDC (window->hWnd); // Grab A Device Context For This Window if (window->hDC == 0) // Did We Get A Device Context? { // Failed DestroyWindow (window->hWnd); // Destroy The Window window->hWnd = 0; // Zero The Window Handle return FALSE; // Return False } if (SetPixelFormat (window->hDC, PixelFormat, &pfd) == FALSE) // Try To Set The Pixel Format // Make The Rendering Context Our Current Rendering Context if (wglMakeCurrent (window->hDC, window->hRC) == FALSE) { // Failed wglDeleteContext (window->hRC); // Delete The Rendering Context window->hRC = 0; // Zero The Rendering Context ReleaseDC (window->hWnd, window->hDC); // Release Our Device Context window->hDC = 0; // Zero The Device Context DestroyWindow (window->hWnd); // Destroy The Window window->hWnd = 0; // Zero The Window Handle return FALSE; // Return False } // ROACH ShowWindow (window->hWnd, SW_NORMAL); // Make The Window Visible glEnable(GL_MULTISAMPLE_ARB); glDisable(GL_MULTISAMPLE_ARB); |
-- 作者:yugg_03 -- 发布时间:7/29/2008 4:36:00 PM -- thank you |
W 3 C h i n a ( since 2003 ) 旗 下 站 点 苏ICP备05006046号《全国人大常委会关于维护互联网安全的决定》《计算机信息网络国际联网安全保护管理办法》 |
281.250ms |