12.2 Текстурирование в openGl - библиотека DevIL (OpenIL).

Необходимые знания:
Вам могут понадобится следующие статьи:

Разработка программы начинается с создания оболочки

Создайте окно программы и разместите на ней элемент openglsimplecontrol, как показано на рисунке 1, после чего установите его размеры 500х500. Переименуйте данный объект, дав ему имя AnT.
Уроки OpenGL + C#: Окно создаваемой программы Рисунок 1. Окно создаваемой программы.
Также не забудьте установить ссылки на используемые библиотеки Tao (рис. 2). Обратите внимание на ссылку на Tao.DevIL - данная библиотека необходима нам для загрузки текстур (и не забудьте using Tao.DevIl; иначе вы не сможете работать с данной библиотекой) .
Уроки OpenGL + C#: Подключение библиотек Tao Рисунок 2. Подключение библиотек Tao.
Для реализации визуализации будет использоваться таймер – после инициализации окна он будет генерировать событие, называемое тиком таймера раз в 30 миллисекунд. Добавьте элемент таймер, переименуйте экземпляр в RenderTimer и установите время тика 30 миллисекунд (как показано на рисунке 3), а также добавьте ему событие для обработки тика.
Уроки OpenGL + C#: Настройка таймера Рисунок 3. Настройка таймера.
Также необходимо добавить меню для выбора файлов. Для этого добавьте новое меню на форму, объект openFileDialog. В свойствах объекта openFileDialog установите параметр Filter равным «JPG files|*.jpg|All files|*.*».
Уроки OpenGL + C#: Создание меню Рисунок 4. Создание меню.
Инициализация OpenGl происходит как обычно, следует отметить только дополнительную инициализация библиотеки openIL. Нам потребуется объявить ряд переменных для дальнейшей работы программы:

/*http://esate.ru, Anvi*/

// ряд вспомогательных переменных
// поворот
private int rot = 0;
// флаг - загружена ли текстура
private bool textureIsLoad = false;

// имя текстуры
public string texture_name = "";
// идентификатор текстуры
public int imageId = 0;

// текстурный объект
public uint mGlTextureObject = 0;

// событие загрузки формы 
private void Form1_Load( object sender, EventArgs e)
{

  // инициализация библиотеки glut 
  Glut.glutInit();
  // инициализация режима экрана 
  Glut.glutInitDisplayMode( Glut.GLUT_RGB | Glut.GLUT_DOUBLE);

  // инициализация библиотеки openIL 
  Il.ilInit();
  Il.ilEnable( Il.IL_ORIGIN_SET);

  // установка цвета очистки экрана (RGBA) 
  Gl.glClearColor(255, 255, 255, 1);

  // установка порта вывода 
  Gl.glViewport(0, 0, AnT.Width, AnT.Height);

  // активация проекционной матрицы 
  Gl.glMatrixMode( Gl.GL_PROJECTION);
  // очистка матрицы 
  Gl.glLoadIdentity();

  // установка перспективы 
  Glu.gluPerspective(30, AnT.Width / AnT.Height, 1, 100);

  // установка объектно-видовой матрицы 
  Gl.glMatrixMode( Gl.GL_MODELVIEW);
  Gl.glLoadIdentity();

  // начальные настройки OpenGL 
  Gl.glEnable( Gl.GL_DEPTH_TEST);
  Gl.glEnable( Gl.GL_LIGHTING);
  Gl.glEnable( Gl.GL_LIGHT0);

  // активация таймера 
  RenderTimer.Start();

}


Теперь рассмотрим процесс загрузки текстуры. Для этого мы реализуем две функции – первая выполняется как обработка события активации меню, размещенного на нашей форме. Получив имя текстуры мы проведем начальную подготовку к загрузке текстуры в память графического адаптера. В дальнейшем мы выполним дополнительные настройки текстуры, после которых сразу же увидим результат.

/*http://esate.ru, Anvi*/


