Подробные примеры OpenGLГлава 1: Бредисловие (вместо педисловия) Привет всем (уважаемым читателям/телезрителям/"а также их родителям" и пр ;) Сразу хочу предупредить, что это моя первая статья, поэтому просьба не пинать меня ногами, никакого заме-е-ечательного Набоковского слога и живописных эпитетов вы тут не увидите :( Все выдержано в сухом "преподавательском" тоне без малейшего намека на "программерские" шутки про "юзеров", телепузиков, "Microsoft" и "г-на Била Гейтса" (а ровно и пауз на неопределенный срок фразой "я ушел бухать", так как я вовсе не "бухаю". Да да, не смейтесь, я спротЦмен ;) ) Разочаровавшись (многие уже потянулись к "Esc"/бутылке/соске) начнем собсен-н-но... Глава 2: Немного историиКак говорил товарищ Берлага, если приподнять завесу, то становится весьма очевидным что стандарт OpenGL разрабатывается фирмой Silicon Graphics (теперь SGI) с лета 1992 года. Этот программный интерфейс был во многом основан на библиотеке IRIS GL, поддерживаемой с 1982 года. Для развития нового интерфейса был организован консорциум The OpenGL Architecture Review Board (ARB). На данный момент OpenGL является стандартной библиотекой для всех 32 разрядных операционных систем (Unix, Mac, Windows). Ну и хватит на этом. В конце концов это вам не лезгинка, а твист... в смысле не "Большая Советская Энциклопедия". Глава 3: ИнструментарийСразу скажу что писать мы будем на ассемблере (вообще говоря, все следует писать на ассемблере ;) , а точнее на FlatAssembler (FASM) т.к. он очень быстрый, компактный, постоянно развивается и не отягощен всякими бредовыми конструкциями (типа assume/offset) других ассемблеров (типа TASM ;)... Распаковываем добро из скаченного архива "fasmw.zip" в какую-нибудь папку, и "усе готово шэф" ! Глава 4: Первое приложение (Simple)Я предполагаю что вы уже писали под Win32 хотя бы и "Hello world !" (если нет то почитайте какой-нибудь tutorial по этому поводу, благо, их в сети туева хуча расплодилась). Окинув взглядом прилагаемый "simple.asm" в папке "simple" вы заметили что в нем нету даже оконной процедуры... Ой фу-у-у-у ! Но не спешите закрывать fasmw.exe, это всего лишь следствие моих небольших "оптимизаций" (а иначе накой хрен нам писать на ассемблере, как не из извращенческих соображений оптимизации ?) Но обо всем по порядку... Надеюсь следующий код понятен всем ? (fasminc можно установить например так (в файле autoexec.nt для WinXP) "set fasminc=путь_к_папке_fasm") ;формат exe файла Для начала спрячем курсор, дабы некоторые "продвинутые" юзвери не начали тыкать им куда не попадя, пораниться ведь можно (Извращения начинаются, см. "push ebx" ) ;обнулим ebx. Т.к. он не изменяется API процедурами Для начала "урока рисования" нам нужно создать окно, а точнее его класс (и тут не без извращений ;) ) размером с экран. Можно, конечно, для начала изменить разрешение, а потом уже уверенно создавать окно с известным размером, но это будет слишком просто для нас (и долго) ;) Поэтому мы получим текущее разрешение экрана по X и Y (по Z пока не будем ;) ) и запихнем их в стек (перед этим забьем его нулями (ebx) это у нас будут другие параметры процедуры CreateWindowEx. Вообще многие функции подставляют вместо "0" (ebx) параметры "по умолчанию", этим, как говорит Microsoft, "интеллектуальным свойством" мы будем активно пользоваться во всех частях tutorial'а) Помним при этом что функции возвращают результат в "eax". Вообще, следите за стеком ! Это хоть и геморойно, но зато позволяет не сохранять кучу ненужных "промежуточных" результатов функций (вроде GetSystemMetrics). ;поместим в стек 4-е "0" для процедуры "CreateWindowEx" Тут мы используем полученное разрешение экрана (его берем уже из стека... а накой нам лишние переменные ?) чтобы найти его (экрана) AspectRatio (разрешающую способность, т.е. "max_x/max_y") Потом она нам еще пригодится ;вычислим соотношение разрешений экрана по горизонтали и вертикали По идее, для создания класса окна нам его нужно было бы с начала описать, зарегистрировать... В общем, скука ужасная (и еще байтов жрет кучу !) Вместо этого мы просто создадим окно с предопределенным классом, таких в винде множество, но мы выберем ну хотя бы класс "edit" (о чем красноречиво сообщает строка szClass) Помним о том что некоторые "недостающие" в invokе'е параметры мы уже положили в стек ;создадим окно размером с экран с предопределенным классом "edit" И так, окно мы создали. Если вы уже рисовали что-нибудь под Win32, то вы знаете что для этого нужно получить его "контекст", это делается довольно просто (так как контекст окна нам еще пригодится, мы сохраним его в одном из "неиспользуемых" (в функциях Win32 API) регистров (ebx,ebp,esi,edi) ) ;получим контекст окна Теперь нужно задать режим работы OpenGl'а, число бит на пиксель, режимы отображение и прочую белиберду (половину из которой мы оставляем нулевой (т.е. по умолчанию) ;инициализируем дескриптор формата У нас есть контекст окна, у нас есть пиксельный формат ! "Мы сделаем из тебя парень новую звезду"... Аннннн нет, для начала нам еще осталось преобразовать контекст окна в "нечто" понятное OpenGL'у (т.к OpenGL не должен знать что такое Windows, для этого используется специальная "windows-compliant" функция API wgl***) и еще сделать его "текущим" (т.е. рисовать будем в него) ;преобразуем контекст окна в контекст OpenGL Фууу-х-х-х-х ! Самое сложное позади ;) Винды остались не у дел, теперь "познакомимся", собственно, с простым и удобным OpenGL'ем ;) Говоря голосом ведущего "в мире животных", эта забавная зверушка тоже требует некоторой настройки параметров (ОПЯТЬ ?!) Дело в том что нам нужно включить "перспективные преобразования", проще говоря перспективу, она зависит от текущей разрешающей способности экрана (т.е. max_x/max_y) вот для этого то мы ее и вычисляли. Так как некоторые извращенческие функции OpenGL воспринимают только параметры типа Double (8 байт) то придется пихать их в стек макросом glCall (который использует макрос glPush) А шо делать ? У нас же Intel Все-таки :( Число 90.0 это требуемый "угол обзора" можно поставить его 45.0 или 60.0 как кому нравится. Числа 0.1 и 100.0 это координаты "отсекающих плоскостей", все, что находится между ними, будет отображено на экране. Остальное - обрезано. Надо заметить что многие функции API OpenGL (glRotate, glTransform и пр.) работают с "текущей матрицей", коих 3 (GL_MODELVIEW, GL_PROJECTION и GL_TEXTURE) поэтому чтобы преобразовать матрицу перспективы мы выбираем ее функцией glMatrixMode. ;выберем режим вычисления перспективных преобразований (наилучший) Ура, а вот и он, "основной цикл". В нем вы "пока" ;) не увидите навороченной демы от haujobb, просто очистка экрана и выход по Esc. Т.к. мы работаем в режиме "двойной буферизации" то рендеринг идет в дополнительный буфер, для отображения его на экране нужно вызвать функцию GDI32 "SwapBuffers". Дабы впоследствии (когда мы добавим сюда что-нибудь) все не вертелось с бешеной скоростью, добавим сюда еще и синхронизацию с таймером ;основной цикл Не забудем выйти и описать переменные ;) Обратите внимание как (как просто ! ;) ) в Fasm'е описывается импорт и ресурсы. ;выход из программы Ну, вот в принципе и все, в первом OpenGL приложении. Это, типа, был "template", дальше я буду добавлять только измененные части. Глава 4: Первый цветной треугольник (и тут негры ;) )Ну, покончив с пережитками Win32 программирования, откинувшись (и оттопырившись) на спинку стула, можно наконец приступить к OpenGL'у вплотную... Оказывается нарисовать на нем треугольник не просто, а, как говорится, очень просто ! Все что надо это задать его координаты. Для начала сообщим что мы хотим, собственно, рисовать треугольники (GL_TRIANGLES) т.е. каждые три точки определяют один треугольник (следующие три - уже другой) ;начало рисования треугольника Теперь задаем координаты его вершин и их цвет. Цвет представляет собой 3 float'а (красную, зеленую и синюю (чуть было не написал голубую ;) ) составляющие) о чем говорит постфикс функции "3f". Этими префиксами/постфиксами отличаются все функции OpenGL API (т.е. если надо задать еще и alpha-состовляющую - используем функцию glColor4f, если нужно задавать параметры в Double то 3d/4d или 3i/4i для Integer) То же самое относится и к функции glVertex3f (соответственно первый параметр - координата X, второй - Y, третий - Z) ;цвет 1-й вершины Все, нарисовались ! ;конец рисования треугольника Если все так и оставить, то мы ничего не увидим, т.к. треугольник будет лежать прямо в точке наблюдения, надо бы его отодвинуть. Но, так как мы будем делать это каждую итерацию цикла то наш треугольник будет все дальше и дальше отодвигаться от нас (проверьте это сами, удалив вызов glLoadIdentity) поэтому вначале мы будем "обнулять" матрицу изображения. ;обнулим текущую матрицу (матрицу изображения) Просто нарисованный треугольник ничем не говорит нам о своей "трехмерности", надо его для этого повращать. Делается это функцией glRotate которая вращает (умножает текущую матрицу на матрицу поворота) на угол [theta] вокруг векторов с координатами (0,0,0) и (второй параметр, третий параметр, четвертый параметр) соответственно. Угол мы будем увеличивать каждую итерацию цикла (т.к. матрица изображения "обнуляется") ;умножим матрицу изображения на матрицу поворота Вот и все ! И оч-ч-чень просто, по-моему... Глава 5: Да будет свет !Свет в OpenGL включается очень просто (как и многое другое) выключателем ;) т.е. функцией glEnable с параметром GL_LIGHTING (отключается соответственно функцией glDisable). Нужно еще включить еще и определенный источник GL_LIGHT* (номер источника). Мы не будем пока парить себе мозг разнообразными видами источников и их параметрами, включим для начала источник GL_LIGHT0 (для него параметры настроены по умолчанию) ;включим источник света GL_LIGHT0 (используя значения по умолчанию) Так как в этой главе мы будем рисовать объемную фигуру (кубик) то нужно еще включить режим отсечения не лицевых граней (а то все грани кубика будут рисоваться и перекрывать друг друга) т.е. z-буфер. Делается это опять же функцией glEnable. Цвет получившегося (освещенного) полигона зависит от свойств "материала" и только :( Чтобы правильно отображать его цвет нужно еще включить режим его отслеживания (GL_COLOR_MATERIAL). ;включим режим отсечения не лицевых граней (z-буфер) Для того чтобы использовать освещение, для каждой грани нужно определить нормаль. Делается это функцией glNormal3f, координата X, координата Y, координата Z ;начало рисования куба из 6 четырехугольников GL_QUADS Заметьте что мы вызываем glRotatef 3 раза, для придания траектории вращения большей random'ности Глава 5: ТекстурированиеДля пущего реализЬма напялим на наш кубик текстуру. Делается это тоже проще пареной репы. Для начала нужно ее (текстуру) нарисовать (можно выдрать откуда-то, главное помните, что ее размер должен быть степенью двойки (256*256*24bpp в примере) ;), и сохранить в формате "raw" (например Photoshop'ом или IrfanView) конечно размер полученного файла будет немаленьким, но проще потом exe-шник сжать UPX'ом чем париться с JPEG/TGA форматами... Затем подключим полученный файл в виде ресурса в resourse.inc fileres texture,'textures.raw' Далее ее нужно перевести в понятный OpenGL'у формат функцией glTexImage2D. GL_TEXTURE_2D говорит что текстура у нас 2-х мерная, следующий ноль (ebx) определяет mip-map уровень для нее (для ускорения текстурирования из текстуры можно предварительно сгенерировать несколько уменьшенных копий, но у нас пока только одна), 3-ка - это число компонент в цвете (у нас RGB, а может быть и1-а (R), 2-е (RA), 4-е (RGBA)), затем размерность текстуры по x и y соответственно (256*256), "0" (ebx) это толщина "рамки" вокруг текстуры, далее формат текстуры (RGB, RGB, RGB, ...), тип каждой компоненты (у нас байт) и, собственно, смещение в файле (texture+16). ;создадим 256x256x24bpp текстуру Теперь осталось определить еще некоторые параметры текстуры, такие как фильтры уменьшения/увеличения (GL_TEXTURE_MIN_FILTER/GL_TEXTURE_MAG_FILTER) (т.е. которые применяются когда текстура, соответственно, меньше/больше требуемой для текстурирования в данный момент времени) функцией glTexParameteri. Установим их в GL_LINEAR (лучшее качество, можно еще GL_NEAREST побыстрее, но похуже) ;установим фильтр текстуры при уменьшении (linear) Вообще говоря, нужно было предварительно выбрать ID текстуры (1 для первой текстуры, 2 для второй и т. д.) функцией glBindTexture, но т.к. у нас только одна, и вся работа идет с 1-ой текстурой (по умолчанию), то нам ничего не мешает этого не делать. ;выберем текстуру номер 1 Осталось только включить текстурирование функцией glEnable ;включим текстурирование Усе, однако OpenGL не знает как привязать координаты вершин объектов к текстурным координатам (за исключением автоматической генерации текстурных координат, но об этом позже) так что надо ей об этом сообщить функцией glTexCoord2f с двумя параметрами (для 2-х мерной текстуры) x и y координатами текстуры (они изменяются также как и все остальное в OpenGL - в относительных координатах от 0.0 до 1.0) ;нормаль 1-го четырехугольника В случае с несколькими текстурами, их выбор осуществляется, как я уже говорил, функцией glBindTexture. Глава 6: Alpha смешивание (blending) или шара продолжаетсяAlpha смешивание позволяет нам использовать эффекты прозрачности. Для этого нужно опять таки его просто включить функцией glEnable (вам даже не надо знать как оно работает ! Вот шара :) помучившись со своим дос-софтверным 3D движком можно вздохнуть спокойно ;) ), настроить его тип можно функцией glBlendFunc, параметры источника (что смешивается), параметры результата (с чем смешивается). Параметры зависят от требуемого результата. ;выберем режим работы альфа смешивания Чтобы было с чем смешивать, нужно отключить режим отсечения не лицевых граней (попросту z-буфер) функцией glDisable. ;выключим режим отсечения не лицевых граней (z-буфер) либо вообще его не включать (как у нас в примере). Глава 7: Туман (без лошади)А теперь "офигенно" сложный этап tutorial'а ;) Туман ! Делается даже сложней чем alpha смешивание ;) а именно: ;выберем режим работы тумана (экспоненциальный) И все ! Параметры я думаю говорят сами за себя... Так как "туманятся" только объекты, то для пущей выразительности окрашиваем остатки экрана под цвет тумана (непонятно почему разработчики OpenGL не предусмотрели для glClearColor вариант с постфиксом fv (передается указатель на массив из Float'ов). Режим "работы" тумана можно выбрать и другой (ну, например, с 9 до 6 вечера, без выходных ;) ) GL_EXP или GL_LINEAR, поэкспериментируйте... Глава 8: Outline шрифтыЗаценим теперь, какую "титаническую" работу проделала Microsoft (ну вот, а говорил, что не будет про них) в своем scream-saver'е "3D Text". Для начала привычные для шрифтов вызовы Win32 API: создаем объект типа (ти-и-ипа) "шрифт" (все значения оставляем на совести Windows), и даем установку (а-ля Кашпировский) для "рисования". ;создадим шрифт Дальше вступает в дело OpenGL: преобразовывает векторный (именно векторный ! Шрифт "System" преобразовать не удастся, а жаль) в так называемый список (с... что ?!), т.е. последовательность OpenGL команд описания графических примитивов (те что обычно задаются между glBegin, glEnd). Для этого используется функция wglUseFontOutlinesA (или ее unicode версия wglUseFontOutlinesW для символов с кодами больше 255) Получаем "outline font". Мы будем преобразовывать символы начиная с нулевого (ebx) по 255 (всего, значит, 256 символов), единица означает что используются полигоны, а не линии ("0"), "0.2" это толщина нашего шрифта, в ebp, если помните, сохранен контекст OpenGL. Для операций с несколькими (у нас - 256) списками нужно выбрать первый список (вообще-то его их нужно было сгенерировать функцией glGenLists, но за нас это делает OpenGL). Для этого используется функция glListBase. ;преобразуем символы от 0-го до 256-го Посмотрим на предыдущие примеры tutorial'а, и офигеем ;) Зачем было столько носиться с оптимизацией, если размер какой-то завшивленной 256*256*24bpp текстуры занимает целых 200 кило ? Это не есть хорошо, будем теперь генерить ее вручную ! Это не tutorial про генерацию текстур (читайте в "Hugi" про это), поэтому выберем простую "шумовую" текстуру, для этого неплохо подходят код нашей проги. Заюзаем его в качестве текстуры (хе-хе, вот это я понимаю, извращение). OpenGL, конечно, ничего не знает про координаты текстуры для "outline" шрифта, да и вклиниться в работу функции wglUseFontOutlines и "наследить" там вызовами glTexCoord2f будет сложно (для этого нужно юзать feedback буфер), так что просто предоставим заниматься этим самой OpenGL, включив автоматическую генерацию текстурных координат (да, да, вот где еще одна шара !). Причем выберем режим текстуры GL_SPHERE_MAP, который обычно используется в создании всяческих отражений (enironment mapping). ;создадим 16x16x32bpp текстуру используя Ндааа... Опять глава кончилась не успев начаться ;) Ах да, нужно еще написать какое-нибудь слово (желательно не из трех букв, хотя в OpenGL слава Богу еще не встроили Parental Lock ;) все-таки это не DirectX), для этого вызовем списки (хмм, с этим словом главное не описАться... ой) с номерами равными кодам желаемых букв (т.к. мы генерили символы от "0" до "255"). Делаем это функцией glCallLists. ;вызавем txtIntro_length элементов списка (шрифта) Ура ! Получилось довольно красиво (и, главное, всего на три кило). Можно даже забацать из этого какое-нибудь "Newschool scrolltro". Дерзайте. Глава 9: Motion blur и рендеринг в текстуруИ так, мы уже вплотную подобрались к алгоритмам используемым в демках. Т.к. OpenGL не позволяет (нормальным образом) получить доступ к видеопамяти, поэтому и алгоритмы эффектов здесь соответствующие - извращенческие. Так что обычным образом motion blur нам сделать не удастся, будем юзать "встроенную" возможность OpenGL blur'ить текстуры при их растягивании (ну да, нам даже не надо знать как работают motion blur фильтры !) Вкратце план довольно прост:
Все, т.к. альфа смешивание включено, то каждый раз смешивая текстуру с предыдущими сценами (с альфа компонентой меньше "1.0") и черный экран (с альфа компонентой "0.0"), она будет постепенно "исчезать". Так как мы будем рендерить все в пустую текстуру, то с начала нужно ее создать, делается это как и обычно: ;выберем текстуру номер 1 Заметьте, что кубик мы предварительно "компилируем" в список. ;создадим новый список cubeList Blur'ить мы будем не каждый раз, а только через 4 фрейма (иначе "хвост" будет слишком маленьким, да и тормознуто это). ;увеличим счетчик кадров blur'а С начала нужно установить окно размером blurSize*blurSize, и отрендерить туда нашу "сцену". ;установим окно вывода с Скопируем то что получилось в текстуру, функцией glCopyTexImage2D. GL_TEXTURE_2D показывает что текстура двухмерная, следующий ноль (ebx) - это mip-map уровень, затем координаты текстуры (0,0), ее размер (blurSize*blurSize), и размер границы ("0"). Очистим экран, и вернем OpenGL'ое окно обратно. ;выберем текстуру номер 1 Теперь как нам нарисовать четырехугольник точно размером с экран ? Ведь OpenGL'у плевать на пиксели, он оперирует какими-то "условными единицами" (зелеными, наверное ;) ). Для этого нам надо установить так называемую "Ортогональную (прямоугольную) проекцию" делается это не сложнее установки перспективной проекции: ;и умножим на матрицу ортогональной проекции Усе, рисуем нашу сцену четырехугольником (заметьте, что перспективную проекцию мы устанавливаем не функцией, а, просто, сохранив проекционную матрицу в стеке функцией glPushMatrix, и восстанавливаем ее функцией glPopMatrix) ;выберем текстуру номер 1 В принципе ничего сложного тут нет, все абсолютно "прозрачно", смотрите код и все поймете. Глава 10: Zoom blur
;подготовим структуру описывающую видеорежим, ее размер Обратите внимание на, уже набивший всем оскомину, "эффект" широкоформатной пленки (типа, фи-и-и-ильму, фи-и-и-ильму !), который кое-кто уже умудрился впарить даже в 256b intro. Т.к. я поубивал много лишних вызовов процедур (к примеру, glViewport нужно было бы вставить после инициализации), то прога потеряла некоторую долю логичности (а заодно и пару "килограмм"), но к 10 главе мы уже все стали "хавцами" в OpenGl'е, неправда ли ? ;установим окно вывода с координатами 0,77 Сам алгоритм, который очень похож на motion blur, состоит в следующем (неизмененные места оставлены специально):
Смотрим код: ;инициализируем максимальный радиус радиального blur'а Незабудем вернуть видеорежим обратно, для этого просто вызовем функцию "ChangeDisplaySettings(null,0)" ;вернем видеорежим обратно Вот и все ! Уже украли/обрили... Просто, но, черт возьми, эффЭктно (и впереди я, на белом верблюде). Так о чем это я ? Ага, пришло, наконец, время долгожданного прощания. Просьба не устраивать сцен и истерик ;) обнимемся как братья... Э-э-э-э, что там еще говорят ? Желаю счастья в личной жизни... Один маленький, но очень гордый птичка... Нет, не то... Типа, надобранич дитлохи, до зустричи (тут я прям прослезился, как все Хрюши, Степаши и тети Тани/Амаяки Акопяны, канала О.Р.Т., вместе взятые)... Приложение 1: Vertex arraysНе успев обрадоваться от вышеописанного расставания (сцена с рыдающими детьми: "Папа ! Папа ! На кого ты нас покинул ?!"). Люба, я вернулся (wmplayer.exe c:\windows\media\tada.wav). Ну "да-ра-гггие мАи" ну не мог же я выпустить вас "в люди" голыми, так сказать ! Так бы сейчас и писали glBegin'ами. Шо вы ? Это уже совсем не модно ! Щас "в Европе, а также в лучших домах Филадельфии" все поголовно юзают массивы вершин. Вообще то, массив вершин (vertex array) - это почти тоже самое, что и команды между glBegin/glEnd, только их выполняет сама карта, подставляя значения из нашего массива. Как нам уже известно, описывать приходится не только, собственно, вершины, но и нормали, текстурные координаты, цвет и пр., поэтому и массивы бывают разные. Однако, мы не будем мучить себя подключением всех массивов, скинем просто все в кучу функцией "glInterleavedArrays" (т.е. данные в массиве идут последовательно, сначала нормаль одной вершины, потом ее текстурные координаты, цвет и пр. затем сами координаты вершины. Затем тоже самое для следующей вершины и т.д.). Она принимает параметрами тип "сваленных в кучу" массивов, тут это GL_N3F_V3F, т.е. N3F - массив нормалей, по 3 float'а на нормаль и V3F - массив вершин, тоже из 3-х float'ов на вершину, так называемый "stride" - "расстояние" между данными для соседней вершины (у нас будет "0" (ebx) т.к. данные в массиве идут подряд), и ,наконец, ссылку на массив с данными (mdlSheep). Но glInterleavedArrays только подключает массивы на отображение, их еще нужно, собственно, отобразить. Делается это функциейй "glDrawArrays". Первый параметр - это тип используемых примитивов (GL_TRIANGLES), второй - это первый элемент массива (ebx=0, т.е. рисуем все элементы) и третий параметр - это общее число элементов... ;включим отображение массивов нормалей Дело за малым - осталось найти де взять этот массив ;) Можно, конечно, и ручками (как в следующем приложении), но я (для демонстрации "крутизны" массивов вершин) отконвертил модельку X-Wing'а (предварительно сохранив ее 3DStudio в формате "ASC"). Можно было вставить ее просто как переменную (mdlShip dd ...) но это б заняло полтора мегабайта ;) Так что пришлось вынести ее в отдельный файл, и скомпилить FASM'ом, в результате чего получился 600 Kb бинарник, который я засунул в ресурсы директивой "file". mdlShip file '..\resources\models\ship.bin' Обратите внимание как я "генерил" текстуру (так вот откуда Cпилберг спер терминатора T1000 ;)) взяв за основу только красные компоненты "пикселей" (а на деле опкоды... красные уже и сюда добрались...) "GL_LUMINANCE_ALPHA". Для придания текстуре яркости, я использовал специальный режим обработки bitmap'ов (о них в следующем приложении) т.е. здесь - текстуры: "glPixelTransferf" с параметром "GL_RED_SCALE" (множителем красной (нет, ну хоть в кавычках это слово пиши) компоненты) и значением "10.0". invoke glPixelTransferf,GL_RED_SCALE,10.0 Ну, теперь все быстренько на борьбу с кубиками и торами ! Рисуйте свои модельки и вперед. Помните только (неоднократно натыкался на такое "недопонимание") что массив индексов, это на самом деле массив индексов цветов в режимах с маленькой глубиной цвета (256 цветов и т.д.) а не массив индексов вершин (как в 3D моделях). Приложение 2: Битовые карты (ну там, тройка, семерка, туз...)Ну почему обязательно карты ? Есть много интересных и полезных спортивных игр ! Например литрбо... оуэ-э-э-э битмап шрифты ! Еще бы, как же иначе мы напишем в нашу демку кучу псевдо-философского бреда, и причем непременно (непреме-е-енно !) "разъежающейся-блендещайся" Tahoma'ой... После главы про outlined шрифты, здесь уже все прозаично. Как обычно "создадим" шрифт: ;создадим шрифт (размером "9", остальные значения по умолчанию "0" Теперь, по анологии с outlined шрифтами, преобразуем все это в список команд рисования битмап'ов функцией "wglUseFontBitmaps(контекст OpenGL (ebp),первый символ (ebx),число символов (256),список (берем 0-й))" : ;преобразуем символы от 0-го до 256-го в список битмап'ов Установим ортогональную проекцию (для битмап'ов работать в ней удобнее). Вот тут начинается самое интересное... Будем делать "Матрицу" ! Ну, ту самую, что "has Neo...". Надеюсь ему понравилось, но мы за него ОТОМСТИМ ! Вощ-щ-щем расклад такой:
Надеюсь вы что-нибудь поняли... Если нет, то смотрите код, там понятней. Вообще-то это была задумка написать "город" а-ля в "Матрице", отсюда и кубик, но меня потом в конец обломало :( Пишите сами, в общем. На том и сказке/тьюториалу конец (делу венец и т.п.) а кто слушал #$%&@# !!! |