代码: |
#define MESH_RESOLUTION 4.0f // 每个顶点对应几个像素 #define MESH_HEIGHTSCALE 1.0f // Mesh Height Scale //#define NO_VBOS // 如果定义了,强制的不使用VBO |
代码: |
//VBO扩展的定义,从 glext.h摘抄
#define GL_ARRAY_BUFFER_ARB 0x8892 #define GL_STATIC_DRAW_ARB 0x88E4 typedef 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); // VBO 扩展的函数指针
PFNGLGENBUFFERSARBPROC glGenBuffersARB = NULL; // VBO 名字生成函数 PFNGLBINDBUFFERARBPROC glBindBufferARB = NULL; // VBO 绑定函数 PFNGLBUFFERDATAARBPROC glBufferDataARB = NULL; // VBO 数据加载函数 PFNGLDELETEBUFFERSARBPROC glDeleteBuffersARB = NULL; // VBO 删除函数 |
代码: |
class CVert // 顶点类
{ public: float x; // X Component float y; // Y Component float z; // Z Component }; typedef CVert CVec; // 定义CVec 和CVert是一样的。
class CTexCoord // 纹理坐标类 { public: float u; // U Component float v; // V Component }; class CMesh { public: // 网格数据 int m_nVertexCount; // 顶点数目 CVert* m_pVertices; // 顶点数据 CTexCoord* m_pTexCoords; // 纹理坐标 unsigned int m_nTextureId; // 纹理标ID // VBO 的名字 unsigned int m_nVBOVertices; // 顶点 VBO 的名字 unsigned int m_nVBOTexCoords; // 纹理坐标 VBO 的名字 // 临时数据
AUX_RGBImageRec* m_pTextureImage; //高度图的数据 public: CMesh(); // Mesh Constructor ~CMesh(); // Mesh Deconstructor //高度图加载函数 bool LoadHeightmap( char* szPath, float flHeightScale, float flResolution ); // 得到一个点的高度 float PtHeight( int nX, int nY ); // 绑定VBO对象。 void BuildVBOs(); }; |
代码: |
bool g_fVBOSupported = false; // ARB_vertex_buffer_object是否被支持? CMesh* g_pMesh = NULL; //网格数据 float g_flYRot = 0.0f; //旋转 int g_nFPS = 0, g_nFrames = 0; // FPS和FPS 计数器 DWORD g_dwLastFPS = 0; //最后依次计算FPS的时间 |
代码: |
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 // Load Texture Data m_pTextureImage = auxDIBImageLoad( szPath ); // Utilize GLaux's Bitmap Load Routine |
代码: |
// 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 ); // Set The Data, Using PtHeight To Obtain The Y value m_pVertices[nIndex].x = flX - ( m_pTextureImage->sizeX / 2 ); m_pVertices[nIndex].y = PtHeight( (int) flX, (int) flZ ) * flHeightScale; m_pVertices[nIndex].z = flZ - ( m_pTextureImage->sizeY / 2 ); // Stretch The Texture Across The Entire Mesh
m_pTexCoords[nIndex].u = flX / m_pTextureImage->sizeX; m_pTexCoords[nIndex].v = flZ / m_pTextureImage->sizeY; // Increment Our Index nIndex++; }
} } |
代码: |
// 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); // Free The Texture Data
if( m_pTextureImage ) { if( m_pTextureImage->data ) free( m_pTextureImage->data ); free( m_pTextureImage ); } return true; } |
代码: |
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 ); // Generate And Bind The Texture Coordinate Buffer glGenBuffersARB( 1, &m_nVBOTexCoords ); // Get A Valid Name glBindBufferARB( GL_ARRAY_BUFFER_ARB, m_nVBOTexCoords ); // Bind The Buffer // Load The Data glBufferDataARB( GL_ARRAY_BUFFER_ARB, m_nVertexCount*2*sizeof(float), m_pTexCoords, GL_STATIC_DRAW_ARB ); // Our Copy Of The Data Is No Longer Necessary, It Is Safe In The Graphics Card delete [] m_pVertices; m_pVertices = NULL; delete [] m_pTexCoords; m_pTexCoords = NULL; } |
代码: |
// 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; } // Check For VBOs Supported
#ifndef NO_VBOS g_fVBOSupported = IsExtensionSupported( "GL_ARB_vertex_buffer_object" ); if( g_fVBOSupported ) { // Get Pointers To The GL Functions glGenBuffersARB = (PFNGLGENBUFFERSARBPROC) wglGetProcAddress("glGenBuffersARB"); glBindBufferARB = (PFNGLBINDBUFFERARBPROC) wglGetProcAddress("glBindBufferARB"); glBufferDataARB = (PFNGLBUFFERDATAARBPROC) wglGetProcAddress("glBufferDataARB"); glDeleteBuffersARB = (PFNGLDELETEBUFFERSARBPROC) wglGetProcAddress("glDeleteBuffersARB"); // Load Vertex Data Into The Graphics Card Memory g_pMesh->BuildVBOs(); // Build The VBOs } #else /* NO_VBOS */ g_fVBOSupported = false; #endif |
代码: |
bool IsExtensionSupported( char* szTargetExtension )
{ const unsigned char *pszExtensions = NULL; const unsigned char *pszStart; unsigned char *pszWhere, *pszTerminator; // Extension names should not have spaces
pszWhere = (unsigned char *) strchr( szTargetExtension, ' ' ); if( pszWhere || *szTargetExtension == '' ) return false; // Get Extensions String pszExtensions = glGetString( GL_EXTENSIONS ); // Search The Extensions String For An Exact Copy
pszStart = pszExtensions; for(;;) { pszWhere = (unsigned char *) strstr( (const char *) pszStart, szTargetExtension ); if( !pszWhere ) break; pszTerminator = pszWhere + strlen( szTargetExtension ); if( pszWhere == pszStart || *( pszWhere - 1 ) == ' ' ) if( *pszTerminator == ' ' || *pszTerminator == '' ) return true; pszStart = pszTerminator; } return false; } |
代码: |
void Draw (void)
{ glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear Screen And Depth Buffer glLoadIdentity (); // Reset The Modelview Matrix // Get FPS
if( GetTickCount() - g_dwLastFPS >= 1000 ) // When A Second Has Passed... { g_dwLastFPS = GetTickCount(); // Update Our Time Variable g_nFPS = g_nFrames; // Save The FPS g_nFrames = 0; // Reset The FPS Counter char szTitle[256]=; // Build The Title String
sprintf( szTitle, "Lesson 45: Nehe & Paul Frazee's VBO Tut - %d Triangles, %d FPS", g_pMesh->m_nVertexCount / 3, g_nFPS ); if( g_fVBOSupported ) // Include A Notice About VBOs strcat( szTitle, ", Using VBOs" ); else strcat( szTitle, ", Not Using VBOs" ); SetWindowText( g_window->hWnd, szTitle ); // Set The Title } g_nFrames++; // Increment Our FPS Counter // Move The Camera
glTranslatef( 0.0f, -220.0f, 0.0f ); // Move Above The Terrain glRotatef( 10.0f, 1.0f, 0.0f, 0.0f ); // Look Down Slightly glRotatef( g_flYRot, 0.0f, 1.0f, 0.0f ); // Rotate The Camera |
代码: |
// 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 |
代码: |
// Disable Pointers
glDisableClientState( GL_VERTEX_ARRAY ); // Disable Vertex Arrays glDisableClientState( GL_TEXTURE_COORD_ARRAY ); // Disable Texture Coord Arrays } |
|
|
|
|
|
|
|
|
|