Формат 3d studio mesh, взгляд изнутри
О себе.
Что здесь написать… ну мало что изменилось с момента написания прошлого урока. Разве что только то, что я поступил в Иркутский Гос. Тех. Университет, факультет кибернетики, на специальность Автоматизированные системы управления (на программиста короче:)). И я еще сильнее полюбил gamedeveloping… |
Формат 3d studio mesh, взгляд изнутри.
Или как загружать модели из файлов 3ds в программу.
Введение.
Я с этого лета изучаю С++ и OpenGl (точнее в С++ я только повышал навыки))... уже столько информации впитал жуть). Причиной тому послужило то, что я пришел к выводу, что нельзя написать нормальную игру, не вникая в процесс программирования полностью. Вообще поначалу сложно было, но сейчас уже стало легче...
Ооочень большой проблемой стало нахождение обучений на русском языке, в Интернете, да и на полках книжных (... И дело не совсем в том, что книг на данную тему нет, они, безусловно, есть, но в целом везде содержание схоже, дается базис. Самой сильной проблемой (как я потом выяснил по форумам, чатам, сайтам) это является загрузка моделей из файлов, в OpenGl нет встроенных команд для этого, все вводится вручную...
Вот, например так описывается куб, состоящий из 6 граней, которые мы и описываем, причем заметьте – только точки, но есть ведь еще столько же – координаты текстур, координаты фейсов (faces coordinats):
glVertex3f( 0.0f, 1.0f, 0.0f); |
А если у нас модель хотя бы на 2000 verticles? ;)
Вначале заинтересовали текстовые форматы, их ведь можно легко редактировать, да и читать как-то проще)... Но это потеря времени, ресурсов... И пришел я к 3ds (3d Studio Mesh) , один из самых распространенных форматов хранения 3d сцен, казалось бы, идеальное решение?) это как бы сразу объединение с 3дмаксом... но не тут то было, инфы очень мало, да и на английском она, везде только вопросы как, да нет ответов (компания Autodesk долгое время не выпускала руководства и, потому его пробовали создать отдельные разработчики… да, и последнее такое руководство датировано … 1998 годом! Все же официальное руководство появилось, но такое ощущение, что только чтоб отвязались), хотя примеры в не достаточно полезные, это бесспорно)...
В данном уроке предполагается базовое владение программированием, на C++ или Delphi (в примерах к уроку я использовал С++ для создания программы, где для вывода изображения использовал OpenGL, так как в данной графической библиотеке проблема стоит наиболее остро).
Примечания: в конце урока будет изложено то, как настроить компиляторы C++ на работу с OpenGl, я не привожу эту информацию в начале, так как это не цель урока. Там же приведены ссылки на полезные ресурсы сети, посвященные данной тематике и файлы к уроку.
Итак, настало сказать пока нашему дорогому кубу ( или чайнику) ! :) Стандартно в OGL (OpenGl) нет встроенных возможностей загрузки файлов, иначе говоря, нам предлагается либо написать его самому, либо вводить все координаты вручную, а когда речь идет о тысячах точек (verticles) это просто безумно...
Цели урока:
- Понять то, как устроен формат 3d Studio Mesh.
- Научиться считывать информацию, содержащуюся в файлах формата 3ds и использовать ее.
Содержание:
- Знакомство с 3d Studio Mesh.
- Разработка простого приложения. Чтение модели (текстуры, геометрия)
- Подробнее о KEYFRAMER CHUNK. Подробности по хранению анимации.
- Иерархия объектов.
- Как легче узнать какие параметры надо прочитать?
- Как настроить компилятор для работы с OpenGL.
- Ссылки.
- Файлы к уроку.
Знакомимся с 3ds.
В общих чертах мы можем сказать, что 3ds файл содержит полную информацию о 3d сцене, содержащей один или более объектов. Если мы откроем файл в блокноте, что мы увидим? – ничего… лишь перемешанный текст, это потому, что все записано в шестнадцатеричном коде(hexademetrical). Внутреннее же строение файла представляет собой серии блоков называемых на английском – Chunk (кусок или участок памяти, я же буду писать: объект Chunk или просто Chunk). Что же содержится в этих блоках? Все нужное для описания сцены: имена объектов, координаты вершин (vertices coordinates), координаты наложения текстур (mapping coordinates), ключи анимации (animation keyframes) и прочее ...
У объекта chunk нелинейная структура, это значит что элементы, находящиеся по структуре внутри других, читаются только после того, как будут прочитаны (будет получен к ним доступ) элементы их содержащие. Структура имеет вид дерева, такую структуру можно наблюдать на локальных дисках компьютера. Конечно же, необязательно читать все объекты, достаточно прочитать только самые важные.
Каждый chunk состоит из 4 записей:
-Identifier: это число, записанное в шестнадцатеричном формате, размером 2 байта, идентифицирующее chunk. С этой информацией мы можем немедленно узнать, нужен ли он нам. Если нам нужен chunk, мы открываем собранную в нем информацию, если нужно, в его child-элементе (элементы, находящиеся по иерархии внутри данного), однако если он бесполезен, мы пропускаем его, используя следующий параметр…
-Lengthofthechunk: еще одно число, на этот раз размером 4 байта, содержит сумму длины chunk’а и его длинны child-элементов.
-Chunkdata: это поле может иметь разную длину. Реально хранимая информация содержится здесь.
В данной таблице представлена зависимость ветвления и размера в объектах chunk:
|
Иерархия и код наиболее полезных chunk’ов в файле:
MAIN CHUNK 0x4D4D
3D EDITOR CHUNK 0x3D3D
OBJECT BLOCK 0x4000
TRIANGULAR MESH 0x4100
VERTICES LIST 0x4110
FACES DESCRIPTION 0x4120
FACES MATERIAL 0x4130
MAPPING COORDINATES LIST 0x4140
SMOOTHING GROUP LIST 0x4150
LOCAL COORDINATES SYSTEM 0x4160
LIGHT 0x4600
SPOTLIGHT 0x4610
CAMERA 0x4700
MATERIAL BLOCK 0xAFFF
MATERIAL NAME 0xA000
AMBIENT COLOR 0xA010
DIFFUSE COLOR 0xA020
SPECULAR COLOR 0xA030
TEXTURE MAP 1 0xA200
BUMP MAP 0xA230
REFLECTION MAP 0xA220
[SUB CHUNKS FOR EACH MAP]
MAPPING FILENAME 0xA300
MAPPING PARAMETERS 0xA351
KEYFRAMER CHUNK 0xB000 - об особенностях и иерархии данной ветви мы поговорим позже
Важно не забывать при чтении определенного chunk’а, нужно вначале прочитать его отцов (элементов стоящих выше по иерархии). Например, для прочтения chunk’а VERTICES LIST мы должны прочитать MAIN CHUNK, 3D EDITOR CHUNK, OBJECT BLOCK и, наконец, TRIANGULAR MESH. Другие объекты, конечно, могут быть пропущены…
Так же хочу отметить, что в том случае если нам надо прочитать более одного объекта, тогда учитывая то, что создание идет через struct, мы прочитать OBJECTBLOCK еще раз и создать новый объект, используя структуру. Ориентироваться в том, что за объект нам выдал chunk можно по имени прочитанного объекта, как только имя повторилось, идем дальше, так же нужно не забывать проверять, что мы читаем, чтобы не прочитать свет, камеры, когда нам нужен mesh. В своем примере я читаю один объект.
Я предлагаю отбросить некоторые объекты в древе и оставить только ветви с информацией: "vertices", "faces", "mapping coordinates", и их отцов по дереву. Эти объекты мы используем в начальном примере:
MAIN CHUNK 0x4D4D
3D EDITOR CHUNK 0x3D3D
OBJECT BLOCK 0x4000
TRIANGULAR MESH 0x4100
VERTICES LIST 0x4110
FACES DESCRIPTION 0x4120
MAPPING COORDINATES LIST 0x4140
Таблица с более подробным описанием каждого chunk’а:
MAIN CHUNK | |
Identifier | 0x4D4D |
Length | 0 + Sub-chunks length |
Chunk father | None |
Sub chunks | 3D EDITOR CHUNK |
Data | None |
3D EDITOR CHUNK | |
Identifier | 0x3D3D |
Length | 0 + sub-chunks length |
Chunk father | MAIN CHUNK |
Sub chunks | OBJECT BLOCK, MATERIAL BLOCK, KEYFRAMER CHUNK |
Data | None |
OBJECT BLOCK | |
Identifier | 0x4000 |
Length | Object name length + sub-chunks length |
Chunk father | 3D EDITOR CHUNK |
Sub chunks | TRIANGULAR MESH, LIGHT, CAMERA |
Data | Object name |
TRIANGULAR MESH | |
Identifier | 0x4100 |
Length | 0 + sub-chunks length |
Chunk father | TRIANGULAR MESH |
Sub chunks | None |
Data | Vertices number (unsigned short) Vertices list: x1,y1,z1,x2,y2,z2 etc. (for each vertex: 3*float) |
FACES DESCRIPTION | |
Identifier | 0x4120 |
Length | varying + sub-chunks length |
Chunk father | TRIANGULAR MESH |
Sub chunks | FACES MATERIAL |
Data | Polygons number (unsigned short) Polygons list: a1,b1,c1,a2,b2,c2 etc. (for each point: 3*unsigned short) Face flag: face options, sides visibility etc. (unsigned short) |
MAPPING COORDINATES LIST | |
Identifier | 0x4140 |
Length | varying + sub-chunks length |
Chunk father | TRIANGULAR MESH |
Sub chunks | SMOOTHING GROUP LIST |
Data | Vertices number (unsigned short) Mapping coordinates list: u1,v1,u2,v2 etc. (for each vertex: 2*float) |
VERTICES LIST | |
Identifier | 0x4110 |
Length | varying |
Chunk father | TRIANGULAR MESH |
Sub chunks | None |
Data | Vertices number (unsigned short) Vertices list: x1,y1,z1,x2,y2,z2 etc. (for each vertex: 3*float) |
Разработка простого приложения.
В моем примере мы сможем считывать только один объект из файла! (то, как это исправить будет описано в следующей главе.
Итак, для начала берем файл – заготовку, содержащий объявление всех структур OpenGl (template01.zip). Я не буду останавливаться на разъяснении устройства программы, это вы сможете понять и по комментариям.
В принципе мы могли бы хранить все типы в главном исходном коде (main.cpp) программы, но лучшим решением будет расположить их в заголовочном файле (header file, main.h).
#define MAX_VERTICES 8000
#define MAX_POLYGONS 8000
Мы должны указать максимальное количество точек и полигонов, которое будит поддерживать наше приложение.
Теперь мы должны создать файл 3dsLoader.cpp (здесь и будет выполняться загрузка модели). Сюда мы вводим:
char Load3DS (obj_type_ptr p_object, char *p_filename)
{
int i;
FILE *l_file;
unsigned short l_chunk_id;
unsigned int l_chunk_length;
unsigned char l_char;
unsigned short l_qty;
unsigned short l_face_flags;
В Load3DS как параметры передаются указатель на объект структуры данных и имя файла, который надо открыть. Возвращает «0» если файл не найден, если файл найден и прочитан то «1». На самом деле для инициализации нам требуется не так уж и много переменных: счетчик i, указатель на файл *l_file и дополнительная переменная l_char для экстраполяции данных в байт формате.
Остальные переменные:
-unsignedshortl_chunk_id: идентификатор chunk’а, шестнадцатеричное значение в 2 байта.
-unsigned int l_chunk_length: длинна chunk’а, 4 байта.
-unsignedshortl_qty: дополнительный параметр, будет полезен для получения информации о параметрах читаемой информации.
-unsignedshortl_face_flags: запоминает некоторую информацию относительно текущего полигона (видим, не видим и прочее), полезен только 3d редакторов сцены, в нашем случае мы не будем с ним работать, но будем его считывать, чтобы переместиться на следующий chunk. Итак, наконец, откроем файл:
if ((l_file=fopen (p_filename, "rb"))== NULL) return 0; //Open the file
while (ftell (l_file) < filelength (fileno (l_file))) //Loop to scan the whole file
{
while здесь цикл, для прохождения по всему файлу. Функция ftell позволяет нам запрашивать позицию, а filelength возвращает значение длины файла.
fread (&l_chunk_id, 2, 1, l_file); //Read the chunk header
fread (&l_chunk_length, 4, 1, l_file); //Read the length of the chunk
Мы экстраполировали идентификатор и длину chunk’а и сохранили их в in l_chunk_id и l_chunk_length
Теперь мы должны проанализировать и использовать содержимое id:
switch (l_chunk_id)
{
case 0x4d4d:
break;
Итак, мы нашли MAINCHUNK! Замечательно!) Что же мы теперь будем делать? А ничего. По сути, он не содержит данных, нам интересны его под объекты. Если бы мы не включили его в case, мы бы его перепрыгнули! Почему? Об этом позже… А сейчас только скажем, что произойдет, если мы перепрыгнем корневой объект? Правильно, мы окажемся в конце файла… нам это надо?... нет:)
Теперь мы точно так же поступаем с the 3D EDITOR CHUNK, в нем так же нет данных. Так что давайте просто его прочитаем =) и он отправит нас к своим child-элементу… Object Block!
case 0x3d3d:
break;
Итак это Object Block, этот chunk содержит интересную информацию: имя объекта, хранимое в поле name в структуре объекта. Выход их структуры while будет по нахождению знака ’\0’ или количестве знаков бол 20. Но будьте осторожны! Мы прочитали все данные этого chunk’а, это дат нам возможность перейти на следующий.
case 0x4000:
i=0;
do
{
fread (&l_char, 1, 1, l_file);
p_object->name[i]=l_char;
i++;
}while(l_char != '\0' && i<20);
break;
И еще одна пустая ветвь, дающая доступ к chunk’ам, которые нам надо прочитать.
case 0x4100:
break;
Итак это точки (vertices)! VERTICES LIST содержит все точки объекта, для начала мы читаем значение "quantity", затем создаем цикл for, чтобы прочитать все точки. Сохраняем всю информацию внутри структуры object (она описана в заголовочном файле к main.cpp).
case 0x4110:
fread (&l_qty, sizeof (unsigned short), 1, l_file);
p_object->vertices_qty = l_qty;
printf("Number of vertices: %d\n",l_qty);
for (i=0; i<l_qty; i++)
{
fread (&p_object->vertex[i].x, sizeof(float), 1, l_file);
fread (&p_object->vertex[i].y, sizeof(float), 1, l_file);
fread (&p_object->vertex[i].z, sizeof(float), 1, l_file);
}
break;
FACESDESCRIPTION содержит перечень полигонов объекта. Чтение схоже с предыдущим.
Каждый face содержит дополнительно второе поле, содержащее информацию для 3d редакторов (видимые стороны и прочее). Мы, конечно, читаем и их, но лишь для передвижения далее…
case 0x4120:
fread (&l_qty, sizeof (unsigned short), 1, l_file);
p_object->polygons_qty = l_qty;
printf("Number of polygons: %d\n",l_qty);
for (i=0; i<l_qty; i++)
{
fread (&p_object->polygon[i].a, sizeof (unsigned short), 1, l_file);
fread (&p_object->polygon[i].b, sizeof (unsigned short), 1, l_file);
fread (&p_object->polygon[i].c, sizeof (unsigned short), 1, l_file);
fread (&l_face_flags, sizeof (unsigned short), 1, l_file);
}
break;
Последним в данном примере мы читаем MAPPING COORDINATES LIST, так же как обычно вначале читаем quantity, затемлист координат, только теперь одна очко будет иметь 2 координаты, так как наложение идет в двумерном пространстве, U и V, припоминается?)
case 0x4140:
fread (&l_qty, sizeof (unsigned short), 1, l_file);
for (i=0; i<l_qty; i++)
{
fread (&p_object->mapcoord[i].u, sizeof (float), 1, l_file);
fread (&p_object->mapcoord[i].v, sizeof (float), 1, l_file);
}
break;
Замечательно! Case – default! Это значит, что на этом рутинная работа закончена, когда у нас на пути chunks, которые нам читать не нужно нам поможет функция fseek, используя информацию из chunk_length, она переводит нас на начало следующего chunk.
default:
fseek(l_file, l_chunk_length-6, SEEK_CUR);
}
}
На этом и конец этого примера. Правда осталась только одна мелочь: давайте закроем файл и возвратим 1!
fclose (l_file); // Closes the file stream
return (1); // Returns ok
}
И вот наша модель из 3дМакса попала в наше приложение!
Весь пример вы можете скачать по ссылке в конце урока. В нем так же в отдельный модуль выделена загрузка текстур, для удобства. (прим.: Данный пример основывается на примере взятом на www.spacesimulator.net)
Подробнее о KEYFRAMER CHUNK.
Эту информацию найти было особенно сложно
…Таблица с подробным описанием каждого chunk’а относящегося к анимации:
KEYFRAMER | |
Identifier (идентификатор) | 0xB000 |
Уровень в иерархии | 1 |
Length (длинна) | 0 + sub-chunks length |
Chunk father (элемент родитель) | None |
Sub chunks (ветви) | |
Data, descripion | Данные кейфреймера служат для описания движения по сцене объектов (например – куба:)), источников света и камер. |
INFORMATION BLOCK | |
Identifier (идентификатор) | 0xB001 ... 0xB007 |
Уровень в иерархии | 2 |
Length (длинна) | Варьируется, зависит от ветвей |
Chunk father (элемент родитель) | 0xB000 (Keyframer chunk) |
Sub chunks (ветви) | |
Data, descripion | Этот блок содержит ветви описывающие движение каждого отдельного объекта, камеры, источника света. 0xB001 : Ambient light information block 0xB002 : Mesh information block 0xB003 : Camera information block 0xB004 : Camera target information block 0xB005 : Omni light information block 0xB006 : Spot light target information block 0xB007 : Spot light information block |
FRAMES (START, END) | |
Identifier (идентификатор) | 0xB008 |
Уровень в иерархии | 2 |
Length (длинна) | 8 |
Chunk father (элемент родитель) | 0xB000 (Keyframer chunk) |
Sub chunks (ветви) | |
Data, descripion | Состоит из двух записей: dword Start, End. Думаю его значение понятно. |
OBJECT NAME, PARAMETERS AND HIERARCHY FATHER | |
Identifier (идентификатор) | 0xB010 |
Уровень в иерархии | 3 |
Length (длинна) | Варьируется, зависит от ветвей |
Chunk father (элемент родитель) | 0xB001..0xB007 Information block |
Sub chunks (ветви) | |
Data, descripion | Состоит из следующих записей: strz Object Name word Flag1 * Bit 11 : Hidden word Flag2 * Bit 0 : Show path * Bit 1 : Animate smoothing * Bit 4 : Object motion blur * Bit 6 : Morph materials word Hierarchy father, link to the parent object (-1 for none) * подробности по иерархии подтаблицей |
OBJECT PIVOT POINT | |
Identifier (идентификатор) | 0xB013 |
Уровень в иерархии | 3 |
Length (длинна) | 12 |
Chunk father (элемент родитель) | 0xB001...0xB007 Information block |
Sub chunks (ветви) | |
Data, descripion | Содержит одну запись в векторном виде: Vector Pivot point |
TRACK | |
Identifier (идентификатор) | 0xB020 ... 0xB029 |
Уровень в иерархии | 3 |
Length (длинна) | Варьируется, зависит от ветвей |
Chunk father (элемент родитель) | 0xB001..0xB007 Information block |
Sub chunks (ветви) | |
Data, descripion | Содержит множества записей: word Flag * Bits 0-1 : 0 = single 2 = repeat 3 = loop * Bit 3 : lock X * Bit 4 : lock Y * Bit 5 : lock Z * Bit 7 : unlink X * Bit 8 : unlink Y * Bit 9 : unlink Z dword Number of keys in this track Then, for each key: dword Key number (position in track) word Acceleration data present (flag) Range: * Bit 0 : Tension follows [-1.0, 1.0] * Bit 1 : Continuity follows [-1.0, 1.0] * Bit 2 : Bias follows [-1.0, 1.0] * Bit 3 : Ease to follows [ 0.0, 1.0] * Bit 4 : Ease from follows [ 0.0, 1.0] n floats Acceleration data ? Track specific data Track specific data is: 0xB020 : Position track : 1 vector Position 0xB021 : Rotation track : 1 float Angle (rad) 1 vector Axis 0xB022 : Scale track : 3 floats Size 0xB023 : FOV track : 1 float Angle (degree) 0xB024 : Roll track : 1 float Angle (degree) 0xB025 : Color track : 0xB026 : Morph track : 1 strz Object name 0xB027 : Hotspot track : 1 float Angle (degree) 0xB028 : Falloff track : 1 float Angle (degree) 0xB029 : Hide track : nothing |
HIERARCHY POSITION | |
Identifier (идентификатор) | 0xB030 |
Уровень в иерархии | 3 |
Length (длинна) | 2 |
Chunk father (элемент родитель) | 0xB001 ... 0xB007 Information block |
Sub chunks (ветви) | |
Data, descripion | word HierarchyПодробнее об иерархии далее, в отдельной главе. |
Информация далеко не полная, подробнее об этом можно узнать из доков sdk или споcобом, который я опишу немного позже.
Иерархия объектов.
Иерархия объектов схожа с иерархией chunk`ов, то же самое дерево… но не всегда. Каждому объекту в сцене дается номер, чтобы идентифицировать его номер в иерархии. Каждый объект созданный в файле будет и в дереве иерархии. Корневому элементу дается номер «-1»(ffff). При чтении файла сохраняется номер объекта. Если он увеличивается, будет идти работа с дочерним элементом, уменьшится – мы перешли на родительский элемент.
Для примера того, как иерархия представляется, используем файл 50pman.3ds (он есть среди файлов к уроку), его по каким то причинам, по традиции используют для описания этого момента еще с момента появления формата 3ds.
Hierarchy | object name -1 pelvis |
|
Для просмотра древа объектов 3ДМаксе есть Schematic View (Graph Editors->New Schematic View). Собственно в нем же и можно ее изменять. (можно поставить background image - картинку редактируемой модели и расставить все части по картинке)
Schematic View для 50pman.3ds
Для того чтобы понять то почему нумерация имеет именно такой порядок нужно представить саму модель, структура здесь имеет не стандартный вид дерева, потому что главный элемент логически помещен в центр.
Использование иерархии может быть полезно, когда мы должны объединить несколько объектов в структуру, а то как они должны зависеть друг от друга читать из файла.
Как легче узнать какие параметры надо прочитать?
В уроке я не привожу примера с чтением анимации, но взамен (чтобы вы не расстраивались:)) привожу пример, который есть в sdk от autodesk.
Для начала скачайте sdk по ссылке в конце урока. Он подготовлен для работы в MSVC++, но прочитать исходники я думаю, не составит труда тем, у кого ее нет.
Запустим MAKEREL.BAT, это установит пути к директориям sdk. (Чтобы это отменить запустите CLEAN.BAT)
В папке DUMP3DS находится пример, консольное приложение, которое читает 3ds файл и выводит в консоль информацию обо всех chunk`ах, которые подверглись изменению. (Теперь, например мы можем легко узнать какие chunk`и изменяются при добавлении анимации, карт и прочее…) В папке INC содержится заголовочный файл, в котором объявляются все chunk`и, и структуры для их обработки.
Вообще в sdk есть интересные документы, которые еще больше могут углубить ваши знания:
3DSFTK3.DOC – содержит информацию о программе приведенной Autodesk, спецификацию всех функций, структур, переменных. Тут все довольно понятно.
3DSFTK3.DOC – информация о том как устроен формат 3ds. Здесь все довольно непонятно :)
3DSFTK3B.DOC – все о анимации. Имеет довольно странную структуру, но полезного тут много.
Как настроить компилятор для работы с OpenGL.
Многие спорят что лучше, компилятор Microsoft или Borland? Мне кажется, это так же глупо, как и спорить на эту тему о 3DMax или Maya… Мне кажется, что важное отличие первого компилятора в том, что для него больше примеров :).
В архиве GL.rar лежит папка GL и Glut32.lib.
Если:
1.У нас Borland C++ Builder:
Папку копируем в - …/Builder root/include/
2.MSVC++ (для полноценной работы, нужна версия не ниже 6)
Папку копируем в - …/Builder root/include/ . Glut32.lib копируем в -- …/Builder root/lib/
Для запуска программ могут понадобиться dll-библиотеки GLUT, это расширение OGl функций, лежит в glutdlls37beta.rar, dll нужно скопировать в …/windows/system32/.
Ссылки:
http://www.opengl.org/ - официальный сайт OpenGL, на нем можно найти много полезных ссылок.
http://www.images.autodesk.com/adsk/files/3dsftk3.zip - официальный sdk по 3ds от Autodesk.
http://www.gamedev.net/reference/
http://www.opengl.gamedev.ru/ – хорошие примеры по работе с ogl.
http://www.nehe.gamedev.net/ - прекрасные примеры, советую всем, но они на английском…
http://www.opengl.org.ru/ – целая онлайн книга по ogl. Так же можно найти много интересного, например библиотеки, руководства.
http://www.spacesimulator.net/ - игровой проект на ogl. На сайте есть немного уроков.
Советую найти OpenGL Red Book (русская версия) – 475 страниц! Это отличный учебник по OpenGL, к сожалению сайт на котором я ее брал уже не работает, но я думаю поиском пользоваться все умеют:)
И еще интересные демки, часто с исходниками, можно найти на сайте NVidia…
Файлы к уроку:
CrolLesson.rar – содержит:
/example/ - программа с исходниками, приведенная здесь, мной в качестве примера
/for_include/ - glutdlls37beta.rar и GL.rar.
Послесловие.
На этом мой урок подошел завершению, я постарался, как можно полнее изложить тему. Обе цели поставленные вначале урока считаю достигнутыми. Надеюсь, вам было интересно!
Спасибо за внимание, оставляйте свои комментарии и голосуйте. Удачи вам в ваших проектах по 3d графике!
Если оставляете критику, пожалуйста, обосновывайте, мне же важно знать, что не так…
По возникающим вопросам обращайтесь на tony89@yandex.ru, я постараюсь всем отвечать.