Полагаю, что эта глава — наиболее ожидаемая. Она касается текстурного отображения. Текстура — то рисунок, который прикрепляется к поверхности (отображается на поверхность). При этом вам не потребуется сложно образованных поверхностей, просто нужно прикрепить на них рисунок. Число многоугольников, таким образом, довольно невелико. И конечно же: для наполнения вашей 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 и прочие форматы — немного сложнее. Можно также самим формировать что-нибудь и рисовать это в области текстуры. Такие сгенерированные текстуры (или математические текстуры, как их иногда называют) имеют большое преимущество в том, что они занимают мало места — каких-то насколько байт в алгоритме. Мы, однако, займемся ими в следующей главе. А теперь просто убедитесь, что вы все поняли.
FPC | 3.2.2 | release |
Lazarus | 3.2 | release |
MSE | 5.10.0 | release |
fpGUI | 1.4.1 | release |