Книги

OpenGL / FPC - Глава 17

Полагаю, что эта глава — наиболее ожидаемая. Она касается текстурного отображения. Текстура — то рисунок, который прикрепляется к поверхности (отображается на поверхность). При этом вам не потребуется сложно образованных поверхностей, просто нужно прикрепить на них рисунок. Число многоугольников, таким образом, довольно невелико. И конечно же: для наполнения вашей OpenGL сцены содержанием можно прикреплять фотографии, текст, и прочее.

Работать с текстурами в OpenGL на так сложно, как думают некоторые. Это сложно, но для того, чтоб начать, вам не нужно знать все тонкости и подробности. В этой главе мы просто нанесем очень простую сгенерированную текстуру на экран.

Текстура — это просто последовательность данных о пикселях — почти как растр. Давайте представим: указатель на некоторую область памяти. Сначала идет значение красного цвета для первого пикселя, затем — зеленого, а затем — синего цвета. После этого идет значение красного цвета для следующего пикселя и так далее. Конечно, это касается простой RGB текстуры, но суть — именно в этом.

Итак, имеется некоторая информация о рисунке. Как обычно, OpenGL требует идентификатор для этой текстуры. Мы attach этот id к нашей области памяти и говорим OpenGL использовать этот блок памяти всякий раз, когда мы активируем наш id. Так обстоят дела в теории. Посмотрим на код.

Сначала нам нужен id. Это — просто переменная типа GLuint. Определим также указатель на данные нашей текстуры.

  TextureID : GLuint;
  TextureData : pByte;

Во-первых, не забудьте выделить память для вашего указателя. Ее размер — ширина рисунка, умноженная на высоту, и помноженная на число байт, представляющих пиксель. Например, RGB нужно 3 байта на пиксель, RGBA — 4 байта, и так далее. Я буду использовать RGB текстуру размером 128x128.

  GetMem(TextureData, 128*128*3);

Теперь перейдем к командам OpenGL. Мы активируем текстурное отображение просто включив его. Затем указываем OpenGL зарезервировать для нас ID для одной текстуры и хранить его в TextureID.

  glEnable(GL_TEXTURE_2D);
  glGenTextures(1, TextureID);

Теперь мы активируем текстуру и привязываем наш указатель к активированному ID ( не путайте — для активирования используется glBindTexture, а glTexImage2D — для загрузки данных с указателя).

  glBindTexture(GL_TEXTURE_2D, TextureID);	// now use it

Теперь следует инициализировать нашу текстуру. Так мы настраиваем поведение нашей текстуры. Это важно! Не пропускайте этот шаг.

  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);

А теперь и идет собственно загрузка данных текстуры в OpenGL пространство.

  glTexImage2D(GL_TEXTURE_2D, 0, 3, 128, 128, 0, GL_RGB, GL_UNSIGNED_BYTE, TextureData^);

Мы должны задать тип данный пикселя, размер текстуры и порядок следования параметров пикселя. Например, это может быть GL_BGR и прочая. Если хотите их узнать, обратитесь к справочному руководству по api. Также задается указатель, по которому хранятся наши данные.

Перед тем, как продолжить, еще немного об OpenGL и размерах текстур. Текстура должна иметь размер 2^n. Это значит, что можно использовать текстуры вида 8*8, 16*16, 32*32, 64*64, 128*128 и так далее, но никак НЕ текстуры вида 640*480. Можно подумать "Что за вздор?!", но это так. Обычные текстуры имеют такое ограничение, с этим ничего не поделаешь. Конечно, есть способ использовать текстуры любого заданного размера, но это достигается другим способом. Я объясню это позже, хорошо? А сейчас поработаем с 2^n.

А все уже настроено. Теперь пора нарисовать поверхность и прикрепить к ней текстуру. Обычно работают с несколькими текстурами, так что вначале нужно связать с поверхностями ту текстуру, что мы намереваемся использовать.

  glBindTexture(GL_TEXTURE_2D, TextureID);

Далее, следует сказать OpenGL, как именно мы хотим прикрепить текстура к поверхности. Это достигается с помощью команды glTexCoord2f. Процедура рисования выглядит примерно так.

    glTexCoord2f(0.0, 0.0); glVertex3f(-1.0, -1.0,  1.0);
    glTexCoord2f(1.0, 0.0); glVertex3f( 1.0, -1.0,  1.0);
    glTexCoord2f(1.0, 1.0); glVertex3f( 1.0,  1.0,  1.0);
    glTexCoord2f(0.0, 1.0); glVertex3f(-1.0,  1.0,  1.0);

Посмотрите внимательно. glTexCoord2f определяет края текстуры и то, как они присоединяются к поверхности. 0 — это левый/верхний край, а 1 — правый/нижний. Если посмотреть на поверхность, левый/верхний край текстуры присоединяется к левому/верхнему краю поверхности. Если указать, скажем, значение 2, текстура будет нарисована 2 раза. Значение 0.5 будет означать, что будет нарисована только половина текстуры.

Вот, в основном, и все. Ничего не забыли? Ах, да — у нас же ничего нет по адресу, на который ссылается указатель. Там пусто! То есть его надо чем-то заполнить.

Если в качестве текстуры мы хотим использовать рисунок, его надо просто загрузить из файла. Битмапы загружать довольно легко, JPG и прочие форматы — немного сложнее. Можно также самим формировать что-нибудь и рисовать это в области текстуры. Такие сгенерированные текстуры (или математические текстуры, как их иногда называют) имеют большое преимущество в том, что они занимают мало места — каких-то насколько байт в алгоритме. Мы, однако, займемся ими в следующей главе. А теперь просто убедитесь, что вы все поняли.

Актуальные версии
FPC3.2.2release
Lazarus3.2release
MSE5.10.0release
fpGUI1.4.1release