// обработка пункта меню загрузки изображения 
private void loadImageToolStripMenuItem_Click( object sender, EventArgs e)
{

  // открываем окно выбора файла 
  DialogResult res = openFileDialog1.ShowDialog(); // если файл выбран - и возвращен результат OK 
  if (res == DialogResult.OK)
  {
    // создаем изображение с идентификатором imageId 
    Il.ilGenImages(1, out imageId);
    // делаем изображение текущим 
    Il.ilBindImage(imageId);

    // адрес изображения полученный с помощью окна выбора файла 
    string url = openFileDialog1.FileName;

      // пробуем загрузить изображение 
      if ( Il.ilLoadImage(url))
      { 
      
      // если загрузка прошла успешно 
      // сохраняем размеры изображения 
      int width = Il.ilGetInteger( Il.IL_IMAGE_WIDTH);
      int height = Il.ilGetInteger( Il.IL_IMAGE_HEIGHT);

      // определяем число бит на пиксель 
      int bitspp = Il.ilGetInteger( Il.IL_IMAGE_BITS_PER_PIXEL);

      switch (bitspp) // в зависимости от полученного результата 
      {
        // создаем текстуру, используя режим GL_RGB или GL_RGBA 
        case 24:
        mGlTextureObject = MakeGlTexture( Gl.GL_RGB, Il.ilGetData(), width, height);
        break ;
        case 32:
        mGlTextureObject = MakeGlTexture( Gl.GL_RGBA, Il.ilGetData(), width, height);
        break ;
      }

      // активируем флаг, сигнализирующий загрузку текстуры 
      textureIsLoad = true ;
      // очищаем память 
      Il.ilDeleteImages(1, ref imageId);

      }

  }

}

// создание текстуры в памяти openGL 
private static uint MakeGlTexture( int Format, IntPtr pixels, int w, int h)
{
  // идентификатор текстурного объекта 
  uint texObject;

  // генерируем текстурный объект 
  Gl.glGenTextures(1, out texObject);

  // устанавливаем режим упаковки пикселей 
  Gl.glPixelStorei( Gl.GL_UNPACK_ALIGNMENT, 1);

  // создаем привязку к только что созданной текстуре 
  Gl.glBindTexture( Gl.GL_TEXTURE_2D, texObject);

  // устанавливаем режим фильтрации и повторения текстуры 
  Gl.glTexParameteri( Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_WRAP_S, Gl.GL_REPEAT);
  Gl.glTexParameteri( Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_WRAP_T, Gl.GL_REPEAT);
  Gl.glTexParameteri( Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_MAG_FILTER, Gl.GL_LINEAR);
  Gl.glTexParameteri( Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_MIN_FILTER, Gl.GL_LINEAR);
  Gl.glTexEnvf( Gl.GL_TEXTURE_ENV, Gl.GL_TEXTURE_ENV_MODE, Gl.GL_REPLACE);

  // создаем RGB или RGBA текстуру 
  switch (Format)
  { 
    case Gl.GL_RGB:
    Gl.glTexImage2D( Gl.GL_TEXTURE_2D, 0, Gl.GL_RGB, w, h, 0, Gl.GL_RGB, Gl.GL_UNSIGNED_BYTE, pixels);
    break;

    case Gl.GL_RGBA:
    Gl.glTexImage2D( Gl.GL_TEXTURE_2D, 0, Gl.GL_RGBA, w, h, 0, Gl.GL_RGBA, Gl.GL_UNSIGNED_BYTE, pixels);
    break;
  }

  // возвращаем идентификатор текстурного объекта 
  return texObject;
}


Теперь остается обработать событие отклика таймера и реализовать функцию визуализации сцены. При визуализации текстуры нам необходимо включить режим текстурирования, а также при выводе вершин объектов привязывать к ним текстурные координаты, в соответствии с которыми произойдет наложение текстуры.

/*http://esate.ru, Anvi*/


// отклик таймера 
private void RenderTimer_Tick( object sender, EventArgs e)
{
  // вызов функции отрисовки сцены 
  Draw();
} 

// функция отрисовки 
private void Draw()
{ 
  // если текстура загружена 
  if (textureIsLoad)
  { 
    // увеличиваем угол поворота 
    rot++;
    // корректируем угол 
    if (rot > 360)
      rot = 0;

    // очистка буфера цвета и буфера глубины 
    Gl.glClear( Gl.GL_COLOR_BUFFER_BIT | Gl.GL_DEPTH_BUFFER_BIT);
    Gl.glClearColor(255, 255, 255, 1);
    // очищение текущей матрицы 
    Gl.glLoadIdentity();

    // включаем режим текстурирования 
    Gl.glEnable( Gl.GL_TEXTURE_2D);
    // включаем режим текстурирования, указывая идентификатор mGlTextureObject 
    Gl.glBindTexture( Gl.GL_TEXTURE_2D, mGlTextureObject);

    // сохраняем состояние матрицы 
    Gl.glPushMatrix();

    // выполняем перемещение для более наглядного представления сцены 
    Gl.glTranslated(0, -1, -5);
    // реализуем поворот объекта 
    Gl.glRotated(rot, 0, 1, 0);

    // отрисовываем полигон 
    Gl.glBegin( Gl.GL_QUADS);

    // указываем поочередно вершины и текстурные координаты 
    Gl.glVertex3d(1, 1, 0);
    Gl.glTexCoord2f(0, 0);
    Gl.glVertex3d(1, 0, 0);
    Gl.glTexCoord2f(1, 0);
    Gl.glVertex3d(0, 0, 0);
    Gl.glTexCoord2f(1, 1);
    Gl.glVertex3d(0, 1, 0);
    Gl.glTexCoord2f(0, 1);

    // завершаем отрисовку 
    Gl.glEnd();

    // возвращаем матрицу 
    Gl.glPopMatrix();
    // отключаем режим текстурирования 
    Gl.glDisable( Gl.GL_TEXTURE_2D);

    // обновляем элемент со сценой 
    AnT.Invalidate();
  }

}


