13.3 Загрузка, текстурирование и визуализация 3D моделей в OpenGL. Формат ASE. Часть 2.

Код данной функции:
/*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, но это уже задача создания качественного рендера для вашего приложения (свойства материалов, освещение, сглаживание, различные шейдеры, что поднимает уровень визуализации сцены и является уже совсем другой задачей).
Уроки OpenGL + C#: Сцена в окне 3D Studio Max Рисунок 4. Сцена в окне 3D Studio Max.
Уроки OpenGL + C#: Сцена в окне программы после загрузки Рисунок 5. Сцена в окне программы после загрузки.
Уроки OpenGL + C#: Модель вертолета в редакторе 3D Studio Max Рисунок 6-a. Модель вертолета в редакторе 3D Studio Max.
Уроки OpenGL + C#: Текстурированная модель вертолета в редакторе 3D Studio Max Рисунок 6-b. Текстурированная модель вертолета в редакторе 3D Studio Max.
Уроки OpenGL + C#: Сцена, загруженная в программу Рисунок 7. Сцена, загруженная в программу.
Прикрепленные файлы для скачивания:

Нет доступа к просмотру комментариев.

^
Регистрация
Регистрируясь, вы принимаете правила сайта. Если вы не получили код подтв. регистрации - не забудьте проверить папку спам.
Логин*
Email*
Пароль*
Подтверждение пароля*
 
Логин*
Код*
 
×
Восстановление пароля
Пожалуйста, заполните поля, после чего вы получите код подтверждения на ваш Email. Если код не пришел в течении нескольких минут - проверьте папку спам.
Логин

или Email
Логин*
Код подтверждения*
Новый пароль*
Подтверждение пароля*
×
Авторизация
  • Используйте вашу учетную запись на Facebook.com для входа на сайт.
  • Используйте вашу учетную запись VKontakte для входа на сайт.
  • Используйте вашу учетную запись Google для входа на сайт.
Авторизуйтесь с помощью соц. сети или с помощью аккаунта на сайте:
×