
Код данной функции.
// сохраняем тек матрицу}
Gl.glPushMatrix();
// проходим циклом по всем под-объектам
for ( int l = 0; l <= count_limbs; l++)
{}int nom_index = limbs[l].GetTextureNom();
bool textureIsSet = false;if( nom_index > -1)
if (limbs[l].NeedTexture() && text_objects[nom_index] != null)
{
Gl.glEnable( Gl.GL_TEXTURE_2D); // включаем режим текстурирования}
// ID текстуры в памяти
uint nn = text_objects[limbs[l].GetTextureNom()].GetTextureObj();
// активируем (привязываем) эту текстуру
Gl.glBindTexture( Gl.GL_TEXTURE_2D, nn);
Gl.glEnable( Gl.GL_NORMALIZE);
// начинаем отрисовку полигонов
Gl.glBegin( Gl.GL_TRIANGLES);
// по всем полигонам
for ( int i = 0; i < limbs[l].VandF[1]; i++)
{// временные переменные, чтобы код был более понятен}
float x1, x2, x3, y1, y2, y3, z1, z2, z3 = 0;
// вытакскиваем координаты треугольника (полигона)
x1 = limbs[l].vert[0, limbs[l].face[0, i]];
x2 = limbs[l].vert[0, limbs[l].face[1, i]];
x3 = limbs[l].vert[0, limbs[l].face[2, i]];
y1 = limbs[l].vert[1, limbs[l].face[0, i]];
y2 = limbs[l].vert[1, limbs[l].face[1, i]];
y3 = limbs[l].vert[1, limbs[l].face[2, i]];
z1 = limbs[l].vert[2, limbs[l].face[0, i]];
z2 = limbs[l].vert[2, limbs[l].face[1, i]];
z3 = limbs[l].vert[2, limbs[l].face[2, i]];
// рассчитываем номраль
float n1 = (y2 - y1) * (z3 - z1) - (y3 - y1) * (z2 - z1);
float n2 = (z2 - z1) * (x3 - x1) - (z3 - z1) * (x2 - x1);
float n3 = (x2 - x1) * (y3 - y1) - (x3 - x1) * (y2 - y1);
// устанавливаем номраль
Gl.glNormal3f(n1, n2, n3);
// если установлена текстура
if(textureIsSet)
if (limbs[l].NeedTexture() && (limbs[l].t_vert != null) && (limbs[l].t_face != null))
{// устанавливаем текстурные координаты для каждой вершины, ну и сами вершины}
Gl.glTexCoord2f(limbs[l].t_vert[0, limbs[l].t_face[0, i]], limbs[l].t_vert[1, limbs[l].t_face[0, i]]);
Gl.glVertex3f(x1, y1, z1);
Gl.glTexCoord2f(limbs[l].t_vert[0, limbs[l].t_face[1, i]], limbs[l].t_vert[1, limbs[l].t_face[1, i]]);
Gl.glVertex3f(x2, y2, z2);
Gl.glTexCoord2f(limbs[l].t_vert[0, limbs[l].t_face[2, i]], limbs[l].t_vert[1, limbs[l].t_face[2, i]]);
Gl.glVertex3f(x3, y3, z3);
else // иначе - отрисовка только вершин
{Gl.glVertex3f(x1, y1, z1);}
Gl.glVertex3f(x2, y2, z2);
Gl.glVertex3f(x3, y3, z3);
// завершаем отрисовку
Gl.glEnd();
Gl.glDisable( Gl.GL_NORMALIZE);
// открлючаем текстурирование
Gl.glDisable( Gl.GL_TEXTURE_2D);
// возвращаем сохраненную ранее матрицу
Gl.glPopMatrix();
Так же рассмотрим код функции GetFirstWord, которая отвечает за получение первого слова в строке:
// from указывает на позицию, начиная с которой будет выполнятся чтение файла}
char a = word[from]; // первый символ
string res_buff = ""; // временный буффер
int L = word.Length; // длина слова
if (word[from] == ' ' || word[from] == ' ') // если первый символ, с которого предстоит искать слово является пробелом или знаком табуляции
{// необходимо вычисслить наличие секции проблеов или знаков табуляции и откинуть их}
int ax = 0;
// проходим до конца слова
for( ax = from; ax < L; ax++)
{a = word[ax];}
if( a != ' ' && a != ' ') // если встречаем символ пробела или табуляции
break ; // выходим из цикла.
// таким образом мы откидываем все последовательности пробелов или знаков табуляции, с которых могла начинатся переданная строка
if( ax == L) // если вся представленная строка является набором пробелов или знаков табуляции - возвращаем res_buff
return res_buff;
else
from = ax; // иначе сохраняем значение ax
int bx = 0;
// теперь, когда пробелы и табуляция откинуты мы непосредственно вычисляем слово
for (bx = from; bx < L; bx++)
{// если встретили знак пробела или табуляции - завершаем чтение слова}
if (word[bx] == ' ' || word[bx] == ' ')
break ;
// записываем символ в бременный буффер, постепенно получая таким образом слово
res_buff += word[bx];
// если дошли до конца строки
if (bx == L)
bx--; // убераем посл значение
GlobalStringFrom = bx; // позиция в данной строке, для чтения следующего слова в данной строке
return res_buff; // возвращаем слово
Функция, которая будет использоватся для вызова отрисовки модели из оболочки программы.
// если модель не загружена - возврат из функции}
if (!isLoad)
return ;
// сохраняем матрицу
Gl.glPushMatrix();
// масштабирование по умолчанию
Gl.glScalef(0.05f, 0.05f, 0.05f);
// вызов дисплейного списка
Gl.glCallList(thisList);
// возврат матрицы
Gl.glPopMatrix();
Изменения в коде оболочки.
Оболочка притерпела совсем назначительные изменения, которые сводятся к нескольким строкам кода для описания переменных класса, для загрузки 3D модели, выбора файла и ее отрисовки:
Должна быть объвлена переменная:
Функция Form1_Load
Отрисовка модели в функции Draw
Загрузка модели
if (openFileDialog1.ShowDialog() == DialogResult.OK)}
{Model = new anModelLoader();}
Model.LoadModel(openFileDialog1.FileName);
RenderTimer.Start();
Ну вот и все. На слудующих скриншотах, вы можете увидеть сцены в окне 3D Studio Max , затем сцены визуализированные после загрузки 3D модели из формата ASE.
Во втором примере вы можете увидеть что модель текстурирована.
По качеству она уступает визуализированной модели в 3D Studio Max – но это уже задача создания качественного рендера для вашего приложения (свойства материалов, освещение, сглажевание, различные шейдеры, что подымает уровень визуализации сцены и является уже совсем другой задачей).

Рисунок 4: сцена в окне 3D Studio Max.

Рисунок 5: сцена в окне программы после загруки:

Рисунок 6-а (модель вертолета в редакторе).

Рисунок 6-б (Сцена визуализированная в 3D studio Max (текстурированная модель вертолета)).

Рисунок 7. Сцена загруженная в программу
Исходный код этого урока - урок 13 загрузка трехмерных моделей в OpenGL (если вы используете x64 ОС, то после того, как вы открыли исходный код проекта - установите тип проекта - x86, как показанно на рисунке).
Обсуждение данного урока: Загрузка, текстурирование и визуализация 3D моделей в OpenGL. Формат ASE. Часть 2.