OpenGL |
Здравствуйте, гость ( Вход | Регистрация )
OpenGL |
January 6 2006, 18:30
Сообщение
#1
|
|
Жутко ленивый. Группа: Администраторы Сообщений: 2661 Регистрация: 22.11.2005 Из: Москва, Марьино Пользователь №: 1 Skype: dudnikov.v Реальное имя: Владимир |
Краткое описание основных функций OpenGl для MSVC++ и BCB(Borland CBuilder).
Статья по работе с OpenGL в BCB и Delphi: Код Все, что написано в такой форме - код для BCB Цитата Все, что написано в такой форме - код для Delphi Основы программирования OpenGL в Borland С++Builder и Delphi. Автор: Луковкин Сергей Введение На кого рассчитана статья Я рассчитываю на то, что вы знакомы с азами создания приложений в С++Builder или Delphi и совсем не знаете OpenGL. Введение OpenGL (Open Graphics Library) - популярная библиотека для работы с 3D графикой. Стандарт OpenGL появился в 1992 году благодаря компании Silicon Graphics и сейчас переживает годы своего самого бурного развития. Чуть-чуть побольше узнать об OpenGL и о том, как с ним работать в VC, можно почитав wat'а: http://www.gamedev.ru/articles/read.shtml?id=20003 Я хочу показать, как работать с этой библиотекой в таких популярных и, на мой взгляд, очень удобных средах разработки как Delphi и С++Builder. Эта - первая - статья посвящена в основном инициализации OpenGL. Инициализация Первым делом нужно подключить заголовочные файлы: Код #include <GL/gl.h> #include <GL/glu.h> #include <GL/glaux.h> Цитата uses OpenGL; Если вы используете Delphi, то всё необходимое для работы с OpenGL находится в модуле OpenGL.dcu. А если вы используете С++Builder, то подключать придётся несколько файлов: · gl.h и glu.h содержат прототипы основных функций OpenGL определённых в opengl32.dll и glu32.dll. · glaux.h содержит вспомогательные (auxiliary) функции (glaux.dll). В этой статье я не буду использовать glaux.h, т.к. его функции не доступны в Delphi, да и не люблю я эту библиотекуJ. Кроме того основные задачи glaux (как, в прочем, и аналогичной, но более качественной, библиотеки GLUT) - это создание окон, таймеров, обработка клавиатуры и мыши, всё это есть в ИСР (Интегральная Среда Разработки) Delphi или С++Builder. После подключения заголовочных файлов нужно установить формат пикселей. Я для этой цели использую следующую функцию: Код BOOL bSetupPixelFormat(HDC hdc) { PIXELFORMATDESCRIPTOR pfd, *ppfd; int pixelformat; ppfd = &pfd; ppfd->nSize = sizeof(PIXELFORMATDESCRIPTOR); ppfd->nVersion = 1; ppfd->dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER; ppfd->dwLayerMask = PFD_MAIN_PLANE; ppfd->iPixelType = PFD_TYPE_RGBA; ppfd->cColorBits = 16; ppfd->cDepthBits = 16; ppfd->cAccumBits = 0; ppfd->cStencilBits = 0; if ((pixelformat = ChoosePixelFormat(hdc, ppfd)) == 0) { MessageBox(NULL, "ChoosePixelFormat failed", "Error", MB_OK); return FALSE; } if (SetPixelFormat(hdc, pixelformat, ppfd) == FALSE) { MessageBox(NULL, "SetPixelFormat failed", "Error", MB_OK); return FALSE; } return TRUE; } Цитата function bSetupPixelFormat(DC:HDC):boolean; var pfd:PIXELFORMATDESCRIPTOR; ppfd:PPIXELFORMATDESCRIPTOR; pixelformat:integer; begin ppfd := @pfd; ppfd.nSize := sizeof(PIXELFORMATDESCRIPTOR); ppfd.nVersion := 1; ppfd.dwFlags := PFD_DRAW_TO_WINDOW xor PFD_SUPPORT_OPENGL xor PFD_DOUBLEBUFFER; ppfd.dwLayerMask := PFD_MAIN_PLANE; ppfd.iPixelType := PFD_TYPE_RGBA; ppfd.cColorBits := 16; ppfd.cDepthBits := 16; ppfd.cAccumBits := 0; ppfd.cStencilBits := 0; pixelformat := ChoosePixelFormat(dc, ppfd); if pixelformat=0 then begin MessageBox(0, 'ChoosePixelFormat failed', 'Error', MB_OK); bSetupPixelFormat:=FALSE; exit; end; if SetPixelFormat(dc, pixelformat, ppfd)=false then begin MessageBox(0, 'SetPixelFormat failed', 'Error', MB_OK); bSetupPixelFormat:=FALSE; exit; end; bSetupPixelFormat:=TRUE; end; Вряд ли вам придётся менять что-нибудь в этой функции, но кое-что о структуре PIXELFORMATDESCRIPTOR сказать надо. cColorBits - глубина цвета cDepthBits - размер буфера глубины (Z-Buffer) cStencilBits - размер буфера трафарета (мы его пока не используем) iPixelType - формат указания цвета. Может принимать значения PFD_TYPE_RGBA (цвет указывается четырьмя параметрами RGBA - красный, зленный, синий и альфа) и PFD_TYPE_COLORINDEX (цвет указывается индексом в палитре). Как вы видите, я использую RGBA, и вам придётся поступить также, т.к. если вы захотите использовать COLORINDEX, то вам придётся изменить мою функцию: добавить пару флагов и дать начальные значения ещё нескольким переменным. Более подробную информацию смотрите в справочнике или в MSDN. Функция ChoosePixelFormat() подбирает формат пикселей, максимально удовлетворяющий нашим требованиям, и возвращает его дескриптор, а SetPixelFormat() устанавливает его в контексте устройства (dc). После того как в контексте устройства установлен формат пикселей, нужно создать контекст воспроизведения (Rendering Context) для этого в OpenGL определены следующие функции: Код HGLRC wglCreateContext(HDC hdc); BOOL wglMakeCurrent(HDC hdc, HGLRC hglrc); Цитата function wglCreateContext(dc: HDC): HGLRC; function wglMakeCurrent(dc: HDC; glrc: HGLRC):Boolean; Наверное, объяснять их значение не стоит Теперь перейдём к форме. В объявлении класса формы в области private добавьте следующее: Код HGLRC ghRC; HDC ghDC; void Draw(); Цитата ghRC:HGLRC; ghDC:HDC; procedure Draw; ghRC - указатель на контекст воспроизведения (Rendering Context) ghDC - дескриптор устройства (для нас - просто указатель на окно) Процедура Draw будет отвечать за рисование. Далее заполняем FormCreate: Код void __fastcall TForm1::FormCreate(TObject *Sender) { ghDC = GetDC(Handle); if (!bSetupPixelFormat(ghDC)) Close(); ghRC = wglCreateContext(ghDC); wglMakeCurrent(ghDC, ghRC); glClearColor(0.0, 0.0, 0.0, 0.0); FormResize(Sender); glEnable(GL_COLOR_MATERIAL); glEnable(GL_DEPTH_TEST); glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); float p[4]={3,3,3,1}, d[3]={-1,-1,-3}; glLightfv(GL_LIGHT0,GL_POSITION,p); glLightfv(GL_LIGHT0,GL_SPOT_DIRECTION,d); } Цитата procedure TForm1.FormCreate(Sender: TObject); var p: TGLArrayf4; d: TGLArrayf3; begin ghDC := GetDC(Handle); if bSetupPixelFormat(ghDC)=false then Close(); ghRC := wglCreateContext(ghDC); wglMakeCurrent(ghDC, ghRC); glClearColor(0.0, 0.0, 0.0, 0.0); FormResize(Sender); glEnable(GL_COLOR_MATERIAL); glEnable(GL_DEPTH_TEST); glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); p[0]:=3; p[1]:=3; p[2]:=3; p[3]:=1; d[0]:=-1; d[1]:=-1; d[2]:=-3; glLightfv(GL_LIGHT0,GL_POSITION,@p); glLightfv(GL_LIGHT0,GL_SPOT_DIRECTION,@d); end; Вы видите, что тут вызывается FromResize, который мы ещё не описали. Надо это исправить. Поместите туда следующий код: glViewport( 0, 0, Width, Height ); glMatrixMode( GL_PROJECTION ); glLoadIdentity(); glOrtho(-5,5, -5,5, 2,12); gluLookAt(0,0,5, 0,0,0, 0,1,0); glMatrixMode( GL_MODELVIEW ); Теперь, наверное, надо кое-что объяснить. glClearColor() устанавливает цвет (в нашем случае чёрный), которым будет заполняться экран при очищении. У этой процедуры - 4 параметра, что соответствует RGBA. Вместо нее можно написать glClearIndex(0.0) . Эта процедура устанавливает индекс цвета в палитре. glViewport() устанавливает область вывода - область, в которую OpenGL будет выводить изображение. В нашем случае - вся форма. glMatrixMode() устанавливает режим матрицы видового преобразования. Не забивайте ей себе голову, просто запомните, что, если вы меняете тип проецирования, положение или направление камеры, то параметр должен быть GL_PROJECTION. После того, как вы завершили свои изменения, вызовите эту процедуру с параметром GL_MODELVIEW. glLoadIdentity() заменяет текущую матрицу видового преобразования на единичную. glOrtho() устанавливает режим ортогонального (прямоугольного) проецирования. Это значит, что изображение будет рисоваться как в изометрии. 6 параметров типа GLdouble (или просто double): left, right, bottom, top, near, far определяют координаты соответственно левой, правой, нижней, верхней, ближней и дальней плоскостей отсечения, т.е. всё, что окажется за этими пределами, рисоваться не будет. На самом деле эта процедура просто устанавливает масштабы координатных осей. Для того чтобы установить перспективное проецирование, используются процедуры glFrustum() и gluPerspective(), но о них - потом. gluLookAt() устанавливает параметры камеры: первая тройка - её координаты, вторая - вектор направления, третья - направление оси Y. В OpenGL всё включается и выключается (разрешается и запрещается) процедурами glEnable() и glDisable(). Таким образом, мы разрешили тест глубины (GL_DEPTH_TEST), чтобы изображение было объёмным, разрешили давать нашим объектам какой-то цвет (GL_COLOR_MATERIAL), разрешили освещение (GL_LIGHTING) и включили "лампочку №0" (GL_LIGHT0). glLightfv() устанавливает свойства "лампочек": позицию и направление света. После того, как вы завершили работу с OpenGL, нужно освободить занятые ресурсы: освободить контекст, вызвав wglMakeCurrent с параметром ноль для идентификатора контекста OpenGL и разрушить этот контекст функцией wglDeleteContext. Кроме того нужно удалить дескриптор ghDC. Так как обычно работу с OpenGL завершается при завершении работы приложения, то соответствующий код нужно поместить в FormClose: Код void __fastcall TForm1::FormClose(TObject *Sender, TCloseAction &Action) { if(ghRC) { wglMakeCurrent(ghDC,0); wglDeleteContext(ghRC); } if(ghDC) ReleaseDC(Handle, ghDC); } Цитата procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction); begin if ghRC<>0 then begin wglMakeCurrent(ghDC,0); wglDeleteContext(ghRC); end; if ghDC<>0 then ReleaseDC(Handle, ghDC); end; А теперь, давайте уже что-нибудь нарисуем! Давайте нарисуем сферу, а потом заставим её крутиться. Итак, всё, что нам понадобится - это форма и таймер. Установите интервал таймера на 10 миллисекунд (нам этого будет вполне достаточно). Теперь скопируйте все представленные выше фрагменты кода в соответствующие места. В процедуре Timer1Timer напишите одну сточку: Draw(); (в Delphi без скобок). Теперь нам осталось только что-нибудь нарисовать, т.е. отредактировать функцию Draw. Код void TForm1::Draw() { glClear(GL_DEPTH_BUFFER_BIT xor GL_COLOR_BUFFER_BIT); GLUquadricObj *quadObj; quadObj:=gluNewQuadric(); gluQuadricDrawStyle(quadObj, GLU_FILL); glColor3f(1,0,0); gluSphere(quadObj, 2,10,10); glRotatef(3, 0,1,0); gluDeleteQuadric(quadObj); SwapBuffers(ghDC); } Цитата procedure TForm1.Draw; var quadObj :GLUquadricObj; begin glClear(GL_DEPTH_BUFFER_BIT xor GL_COLOR_BUFFER_BIT); quadObj:=gluNewQuadric; gluQuadricDrawStyle(quadObj, GLU_FILL); glColor3f(1,0,0); gluSphere(quadObj, 2,10,10); glRotatef(3, 0,1,0); gluDeleteQuadric(quadObj); SwapBuffers(ghDC); end; Всё, можно нажимать F9!!! А теперь кое-что поясню (в процедуре Draw не встретилось ни одной знакомой строчки ). glClear() сбрасывает значения всего перечисленного в качестве параметров (в нашем случае очищает буфер цвета и буфер глубины). Этой процедуре передавать много всяких буферов для очистки, но лично я использую только 3: GL_DEPTH_BUFFER_BIT, GL_COLOR_BUFFER_BIT, иногда GL_STENCIL_BUFFER_BIT (буфер трафарета). glColor() устанавливает цвет фигуры. Существует следующий синтаксис как для glColor, так и для других функций OpenGL: gl<name>[n][type] Поясняю, каждая функция OpenGL начинается с префикса "gl". Далее следует название функции. После названия - количество параметров (если функция определена для разного кол-ва параметров). И, наконец, переменными какого типа являются параметры: · b - GLbyte байт · s - GLshort короткое целое · i - GLint целое · f - GLfloat дробное · d - GLdouble дробное с двойной точностью · ub - GLubyte беззнаковый байт · us - GLushort беззнаковое короткое целое · ui - GLuint беззнаковое целое · v - вектор - массив из n элементов указанного типа Итак, glColor3f() означает, что цвет задаётся тремя компонентами типа GLfloat. Для рисования сферы мы используем механизм из glu32.dll. Создаём объект типа GLUquadricObj() и инициализируем его функцией gluNewQuadric(). Далее устанавливаем стиль фигуры функцией gluQuadricDrawStyle(quadObj, GLU_FILL). Стиль может быть GLU_FILL, GLU_LINE или GLU_POINT. Что каждый из них значит, проверьте сами. gluSphere() - делает из quadObj сферу. Три последних параметра - это радиус и количество разбиений поперёк и вдоль оси Z соответственно. Я взял маленькое число разбиений, чтобы было видно, что сфера крутится. И не забудем освободить память, занимаемую под quadObj - gluDeleteQuadric(quadObj). glRotatef() - заставляет нашу сферу крутиться. О том как, в следующей статье. И, наконец, SwapBuffers(ghDC) выводит всё на экран. Пока всё.
Прикрепленные файлы
-------------------- Не говори мне что мне делать и я не скажу куда тебе идти. |
|
|
January 16 2006, 19:51
Сообщение
#2
|
|
КМС Группа: Студенты Сообщений: 377 Регистрация: 24.11.2005 Из: ЧехоВ Пользователь №: 8 Реальное имя: Пластун Александр |
Напишите насколько быстро у Вас вращается объект в этой программе!
И напишите характеристики своих компов!
Прикрепленные файлы
-------------------- |
|
|
January 16 2006, 20:21
Сообщение
#3
|
|
Обладатель Нобелевской премии по ориентированию Группа: Админы сайта Сообщений: 1087 Регистрация: 23.11.2005 Из: Москва, Чертаново Пользователь №: 4 Skype: scorpion_mg Реальное имя: Виктор Учебная группа: выпускник! |
-полный оборот за секунды 3
-комп: PIV-1600 ОЗУ: 192 Мб HDD: 40 Гб Video: Nvidia GeForce MX 460 64 Мб + TV out + инет от Акадо + ИК-порт че еще надо? -------------------- |
|
|
January 16 2006, 21:30
Сообщение
#4
|
|
Жутко ленивый. Группа: Администраторы Сообщений: 2661 Регистрация: 22.11.2005 Из: Москва, Марьино Пользователь №: 1 Skype: dudnikov.v Реальное имя: Владимир |
число оборотом/сек >> 1
комп: AMD Sempron 2600+ 512 RAM DDR PC-3200 HDD - 80 Гб IDE Sapphire Radeon 9800 PRO Atlantis 128 Мб -------------------- Не говори мне что мне делать и я не скажу куда тебе идти. |
|
|
January 17 2006, 02:38
Сообщение
#5
|
|
Ученик дьявола Группа: Администраторы Сообщений: 606 Регистрация: 11.12.2005 Из: Ад Пользователь №: 22 Реальное имя: Владимир Учебная группа: каф. 3 |
Полный оборот ~2,5 сек
Комп: P4-2000 RAM-256 nVidia GeForce2 MX 100/200 MB: GigaByte -------------------- Shit happens . . . and very often!
Спирт помогает ориентированию на местности только в одном случае - когда в нём плавает стрелка компаса. (М. Веллер) Life take away from people SO MUCH time! The shortest distance between two points is under construction. |
|
|
January 25 2006, 02:33
Сообщение
#6
|
|
б.р. Группа: Активисты Сообщений: 22 Регистрация: 28.11.2005 Пользователь №: 13 Jabber:povitter@jabber.ru Реальное имя: Виктор |
Помоему у Виниамина со Скорпионом очень загруженные тачки.
У меня на: PIII 735 704 Mb RAM GF4 MX440 64MB ~3-5 Оборотов в секунду -------------------- Там, где в сети переходят на "вы", в реале уже бьют морду. ©
Админ спит, значит сервер стоит. ©Народная_Мудрость |
|
|
Текстовая версия | Сейчас: 28th April 2024 - 22:22 |