/*http://esate.ru, Anvi*/
// функция отрисовки
private void CreateList()
{
// сохраняем тек матрицу
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, которая отвечает за получение первого слова в строке:
/*http://esate.ru, Anvi*/
// функция получения первого слова строки
private string GetFirstWord( string word, int from)
{
// 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; // возвращаем слово
}
Функция, которая будет использоваться для вызова отрисовки модели из оболочки программы:
/*http://esate.ru, Anvi*/
// функция отрисовки 3D модели
public void DrawModel()
{
// если модель не загружена, возврат из функции
if (!isLoad)
return ;
// сохраняем матрицу
Gl.glPushMatrix();
// масштабирование по умолчанию
Gl.glScalef(0.05f, 0.05f, 0.05f);
// вызов дисплейного списка
Gl.glCallList(thisList);
// возврат матрицы
Gl.glPopMatrix();
}
Изменения в коде оболочки
Оболочка претерпела совсем незначительные изменения, которые сводятся к нескольким строкам кода для описания переменных класса и для загрузки 3D модели, выбора файла и ее отрисовки. Должна быть объявлена переменная:
/*http://esate.ru, Anvi*/
anModelLoader Model = null;
Функция Form1_Load:
/*http://esate.ru, Anvi*/
…
// опции для загрузки файла
openFileDialog1.Filter = "ase files (*.ase)|*.ase|All files (*.*)|*.*";
…
Отрисовка модели в функции Draw:
/*http://esate.ru, Anvi*/
…
if( Model != null)
Model.DrawModel();
…
Загрузка модели:
/*http://esate.ru, Anvi*/
// загрузка модели
private void выбратьФайлДляЗагрузкиToolStripMenuItem_Click( object sender, EventArgs e)
{
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-a. Модель вертолета в редакторе 3D Studio Max.
Рисунок 6-b. Текстурированная модель вертолета в редакторе 3D Studio Max.
Рисунок 7. Сцена, загруженная в программу.