главная страница статьи файлы о сайте ссылки |
Георгий Мошкин Для загрузки и наложении текстур при использовании формата Half-Life smd достаточно лишь немного дополнить написанный ранее загрузчик 3D моделей (читайте здесь). Итак, воспользуемся утилитой mdldec.exe и распакуем модель RE_STARS_Jill.mdl: C:\models\jill>mdldec.exe RE_STARS_Jill.mdl В директории jill сразу появилось огромное количество smd файлов. Один из этих файлов содержит модель, а все остальные - скелетную анимацию. Поищем основной smd файл, в котором содержится модель. Обычно этот файл занимает больше всего места на диске. В данном случае это оказался файл c_marine.smd. Если мы заглянем внутрь этого файла, то увидим всё то же, что я описывал в статье про скелетную анимацию. Каждый треугольник модели описывается следующим образом: SM_4B.bmp Напомню смысл этих записей. В первой строчке стоит название текстуры, которая должна накладыватсья на этот треугольник - SM_4B.bmp. Следующие за ней три строки соответствуют трём вершинам треугольников. Например, в строчке 6 -9.572851 0.463093 21.991520 -0.698505 0.532904 0.477603 0.406000 0.383698 записаны следующие данные:
Нас здесь больше всего интересуют текстурные координаты U,V. Именно эти значения необходимо подавать в glTexCoord2f при выводе вершины в OpenGL. Как вы помните, в написанном ранее примере я уже сделал считывание текстурных координат и имени файла текстуры. Для этого были введены соответствующие типы хранения данных: type TPoligon=record и type TVershina=record Поэтому в самой программе у нас уже есть все необходимые данные для загрузки и наложения текстур на модель. Имя текстуры i-того полигона определяется через обращение к poligon[i].tekstura. Текстурные координаты j-той вершины i-того полигона определяются через обращение к записям poligon[i].vershini[j].textkoordinata[0] и poligon[i].vershini[j].textkoordinata[1]. Таким образом, все необходимые нам данные определяются так: имя текстуры:=poligon[i].tekstura Сделаем загрузку текстур. Так как разные полигоны имеют общие текстуры, то целесообразно сделать внешний массив для хранения идентификаторов OpenGL текстур: teksturi:array of GLUINT; В элементе k массива teksturi будет храниться идентификатор, подаваемый в glBindTexture: glBindTexture(GL_TEXTURE_2D, teksturi[k]); Но откуда мы узнаем, какой элемент массива teksturi необходим полигону i? То есть как мы определим число k по номеру полигона i? Для этого нужно дополнить тип TPoligon следующим образом (новая строчка выделена красным цветом): type TPoligon=record Теперь понятно, что при установке текущего номера текстуры мы будем подавать в OpenGL следующую команду: glBindTexture(GL_TEXTURE_2D, teksturi[poligon[i].teksGL]); Осталось только найти общие имена текстур, загрузить неповторяющиеся текстуры и установить соответствующие teksnomer для каждого полигона. В своё время я уже реализовывал это в версии загрузчика скелетной анимации для TMT Pascal, поэтому сделать это не составит большого труда. Итак, после загрузки модели (событие по кнопке "1.Загрузить модель и анимацию"), нам необходимо произвести некий анализ всех имён poligon[i].tekstura. Это необходимо сделать после строчки, в которой происходит загрузка модели: monster.zagruz('c_marine.smd'); Помимо общего списка идентификаторов текстур нам понадобятся их имена, поэтому добавим: imenatektur:array of STRING; В этих массивов одинаковое число элементов: teksturi:array of GLUINT; Для загрузки текстур будем использовать модуль BMP.PAS, который есть во многих демках на sulaco.co.za, поэтому в раздел USES добавляем модуль "bmp": uses BMP; Использование массивов, заданных выше, будет заключаться в следующем: LoadTexture(imenatekstur[j], teksturi[j]) Таким образом, мы загружаем текстуру с именем imenatekstur[j] и получаем число teksturi[j]: LoadTexture('текстура.bmp', идентификатор) Обратите внимание, что imenatekstur[j] задаём мы, а значение идентификатора teksturi[j] получаем после срабатывания функции LoadTexture. Выше мы дополнили тип TPolygon записью teksGL: type TPoligon=record В переменной teksGL будет храниться индекс нужного элемента массива teksturi. Использоваться teksGL будет так: glBindTexture(GL_TEXTURE_2D, teksturi[poligon[i].teksGL]); Вот как будет выглядеть дополненный процесс загрузки текстур: for i:=0 to length(monster.poligon)-1 do
- пройдёмся по всем полигонам for j:=0 to length(imenatekstur)-1 do
- пройдёмся по списку загруженных текстур if (nashli=false) then
- выше мы не нашли имя в списке - значит будем загружать k:=length(teksturi)-1; imenatekstur[k]:=monster.poligon[i].tekstura; end; Осталось сделать совсем немного - добавить команды OpenGL для наложения текстур. Для этого отыщем процедуру procedure TForm1.RenderModel. Вот она: procedure TForm1.RenderModel; for i:=0 to length(monster.poligon)-1 do glEnd; Для кнопок визуализации скелета добавляем glDisable(GL_TEXTURE_2D), а для отображения скелета - glEnable(GL_TEXTURE_2D). Сама процедура вывода модели с наложением текстур будет выглядеть следующим образом: var tekushtex:integer; // текущая текстура procedure TForm1.RenderModel;
if tekushtex<>monster.poligon[i].teksGL
then
Как видите, появилась команда glBindTexture и glTexCoord2f. Процедура glBindTexture служит для выбора текущей текстуры, а glTexCoord2f - для установки текстурной координаты. Стоит отметить, что вызывать glBindTexture можно только вне блока glBegin - glEnd. Так как вызов данной процедуры занимает определённое время, то для оптимизации я ввёл переменную tekushtex. Если ранее мы уже сделали вызов кода: glBindTexture(GL_TEXTURE_2D,teksturi[tekushtex]) то вызывать её вновь следует лишь в том случае, если у последующего треугольника номер текстуры не равен текущему: if tekushtex<>monster.poligon[i].teksGL then Такая оптимизация позволяет уменьшить время, затрачиваемое на вывод 3D модели. Оптимизация получается за счёт уменьшения количества вызовов glBindTexture и уменьшения количества блоков glBegin - glEnd. В заключении стоит отметить ещё несколько моментов: текстуры сконвертировал в формат 24bit BMP. Размеры текстур такие, чтобы не было проблем с OpenGL. Вместо mdldec можете использовать программу MilkShape3D (в меню там есть Decompile Half-Life MDL). |