Результат работы программы - вращающаяся плоскость с изображением текстуры.
Уроки OpenGL + C#: Результат работы программы Рисунок 5. Результат работы программы.

Примечания

В случае возникновения ошибки: Unable to find an entry point named 'ilInit' in DLL 'DevIL.dll'. или подобных:
  • Перейдите: Мой компьютер -> Свойства -> Дополнительные параметры системы -> Переменные среды...
  • В списках системных переменных выберите Path, нажмите «Изменить...»
  • Поставьте в конце    ;    (точку с запятой) и затем добавь путь к TaoFramework\bin, например, C:\Program Files (x86)\TaoFramework\bin;, а также к TaoFramework\lib (путь полностью).
Прикрепленные файлы для скачивания:
Добавить комментарий
Расширенный режим добавления комментариев доступен на форуме: загрузка изображений, цитирование, форматирование текста, и т.д.
Ваше имя:
Текст сообщения:
Комментарии (20):
mike124
mike124,  
В статье отсутствуют объявления переменных
mike124
mike124,  
Цитата
Теперь рассмотрим процесс загрузки текстуры и создания файла.
Про создание файла нет ни слова.

У меня загрузились только очень маленькие файлы, причем сам я такие создать не смог - скачал из Интернета. Также, хорошо работают иконки.
Anvi
Anvi,  
Проверял на 2448х3264 (JPG), текстура загрузилась и отобразилась.

Остальные ошибки исправлены, спасибо.
admin
admin,  
Сообщение пользователя constX7 перенесено в отдельную тему
roman
roman,  
Даже после исправления переменной Path

Additional information: Не удается загрузить DLL "DevIL.dll": Не найден указанный модуль.

