www.pudn.com > ogl_cg_displacement_mapping.zip > ogl_cg_displacement_mapping.cpp
//----------------------------------------------------------------------------- // Name: ogl_cg_displacement_mapping.cpp // Author: Kevin Harris (kevin@codesampler.com) // Last Modified: 06/10/05 // Description: This sample demonstrates how to perform displacement mapping // using Cg. The sample requirs support for CG_PROFILE_VP40, // which basically means that your card needs to support // GL_ARB_vertex_program and GL_NV_vertex_program3. // // Control Keys: s - Toggle usage of displacement shader. // w - Toggle wire-frame mode. // d - Increase displacement. // D - Decrease displacement. //----------------------------------------------------------------------------- #define STRICT #define WIN32_LEAN_AND_MEAN #include#include #include #include #include #include #include #include "resource.h" // For convenience, this project ships with its own "glext.h" extension header // file. If you have trouble running this sample, it may be that this "glext.h" // file is defining something that your hardware doesn’t actually support. // Try recompiling the sample using your own local, vendor-specific "glext.h" // header file. #include "glext.h" // Sample's header file //#include // Your local header file //----------------------------------------------------------------------------- // GLOBALS //----------------------------------------------------------------------------- HDC g_hDC = NULL; HGLRC g_hRC = NULL; HWND g_hWnd = NULL; HINSTANCE g_hInstance = NULL; GLuint g_decalTextureID = 0; GLuint g_displacementTextureID = 0; CGprofile g_CGprofile_vertex; CGcontext g_CGcontext; CGprogram g_CGprogram_vertex; CGparameter g_CGparam_displacementTexture; CGparameter g_CGparam_displacementScaler; bool g_bUseShaders = true; bool g_bWireFrameMode = false; float g_fDisplacementScaler = 0.5f; float g_fSpinX = 0.0f; float g_fSpinY = 0.0f; struct Vertex { // GL_T2F_C4F_N3F_V3F float tu, tv; float r, g, b, a; float nx, ny, nz; float x, y, z; }; // // Mesh properties... // const int g_nNumVertsAlongX = 64; const int g_nNumVertsAlongZ = 64; const float g_fMeshLengthAlongX = 2.0f; const float g_fMeshLengthAlongZ = 2.0f; // // -- Regular mesh -- // // Composed of simple triangles. // // Number of vertices required for the mesh const int g_nRegularVertCount = (g_nNumVertsAlongX-1) * (g_nNumVertsAlongZ-1) * 6; Vertex g_meshVertices[g_nRegularVertCount]; //----------------------------------------------------------------------------- // PROTOTYPES //----------------------------------------------------------------------------- int WINAPI WinMain(HINSTANCE g_hInstance,HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow); LRESULT CALLBACK WindowProc(HWND g_hWnd, UINT msg, WPARAM wParam, LPARAM lParam); void loadTextures(void); void init(void); void render(void); void shutDown(void); void initShader(void); void createMesh(void); //----------------------------------------------------------------------------- // Name: WinMain() // Desc: The application's entry point //----------------------------------------------------------------------------- int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow ) { WNDCLASSEX winClass; MSG uMsg; memset(&uMsg,0,sizeof(uMsg)); winClass.lpszClassName = "MY_WINDOWS_CLASS"; winClass.cbSize = sizeof(WNDCLASSEX); winClass.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC; winClass.lpfnWndProc = WindowProc; winClass.hInstance = hInstance; winClass.hIcon = LoadIcon(hInstance, (LPCTSTR)IDI_OPENGL_ICON); winClass.hIconSm = LoadIcon(hInstance, (LPCTSTR)IDI_OPENGL_ICON); winClass.hCursor = LoadCursor(NULL, IDC_ARROW); winClass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH); winClass.lpszMenuName = NULL; winClass.cbClsExtra = 0; winClass.cbWndExtra = 0; if( !RegisterClassEx(&winClass) ) return E_FAIL; g_hWnd = CreateWindowEx( NULL,"MY_WINDOWS_CLASS", "OpenGL - Simple Displacement Mapping Using Cg", WS_OVERLAPPEDWINDOW, 0,0, 640,480, NULL, NULL, g_hInstance, NULL ); if( g_hWnd == NULL ) return E_FAIL; ShowWindow( g_hWnd, nCmdShow ); UpdateWindow( g_hWnd ); init(); initShader(); while( uMsg.message != WM_QUIT ) { if( PeekMessage( &uMsg, NULL, 0, 0, PM_REMOVE ) ) { TranslateMessage( &uMsg ); DispatchMessage( &uMsg ); } else render(); } shutDown(); UnregisterClass( "MY_WINDOWS_CLASS", g_hInstance ); return uMsg.wParam; } //----------------------------------------------------------------------------- // Name: WindowProc() // Desc: The window's message handler //----------------------------------------------------------------------------- LRESULT CALLBACK WindowProc( HWND g_hWnd, UINT msg, WPARAM wParam, LPARAM lParam ) { static POINT ptLastMousePosit; static POINT ptCurrentMousePosit; static bool bMousing; switch( msg ) { case WM_CHAR: { switch( wParam ) { case 's': case 'S': g_bUseShaders = !g_bUseShaders; break; case 'w': case 'W': g_bWireFrameMode = !g_bWireFrameMode; break; case 'd': g_fDisplacementScaler += 0.1f; break; case 'D': g_fDisplacementScaler -= 0.1f; break; } } break; case WM_KEYDOWN: { switch( wParam ) { case VK_ESCAPE: PostQuitMessage(0); break; } } break; case WM_LBUTTONDOWN: { ptLastMousePosit.x = ptCurrentMousePosit.x = LOWORD (lParam); ptLastMousePosit.y = ptCurrentMousePosit.y = HIWORD (lParam); bMousing = true; } break; case WM_LBUTTONUP: { bMousing = false; } break; case WM_MOUSEMOVE: { ptCurrentMousePosit.x = LOWORD (lParam); ptCurrentMousePosit.y = HIWORD (lParam); if( bMousing ) { g_fSpinX -= (ptCurrentMousePosit.x - ptLastMousePosit.x); g_fSpinY -= (ptCurrentMousePosit.y - ptLastMousePosit.y); } ptLastMousePosit.x = ptCurrentMousePosit.x; ptLastMousePosit.y = ptCurrentMousePosit.y; } break; case WM_SIZE: { int nWidth = LOWORD(lParam); int nHeight = HIWORD(lParam); glViewport(0, 0, nWidth, nHeight); glMatrixMode( GL_PROJECTION ); glLoadIdentity(); gluPerspective( 45.0, (GLdouble)nWidth / (GLdouble)nHeight, 0.1, 100.0); } break; case WM_CLOSE: { PostQuitMessage(0); } case WM_DESTROY: { PostQuitMessage(0); } break; default: { return DefWindowProc( g_hWnd, msg, wParam, lParam ); } break; } return 0; } //----------------------------------------------------------------------------- // Name: loadTextures() // Desc: //----------------------------------------------------------------------------- void loadTextures( void ) { // // Load the displacement map as a float texture. The displacement map is // basically just a gray-scale height map, Later, we will pass this to the // vertex shader where it will be used to displace the vertices. // AUX_RGBImageRec *pTextureImage = auxDIBImageLoad( ".\\nveye_displace.bmp" ); if( pTextureImage != NULL ) { glGenTextures( 1, &g_displacementTextureID ); glBindTexture( GL_TEXTURE_2D, g_displacementTextureID ); // // Note the GL_NEAREST mip-map settings and the float-texture format of // GL_RGBA_FLOAT32_ATI used by our displacement map. // glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST ); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST ); gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGBA_FLOAT32_ATI, pTextureImage->sizeX, pTextureImage->sizeY, GL_RGB, GL_UNSIGNED_BYTE, pTextureImage->data ); } if( pTextureImage ) { if( pTextureImage->data ) free( pTextureImage->data ); free( pTextureImage ); } // // Load a regular decal texture... // pTextureImage = auxDIBImageLoad( ".\\nveye.bmp" ); if( pTextureImage != NULL ) { glGenTextures( 1, &g_decalTextureID ); glBindTexture( GL_TEXTURE_2D, g_decalTextureID ); glTexParameteri( GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER, GL_LINEAR ); glTexParameteri( GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER, GL_LINEAR ); glTexImage2D( GL_TEXTURE_2D, 0, 3, pTextureImage->sizeX, pTextureImage->sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, pTextureImage->data ); } if( pTextureImage ) { if( pTextureImage->data ) free( pTextureImage->data ); free( pTextureImage ); } } //----------------------------------------------------------------------------- // Name: init() // Desc: //----------------------------------------------------------------------------- void init( void ) { GLuint PixelFormat; PIXELFORMATDESCRIPTOR pfd; memset(&pfd, 0, sizeof(PIXELFORMATDESCRIPTOR)); pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR); pfd.nVersion = 1; pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER; pfd.iPixelType = PFD_TYPE_RGBA; pfd.cColorBits = 16; pfd.cDepthBits = 16; g_hDC = GetDC( g_hWnd ); PixelFormat = ChoosePixelFormat( g_hDC, &pfd ); SetPixelFormat( g_hDC, PixelFormat, &pfd ); g_hRC = wglCreateContext( g_hDC ); wglMakeCurrent( g_hDC, g_hRC ); glClearColor( 0.35f, 0.53f, 0.7f, 1.0f ); glEnable( GL_TEXTURE_2D ); glEnable( GL_DEPTH_TEST ); glMatrixMode( GL_PROJECTION ); glLoadIdentity(); gluPerspective( 45.0f, 640.0f / 480.0f, 0.1f, 100.0f ); loadTextures(); createMesh(); } //----------------------------------------------------------------------------- // Name: createMesh() // Desc: //----------------------------------------------------------------------------- void createMesh( void ) { // Compute position deltas for moving down the X, and Z axis during mesh creation const float dX = (1.0f/(g_nNumVertsAlongX-1)); const float dZ = -(1.0f/(g_nNumVertsAlongZ-1)); // Compute tex-coord deltas for moving down the X, and Z axis during mesh creation const float dTU = 1.0f/(g_nNumVertsAlongX-1); const float dTV = 1.0f/(g_nNumVertsAlongZ-1); int i = 0; int x = 0; int z = 0; // These are all the same... for( i = 0; i < g_nRegularVertCount; ++i ) { // Mesh tesselation occurs in the X,Z plane, so Y is always zero g_meshVertices[i].y = 0.0f; g_meshVertices[i].nx = 0.0f; g_meshVertices[i].ny = 1.0f; g_meshVertices[i].nz = 0.0f; g_meshVertices[i].r = 1.0f; g_meshVertices[i].g = 1.0f; g_meshVertices[i].b = 1.0f; } // // Create all the vertex points required by the mesh... // // Note: Mesh tesselation occurs in the X,Z plane. // // For each row of our mesh... for( z = 0, i = 0; z < (g_nNumVertsAlongZ-1); ++z ) { // Fill the row with quads which are composed of two triangles each... for( x = 0; x < (g_nNumVertsAlongX-1); ++x ) { // First triangle of the current quad // ___ 2 // | /| // |/__| // 0 1 // 0 g_meshVertices[i].x = g_fMeshLengthAlongX * x * dX; g_meshVertices[i].z = g_fMeshLengthAlongZ * z * dZ; g_meshVertices[i].tu = x * dTU; g_meshVertices[i].tv = z * dTV; ++i; // 1 g_meshVertices[i].x = g_fMeshLengthAlongX * (x+1.0f) * dX; g_meshVertices[i].z = g_fMeshLengthAlongZ * z * dZ; g_meshVertices[i].tu = (x+1.0f) * dTU; g_meshVertices[i].tv = z * dTV; ++i; // 2 g_meshVertices[i].x = g_fMeshLengthAlongX * (x+1.0f) * dX; g_meshVertices[i].z = g_fMeshLengthAlongZ * (z+1.0f) * dZ; g_meshVertices[i].tu = (x+1.0f) * dTU; g_meshVertices[i].tv = (z+1.0f) * dTV; ++i; // Second triangle of the current quad // 2 ___ 1 // | /| // |/__| // 0 // 0 g_meshVertices[i].x = g_fMeshLengthAlongX * x * dX; g_meshVertices[i].z = g_fMeshLengthAlongZ * z * dZ; g_meshVertices[i].tu = x * dTU; g_meshVertices[i].tv = z * dTV; ++i; // 1 g_meshVertices[i].x = g_fMeshLengthAlongX * (x+1.0f) * dX; g_meshVertices[i].z = g_fMeshLengthAlongZ * (z+1.0f) * dZ; g_meshVertices[i].tu = (x+1.0f) * dTU; g_meshVertices[i].tv = (z+1.0f) * dTV; ++i; // 2 g_meshVertices[i].x = g_fMeshLengthAlongX * x * dX; g_meshVertices[i].z = g_fMeshLengthAlongZ * (z+1.0f) * dZ; g_meshVertices[i].tu = x * dTU; g_meshVertices[i].tv = (z+1.0f) * dTV; ++i; } } } //----------------------------------------------------------------------------- // Name: initShader() // Desc: Load the CG shader //----------------------------------------------------------------------------- void initShader( void ) { // // Search for a certain vertex shader profile: // // CG_PROFILE_VP40 - GL_ARB_vertex_program + GL_NV_vertex_program3 // if( cgGLIsProfileSupported(CG_PROFILE_VP40) ) g_CGprofile_vertex = CG_PROFILE_VP40; else { MessageBox( NULL,"Failed to initialize vertex shader! Hardware doesn't " "support CG_PROFILE_VP40, which is required to run!", "ERROR",MB_OK|MB_ICONEXCLAMATION ); return; } // Create the context... g_CGcontext = cgCreateContext(); // // Create a displacement shader... // g_CGprogram_vertex = cgCreateProgramFromFile( g_CGcontext, CG_SOURCE, "ogl_cg_displacement_mapping.cg", g_CGprofile_vertex, NULL, NULL ); // // Load the programs using Cg's expanded interface... // cgGLLoadProgram( g_CGprogram_vertex ); // // Bind some parameters by name so we can set them later... // g_CGparam_displacementTexture = cgGetNamedParameter(g_CGprogram_vertex, "displacementTexture"); g_CGparam_displacementScaler = cgGetNamedParameter(g_CGprogram_vertex, "displacementScaler"); } //----------------------------------------------------------------------------- // Name: shutDown() // Desc: //----------------------------------------------------------------------------- void shutDown( void ) { glDeleteTextures( 1, &g_decalTextureID ); glDeleteTextures( 1, &g_displacementTextureID ); cgDestroyProgram( g_CGprogram_vertex ); cgDestroyContext( g_CGcontext ); if( g_hRC != NULL ) { wglMakeCurrent( NULL, NULL ); wglDeleteContext( g_hRC ); g_hRC = NULL; } if( g_hDC != NULL ) { ReleaseDC( g_hWnd, g_hDC ); g_hDC = NULL; } } //----------------------------------------------------------------------------- // Name: render() // Desc: //----------------------------------------------------------------------------- void render( void ) { // Clear the screen and the depth buffer glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); if( g_bWireFrameMode ) glPolygonMode( GL_FRONT_AND_BACK, GL_LINE ); else glPolygonMode( GL_FRONT_AND_BACK, GL_FILL ); glMatrixMode( GL_MODELVIEW ); glLoadIdentity(); glTranslatef( 0.0f, 0.0f, -3.0f ); glRotatef( -(g_fSpinY - 90.0f), 1.0f, 0.0f, 0.0f ); glRotatef( -g_fSpinX, 0.0f, 1.0f, 0.0f ); // Since the mesh is created off-center in the XZ plane we'll need to move // it to the center for it to spin correctly in the sample. glTranslatef( -(g_fMeshLengthAlongX/2.0f), 0.0f, (g_fMeshLengthAlongZ/2.0f) ); if( g_bUseShaders == true ) { float fdisplacementScaler[] = { g_fDisplacementScaler, 0.0f, 0.0f, 1.0f }; cgGLSetParameter4fv( g_CGparam_displacementScaler, fdisplacementScaler ); cgGLEnableTextureParameter( g_CGparam_displacementTexture ); cgGLSetTextureParameter( g_CGparam_displacementTexture, g_displacementTextureID ); cgGLBindProgram( g_CGprogram_vertex ); cgGLEnableProfile( g_CGprofile_vertex ); // Assign the regular decal texture glBindTexture( GL_TEXTURE_2D, g_decalTextureID ); glInterleavedArrays( GL_T2F_C4F_N3F_V3F, 0, g_meshVertices ); glDrawArrays( GL_TRIANGLES, 0, g_nRegularVertCount ); cgGLDisableTextureParameter( g_CGparam_displacementTexture ); cgGLDisableProfile( g_CGprofile_vertex ); } else { // // Render the normal way... // glBindTexture( GL_TEXTURE_2D, g_decalTextureID ); glInterleavedArrays( GL_T2F_C4F_N3F_V3F, 0, g_meshVertices ); glDrawArrays( GL_TRIANGLES, 0, g_nRegularVertCount ); } SwapBuffers( g_hDC ); }