Главная Статьи Ссылки Скачать Скриншоты Юмор Почитать Tools Проекты Обо мне Гостевая |
Не секрет, что для серьезного использования OpenGL сейчас необходимо пользоваться различными расширениями (по крайней мере под форточками, где до сих пор OpenGL 1.1).
Использование расширений дает как доступ к таким стандартным уже возможностям, как шейдеры, так и к довольно специфическим возможностям конкретным видеокарточек.
Существует довольно много различных библиотек, предназначенных для работы с расширениями OpenGL (одна из них - мою libExt - постоянно используется в примерах с данного сайта).
В этой статье я хочу рассмотреть одну из самых популярных таких библиотек - (вошедшую в состав OpenGL SDK) - библиотеку OpenGL Extension Wrangler Library - GLew.
Это простая в использовании кроссплатформенная (в числе поддерживаемых платформ - M$ Windoze, Linux, Mac OS X, Solaris и другие ) библиотека обеспечивает удобство в использовании расширений OpenGL.
Для M$ Windoze (как и многих других платформ) можно скачать уже откомпилированную версию, состоящую из заголовочного файла glew.h, динамической библиотеки glew32.dll и двух библиотек glew32.lib и glew32s.lib.
При этом вы можете для компиляции своих программ использовать как статическую версию (т.е. не требующую динамической библиотеки glew32.dll, библиотечный файл glew32s.lib), так и динамическую (библиотека glew32.lib). В последнем случае для выполнения потребуется glew32.dll, но размер выполняемого файла будет меньше.
Для использования библиотеки необходимо подключить ее заголовочный файл glew.h вместо файла gl.h (он сам подключает все, что надо).
Далее для инициализации библиотеки необходимо вызвать функцию glewInit, возвращающую значение GL_TRUE при успешной инициализации библиотеки.
Обратите внимание, что данная функция должна быть вызвана уже после того, как будет создан и настроен контекст OpenGL, например в программах, использующих GLUT, после вызова функции glutCreateWindow.
Самый простой способ проверить поддержку расширения с заданным именем заключается в проверке значения глобальной переменной с именем вида GLEW_имя-расширения (т.е. в названии расширения GL заменяется на GLEW).
Так расширению GL_ARB_vertex_program соответствует глобальная переменная GLEW_ARB_vertex_program. Если она отлична от нуля, то данное расширение поддерживается и Вы можете напрямую обращаться к функциям, вводимым этим расширением.
Также можно проверить поддержку расширения по строке, содержащей его имя, при помощи функции glewIsSupported.
if ( glewInit () != GLEW_OK ) { printf ( "Error in glewInit\n" ); return 1; } if ( !GLEW_ARB_shading_language_100 ) { printf ( "GL_ARB_shading_language_100 NOT supported.\n" ); return 1; } if ( !GLEW_ARB_shader_objects ) { printf ( "GL_ARB_shader_objects NOT supported" ); return 2; }
Для работы с расширениями, специфичными для определенной платформы дополнительно включите заголовочный файл wglew.h (для платформы M$ Windoze) или glxew.h (для Linux).
Аналогичным способом можно проверить поддержку заданной версии OpenGL - каждой версии соответствует глобальная переменная вида GLEW_VERSION_n_m (через n и m обозначены старший и младший номера версии, например 1.4).
Так следующий фрагмент кода проверяет поддержку OpenGL 1.4.
if ( GLEW_VERSION_1_4 ) { ... }
Этого же можно добиться и используя функцию glewIsSupported:
if ( glewIsSupported ( "VERSION_1_4" ) ) { ... }
Для поддержки ряда экспериментальных расширений следует перед вызовом glewInit установить значение глобальной переменной glewExperimental в GL_TRUE.
Ниже приводится исходный текст простого примера, использующего библиотеку GLew для работы с шейдерами в OpenGL (обратите внимание, что данной программе кроме библиотек GLUT и GLew больше ничего не нужно).
#include <GL/glew.h> #include <GL/gl.h> #include <GL/glu.h> #ifdef _WIN32 #include <GL/wglew.h> #else #include <GL/glxew.h> #endif #include <glut.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <ctype.h> #include <math.h> float eye [] = { 7, 5, 7, 1 }; // camera position float light [] = { 5, 0, 4, 1 }; // light position float rot [] = { 0, 0, 0 }; float angle = 0; int mouseOldX = 0; int mouseOldY = 0; GLhandleARB program = 0; // program handles GLhandleARB vertexShader = 0; GLhandleARB fragmentShader = 0; bool checkOpenGLError () { bool retCode = true; for ( ; ; ) { GLenum glErr = glGetError (); if ( glErr == GL_NO_ERROR ) return retCode; printf ( "glError: %s\n", gluErrorString ( glErr ) ); retCode = false; glErr = glGetError (); } return retCode; } void printInfoLog ( GLhandleARB object ) { int logLength = 0; int charsWritten = 0; GLcharARB * infoLog; checkOpenGLError (); // check for OpenGL errors glGetObjectParameterivARB ( object, GL_OBJECT_INFO_LOG_LENGTH_ARB, &logLength ); if ( !checkOpenGLError() ) // check for OpenGL errors exit ( 1 ); if ( logLength > 0 ) { infoLog = (GLcharARB*) malloc ( logLength ); if ( infoLog == NULL ) { printf("ERROR: Could not allocate InfoLog buffer\n"); exit ( 1 ); } glGetInfoLogARB ( object, logLength, &charsWritten, infoLog ); printf ( "InfoLog:\n%s\n\n", infoLog ); free ( infoLog ); } if ( !checkOpenGLError () ) // check for OpenGL errors exit ( 1 ); } bool loadShader ( GLhandleARB shader, const char * fileName ) { printf ( "Loading %s\n", fileName ); FILE * file = fopen ( fileName, "rb" ); if ( file == NULL ) { printf ( "Error opening %s\n", fileName ); exit ( 1 ); } fseek ( file, 0, SEEK_END ); int size = ftell ( file ); if ( size < 1 ) { fclose ( file ); printf ( "Error loading file %s\n", fileName ); exit ( 1 ); } char * buf = (char *) malloc ( size ); fseek ( file, 0, SEEK_SET ); if ( fread ( buf, 1, size, file ) != size ) { fclose ( file ); printf ( "Error loading file %s\n", fileName ); exit ( 1 ); } fclose ( file ); GLint compileStatus; glShaderSourceARB ( shader, 1, (const char **) &buf, &size ); free ( buf ); // compile the particle vertex shader, and print out glCompileShaderARB ( shader ); if ( !checkOpenGLError() ) // check for OpenGL errors return false; glGetObjectParameterivARB ( shader, GL_OBJECT_COMPILE_STATUS_ARB, &compileStatus ); printInfoLog ( shader ); return compileStatus != 0; } bool setUniformVector ( GLhandleARB program, const char * name, const float * value ) { int loc = glGetUniformLocationARB ( program, name ); if ( loc < 0 ) return false; glUniform4fvARB ( loc, 1, value ); return true; } void init () { glClearColor ( 0.5, 0.5, 0.5, 1.0 ); glEnable ( GL_DEPTH_TEST ); glDepthFunc ( GL_LEQUAL ); glHint ( GL_POLYGON_SMOOTH_HINT, GL_NICEST ); glHint ( GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST ); } void display () { glClear ( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); // draw the light glMatrixMode ( GL_MODELVIEW ); glPushMatrix (); glTranslatef ( light [0], light [1], light [2] ); glColor4f ( 1, 1, 1, 1 ); glutSolidSphere ( 0.1f, 15, 15 ); glPopMatrix (); glMatrixMode ( GL_MODELVIEW ); glPushMatrix (); glRotatef ( rot [0], 1, 0, 0 ); glRotatef ( rot [1], 0, 1, 0 ); glRotatef ( rot [2], 0, 0, 1 ); glUseProgramObjectARB ( program ); glutSolidTeapot ( 2.5 ); glUseProgramObjectARB ( 0 ); glPopMatrix (); glutSwapBuffers (); } void reshape ( int w, int h ) { glViewport ( 0, 0, (GLsizei)w, (GLsizei)h ); glMatrixMode ( GL_PROJECTION ); // factor all camera ops into projection matrix glLoadIdentity (); gluPerspective ( 60.0, (GLfloat)w/(GLfloat)h, 1.0, 60.0 ); gluLookAt ( eye [0], eye [1], eye [2], // eye 0, 0, 0, // center 0.0, 0.0, 1.0 ); // up glMatrixMode ( GL_MODELVIEW ); glLoadIdentity (); } void motion ( int x, int y ) { rot [1] -= ((mouseOldY - y) * 180.0f) / 200.0f; rot [2] -= ((mouseOldX - x) * 180.0f) / 200.0f; rot [0] = 0; for ( int i = 0; i < 3; i++ ) if ( rot [i] > 360 ) rot [i] -= 360; else if ( rot [i] < -360 ) rot [i] += 360; mouseOldX = x; mouseOldY = y; glutPostRedisplay (); } void mouse ( int button, int state, int x, int y ) { if ( state == GLUT_DOWN ) { mouseOldX = x; mouseOldY = y; } } void key ( unsigned char key, int x, int y ) { if ( key == 27 || key == 'q' || key == 'Q' ) // quit requested exit ( 0 ); } void animate () { angle = 0.004f * glutGet ( GLUT_ELAPSED_TIME ); light [0] = 2*cos ( angle ); light [1] = 3*sin ( 1.4 * angle ); light [2] = 3 + 0.5 * sin ( angle / 3 ); glUseProgramObjectARB ( program ); setUniformVector ( program, "eyePos", eye ); setUniformVector ( program, "lightPos", light ); glUseProgramObjectARB ( 0 ); glutPostRedisplay (); } int main ( int argc, char * argv [] ) { // initialize glut glutInit ( &argc, argv ); glutInitDisplayMode ( GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH ); glutInitWindowSize ( 500, 500 ); // create window glutCreateWindow ( "Example of GLSL Blinn shader" ); // register handlers glutDisplayFunc ( display ); glutReshapeFunc ( reshape ); glutKeyboardFunc ( key ); glutMouseFunc ( mouse ); glutMotionFunc ( motion ); glutIdleFunc ( animate ); init (); if ( glewInit () != GLEW_OK ) { printf ( "Error in glewInit\n" ); return 1; } if ( !GLEW_ARB_shading_language_100 ) { printf ( "GL_ARB_shading_language_100 NOT supported.\n" ); return 1; } if ( !GLEW_ARB_shader_objects ) { printf ( "GL_ARB_shader_objects NOT supported" ); return 2; } GLint linked; // create a vertex shader object and a fragment shader object vertexShader = glCreateShaderObjectARB ( GL_VERTEX_SHADER_ARB ); fragmentShader = glCreateShaderObjectARB ( GL_FRAGMENT_SHADER_ARB ); // load source code strings into shaders if ( !loadShader ( vertexShader, "blinn.vsh" ) ) exit ( 1 ); if ( !loadShader ( fragmentShader, "blinn.fsh" ) ) exit ( 1 ); // create a program object and attach the // two compiled shaders program = glCreateProgramObjectARB (); glAttachObjectARB ( program, vertexShader ); glAttachObjectARB ( program, fragmentShader ); // link the program object and print out the info log glLinkProgramARB ( program ); if ( !checkOpenGLError() ) // check for OpenGL errors exit ( 1 ); glGetObjectParameterivARB ( program, GL_OBJECT_LINK_STATUS_ARB, &linked ); if ( !linked ) return 0; glutMainLoop (); return 0; }
По этой ссылке можно скачать весь исходный код к этой статье. Также доступны для скачивания откомпилированные версии для M$ Windows, Linux и Mac OS X.