Что еще можно сделать?
noname
noname,  
Привет
Цитата
roman написал:
Даже после исправления переменной Path
Additional information: Не удается загрузить DLL "DevIL.dll": Не найден указанный модуль.
Что еще можно сделать?
После исправления Path перезагружали компьютер?
К уроку прикреплены исходные коды с проектом. Если их компилировать, то тоже не работает?
Тип проекта в configuration manager - x86 стоит (http://esate.ru/blogs/noname/oshibka-pri-kompilyatsii-badimageformatexception-0x8007000B/)?
Если положить файл DevIL.dll в папку с проектом / в папку debug к исполняемому файлу?
roman
roman,  
Цитата
После исправления Path перезагружали компьютер? К уроку прикреплены исходные коды с проектом. Если их компилировать, то тоже не работает?
действительно, после перезагрузки заработало. спасибо за совет! :good:
программа-урок запускалась и раньше, но когда загружал текстурку, вылетала. теперь все заработало
Leonardo
Leonardo,  
[img]file:///C:/Users/Leonid/Desktop/TaoError1.png[/img]Ребята, привет!

Подскажите плиз ,как мне ошибку обойти?
У меня WIn7 64, VisualStudio2012, в настройках проекта указано x86.

Как обойти ошибку?

Спасибо!
noname
noname,  
Цитата
Leonardo написал:
Подскажите плиз ,как мне ошибку обойти?
У меня WIn7 64, VisualStudio2012, в настройках проекта указано x86.

Как обойти ошибку?

Спасибо!
А пример из архива у вас запускается (к уроку приложен архив с проектом)?
Вы установили ссылки на библиотеки, как написано в начале урока?

В коде Form1.cs у вас прописано using Tao.DevIl;?
Код
using Tao.OpenGl;
using Tao.FreeGlut;
using Tao.Platform.Windows;

using Tao.DevIl;
Leonardo
Leonardo,  
Цитата
noname написал:
Цитата
Leonardo написал:
Подскажите плиз ,как мне ошибку обойти?
У меня WIn7 64, VisualStudio2012, в настройках проекта указано x86.

Как обойти ошибку?

Спасибо!
А пример из архива у вас запускается (к уроку приложен архив с проектом)?
Вы установили ссылки на библиотеки, как написано в начале урока?

В коде Form1.cs у вас прописано using Tao.DevIl; ?
Код
 using Tao.OpenGl;
using Tao.FreeGlut;
using Tao.Platform.Windows;

using Tao.DevIl; 

Пример из архива выдает ту же самую ошибку!

using Tao.DevIl я прописал
noname
noname,  
А другие проекты у вас запускались?

Может дело в файлах, которые вы пытаетесь загрузить, или в значении url?
Другие вызовы функций Il. до этого вызова ведь не приводят к ошибкам.
Leonardo
Leonardo,  
Проект с визуализацией сферы запустился!

На счет других функций Il - я не пробовал. Посоветуете что сделать?
Il инициализируется же нормально.
noname
noname,  
Цитата
На счет других функций Il - я не пробовал. Посоветуете что сделать?
Il инициализируется же нормально.
Я скачал архив, приложенный к этому уроку и запустил (VS 2015). Все запустилось корректно.
Проверяйте все по шагам:
- установлен tao framework? примечания выполнены (из http://esate.ru/uroki/OpenGL/uroki-OpenGL-c-sharp/initsializatsiya-opengl-v-c-sharp/ и след урока)?
- путь к библиотекам прописан в path (из примечания к этому уроку), перезагрузку выполняли после установки path?
- смотрели отладчиком, что у вас в url в момент ошибки? корректен ли путь?
- если url корректен, файл доступен, пробовали менять файлы? в каком формате и какого размера использовался тестовый файл?
PeTa
PeTa,  
Добрый день! Такая же ошибка - An unhandled exception of type 'System.AccessViolationException' occurred in Textures.exe
ation: Попытка чтения или записи в защищенную память. Это часто свидетельствует о том, что другая память повреждена.
Прописаны все библиотеки:

using Tao.OpenGl;
using Tao.FreeGlut;
using Tao.Platform.Windows;
using Tao.DevIl;
и DevIL.dll скопирован в папку Debug проекта... в чем проблема может быть?
noname
noname,  
Цитата
PeTa написал:
Добрый день! Такая же ошибка - An unhandled exception of type 'System.AccessViolationException' occurred in Textures.exe
ation: Попытка чтения или записи в защищенную память. Это часто свидетельствует о том, что другая память повреждена.
Прописаны все библиотеки:

using Tao.OpenGl;
using Tao.FreeGlut;
using Tao.Platform.Windows;
using Tao.DevIl;
и DevIL.dll скопирован в папку Debug проекта... в чем проблема может быть?
Привет
Проверьте, что у вас тип проекта x86 установлен (http://esate.ru/blogs/noname/oshibka-pri-kompilyatsii-badimageformatexception-0x8007000B/).
Проекты, приложенные к уроку запускаются нормально?

ну и как в комментарии выше - проверяйте все по шагам (комментарий №14)
PeTa
PeTa,  
Да, х86 установлено изначально, думается это беда с библиотекой. Проект запускается, ошибка появляется только после OpenFileDialog,
string url =openFileDialog1.FileName;
if (Il.ilLoadImage(url))
скорее всего проблема с url,при попытке вручную присвоить string url = "D:/2.jpg"; - все равно ошибка.
У меня WIn7 64, VisualStudio2015, в настройках проекта указано x86.
noname
noname,  
Цитата
PeTa написал:
Да, х86 установлено изначально, думается это беда с библиотекой. Проект запускается, ошибка появляется только после OpenFileDialog,
string url =openFileDialog1.FileName;
if (Il.ilLoadImage(url))
скорее всего проблема с url,при попытке вручную присвоить string url = "D:/2.jpg"; - все равно ошибка.
У меня WIn7 64, VisualStudio2015, в настройках проекта указано x86.
если попробовать изменить файл, его разрешение, формат. попробовать простой файл 512х512 пикселей?
у вас свой проект, или вы пытаетесь запустить проект, приложенный к уроку?
PeTa
PeTa,  
Проект и свой, и тот что приложен к курсу - одна и та же ошибка. Вот ссылка на них + текстуры http://hdd.tomsk.ru/desk/czsxxbbk может кто найдет в чем причина
noname
noname,  
Цитата
PeTa написал:
Проект и свой, и тот что приложен к курсу - одна и та же ошибка
Сейчас скачал и запустил проект, приложенный к уроку - все норм. VS 2015.
Проверяйте наличие библиотек, что прописана переменная path (после установки значений в нее должна быть перезагрузка)

У вас прописаны переменные среды, как написано в конце этого урока? Затем была перезагрузка?
http://esate.ru/uroki/OpenGL/uroki-OpenGL-c-sharp/teksturirovanie-opengl-devil/

Program Files (x86)\TaoFramework\lib\DevIL.dll
скопирована в \Windows\System32\?
PeTa
PeTa,  
По итогу - после копирования не только в System32, но и в Windows dll- заработало! Путь был прописан, библиотеки добавлены в Debug и не работало. Не дело это, слишком уж много танцев с бубном... За помощь СПАСИБО!
^