Экспорт из Blender в разработке игр.
главная страница статьи файлы о сайте ссылки
Экспорт из Blender в разработке игр
Делаем скрипт экспорта

Георгий Мошкин
tmtlib@narod.ru

Оглавление.

файлы по теме:

blender2006.zip (546 kb) - 3d модель, исходники экспортера для Blender и загрузчика на Delphi + exe
blender2006noexe.zip (351 kb) - всё то же, но без exe

Займёмся экспортом нашей модели. Для этого нужно написать простенький скрипт на языке Python, который записывает модель в текстовый файл по нашим правилам. Для написания скрипта вы можете использовать встроенный в Blender текстовый редактор. Для этого создайте окно (как создавать окго см. часть 1, шаг 12) и установите его тип (как установить нужный "Window type" см. часть 1, шаг 13) на "Text Editor".

1. Скрипт для Blender необходимо начинать с заголовочной части:

#!BPY

"""
Name: 'Nash format...'
Blender: 241
Group: 'Export'
Tooltip: 'Nash format...'
"""

В смомом начале следует обязательная строчка #!BPY, которая даёт Blender-у понять, что это скрипт в правильном формате (Blender Python script).
Name - текст, который будет добавлен в меню экспортеров Blender-а. По соседству с "Export to 3D Studio..., Export to MD2..., Export to VRML" и др. форматами появится пункт меню с "Nash format...".
Blender - минимальная версия Blender, на которой можно запускать скрипт (я поставил завышенные требования - число 241, соответствующее новой версии 2.41)
Group - к какой группе добавить скрипт
Tooltip - текст всплывающей подсказки

Обратите внимание на строчки с трёмя двойными кавычками (""") - их добавлять обязательно, как это показано выше.

 

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

__author__ = ["Georgy Moshkin"]
__url__ = ("http://www.tmtlib.narod.ru")
__version__ = "1.0"
__bpydoc__ = """\

Etot skript zapisivaet scenu v nash format. Prosto zapustite skript.

"""

__author__ - список авторов скрипта. Авторы записываются в кавычках через запятую (например: ["автор1","автор2","автор3"]).
__url__ - ссылка на домашнюю страницу скрипта, если кто-нибудь захочет поинтересоваться новой версией
__version__ - версия скрипта
__bpydoc__ - документация к скрипту (записывается между "тройными" кавычками)

 

3. Теперь следует подключить необходимые модули.

import Blender

После команды import стоит список из подключаемых модулей. Мы подключили только один модуль - Blender.

 

4. Создадим диалог, который позволит пользователю выбрать имя файла для записи. Эту строчку нужно добавить в самый конец исходника скрипта:

Blender.Window.FileSelector(my_export, "Export v nash format")

my_export - это название функции, которой будет передано выбранное пользователем имя файла.
"Export v nash format" - это текст, который будет написан на кнопке записи (save).
Как только пользователь нажмёт на кнопку Save, произойдёт вызов функции my_export.

 

5. Приступим к написанию функции, отвечающий за экспорт сцены в файл. Это функция my_export:

def my_export(filename):
myfile = open(filename, 'w')
... здесь будет алгоритм экспорта ...
myfile.close()

Мы сделали заготовку функции.
my_export() - название нашей функции. В скобках указывается имя входного параметра.
filename - имя файла, которое передаст Blender.Window.FileSelector после завершения ввода
myfile - идентивикатор файла
open() - команда для открытия файла. В скобках сначала указывается имя файла. Буква w в кавычках означает создание нового файла для записи (не для чтения).
close() - команда закрытия файла
В дальнейшем мы будем дописывать эту функцию, добавляя новые строки между строчкой myfile = open(filename, 'w') и строчкой myfile.close(). Обратите внимание, что скрипты чувствительны к "форматированию текста". Это означает, что вы должны выравнивать код вашего скрипта по определённым правилам. Выравнивание необходимо осуществлять параллельно с написанием скрипта программы в текстовом редакторе с помощью клавиши TAB. В противном случае у вас может возникнуть ошибка "IndentationError: expected an indented block" (в консольном окне Blender).

 

6. Перед началом экспорта необходимо получить доступ к объектам сцены.

MYOBJECTS = Blender.Scene.GetCurrent().getChildren()

В данной строчке я беру текущую сцену блендера Blender.Scene.GetCurrent() и узнаю список всех её объектов с помощью getChildren(). Данный список помещается в переменную MYOBJECTS.

 

7. Теперь мы должны просмотреть все объекты и распознать их тип. Например, для мешей:

for object in MYOBJECTS:
if object.getType() != 'Mesh': continue
print 'object:' + object.name

Это цикл с for, который перебирает все объекты object из массива MYOBJECTS. Если тип объекта отличен от Mesh, то вызывается команда continue, которая переходит к следующему элементу массива. Если же мы нашли объект типа "меш", то выведем его имя в окно консоли командой print. Команду print удобно использовать при отладке скриптов: в любом месте вашего скрипта вы можете добавить вывод отладочной информации в консоль.

 

8. Раззмотрим простейший скрипт, который выведет имена мешей, ламп и камер, которые имеются в нашей сцене:

- - - НАЧАЛО КОДА - - -

#!BPY

# --------------------------------------------------
# Peremennie dlya dobavlenia knopki v menu Blender-a
# ==================================================

""" 
Name: 'Nash format...'
Blender: 241
Group: 'Export'
Tooltip: 'Nash format...'
"""

# ------------------------------------
# Informacia dlya polzovateley skripta
# ====================================

__author__ = ["Georgy Moshkin"]
__url__ = ("http://www.tmtlib.narod.ru")
__version__ = "1.0"
__bpydoc__ = """\

Etot skript zapisivaet scenu v nash format. Prosto zapustite skript.

"""

# -----------------------
# Dobavlyaem nujnie uniti
# =======================

import Blender

# --------------------------
# Glavnaya procedura exporta
# ==========================

def my_export(filename):

	# -=((( Otrkoem file dlya zapisi )))=-

	myfile = open(filename, 'w')

	# -=((( Poluchim spisok obyektov tekushey sceni )))=-

	MYOBJECTS = Blender.Scene.GetCurrent().getChildren()

	# -=((( Proydemsa po vsem objektam )))=-

	# export Meshey
	for object in MYOBJECTS:
		if object.getType() != 'Mesh': continue
		print 'mesh:' + object.name

	# export Lamp
	for object in MYOBJECTS:
		if object.getType() != 'Lamp': continue
		print 'lamp:' + object.name

	# export Camer
	for object in MYOBJECTS:
		if object.getType() != 'Camera': continue
		print 'camera:' + object.name
			
	myfile.close() 

# --------------------------------------------
# Vizivaem okno vibora imeni faila dlya zapisi
# ============================================

Blender.Window.FileSelector(my_export, "Export v nash format")

- - - КОНЕЦ КОДА - - -

скачать исходный код
nashformat.zip (1kb)

Теперь осталось дописать код для экспорта мешей, ламп и камер - как раз в те места, где сейчас стоит команда print. Для объектов типа "Mesh" мы будем экспортировать треугольники, текстурные координаты и т.п.. Для объектов типа "Lamp" мы будем экспортировать положение, яркость, направление излучения. Для камеры - координаты и направление взгляда. Распознание типа объектов сделано с той целью, чтобы не возникало случаев экспорта треугольников из камеры или лампы.

 

9. Допишем процедуру экспорта мешей. Ниже приведён скриншот из встроенного текстового редактора Blender. Это исходный код по записи вершин, нормалей и текстурных координат:

В начале обозначен цикл for object in MYOBJECTS. Обратите внимание, что следующие строки сдвинуты вправо на один "TAB".

В Delphi мы написали бы так:

for i:=0 to length(myobjects) -1 do
begin
...
end;

А здесь никаких begin-ов и end-ов нет! Вместо этого важно соблюдать положение текста программы в пространстве и выравнивать его в соответствии с алгоритмом. Например, начиная со строчки for face in faces и до самого конца весь текст смещён вправо - это большой цикл! Внутри этого цикла есть маленький цикл while (vertidx<len(face.uv)), а так как этот цикл вложенный то его текстовое "тело" сдвинуто ещё правее.

Как всё это работает? Переменные создаются прямо по ходу выполнения скрипта. Например, в строчке vertidx = 0 я задал значение переменной для цикла с while. Переменную vertidx компилятор скриптов создаст автоматически!

Весьма оригинально реализованы циклы: например, что делает for object in MYOBJECTS? А делает эта строчка следующее: компилятор сам (!!!) создаст переменную object, которая будет являтся элементом массива MYOBJECTS. И сделает примерно следующее (весьма условный псевдоэквивалент на pascal):

for i:=0 to length(MYOBJECTS)-1 do
begin
object=Pointer(Integer(MYOBJECTS[i]))
... < а вто здесь всё, что в скрипте сдвинуто вправо относительно строчки for object in MYOBJECTS
end;

Вернёмся к рассмотрению приведённой выше части скрипта. Как только мы нашли объект типа Mesh, то выводим в консольное окно отладочную информацию - в данном случае это просто назывние объекта object.name. Далее идёт цикл, который перебирает все полигоны - этот цикл задаётся строчкой for face in faces.

Внутри цикла мы сразу же делаем запись в файл myfile.write("face \n"). Здесь \n служит для перевода строки в файле (аналог нажатия Enter-а). Далее мы проверяем, есть ли у меша текстурные координаты. Если есть - срабатывает строчка if mesh.hasFaceUV: myfile.write("%s \n" % face.image.name).

Далее в файл записывается количество вершин полигона - len(face.v). Полигоны могут иметь 3 или 4 вершины. Причём myfile.write("%i \n" % len(face.v)) означает следующее: в файл запишется всё, что находится в кавычках. Но при этом на место %i будет записан текст целого числа (integer, поэтому буква i перед процентами). Само число, из которого будет сделан текст, находится вне кавычек - после "вторых" процентов.

При записи вершин мы используем не %i, а %f - что означает float (т.к. координаты вершин - это числа с точкой). %f преобразует в текст числа с точкой, а %i - целые числа. Для подстановки текстовых строк используется %s, что означает string.

Здесь мы записываем координаты трёх вершин - v[0], v[1] и v[2] (в случае четырёхугольного полигона сработает проверка if len(face.v) == 4 и допишется четвёртая вершина). Соответствия с x,y,z следующие: .co[0] - это X, .co[1] - это Y, .co[2] - это Z.

Например, face.v[1].co[2] - это координата первой (считая от нуля) вершины по оси Z. Потом мы записываем нормаль - всё аналогично вершинам, только вместо .co[ ] стоит .no[ ]. Здесь всё просто - .co обозначает координаты вершин (coordinates), а .no - нормали в этих вершинах.

Ну и наконец, внизу, идёт цикл с while для записи текстурных координат.

Приведу кусочек из файла, который будет создавать наш скрипт:

Скачать скрипт - blexp.zip (1kb)

10. Я написал скрипт, который уже готов к добавлению в Blender. Теперь полезно на скриншотах посмотреть пошаговую инструкцию по использованию своего скрипта.

10.1. Нужно скопировать наш скрипт в директорию со скриптами Blender-а:

C:\Program Files\Blender Foundation\Blender\.blender\scripts\nashformat.py

10.2 Запустить Blender и сделать окно типа Text Editor (просто смените Window type у любого окна, кликнув на иконку в левом нижнем углу окна).

10.3 В появившемся пустом окне кликните правую кнопку мыши, выберите пункт Open... и откройте скрипт nashformat.py.

 

10.4 В окне появится исходный текст скрипта. Опять нажмите правую кнопку мыши и выберите пункт Execute script...

 

10.5 Наведите мышку на границу между верхним меню и основным окном. Потяните мышкой за эту границу вниз, чтобы вытянуть скрытые настройки из верхней части экрана. Выберите вкладку File Paths и нажмите на иконку "Re-evaluate scripts registration in menus":

 

11. Всё! Теперь в меню программы появится наш фирменный скрипт!

 

Для написания скриптов удобно использовать документацию по написанию Python-овских скриптов в Blender. Хотя написаннный мною скрипт не идеален, но он является отличной базой для понимания и написания собственных скриптов экспорта. Так как при экспорте из Blender-а очень легко обратиться ко всем данным сцены, то возникает возможность создания специального экспортера для создания уровней, учитывающий имена объектов (door_15, key_15, zomby_boss_txt), а также использовать различные параметры "не по назначению". Например, я использую Blender для разработки игры в стиле Resident Evil. Это означает, что двери, ключи, горшки с цветами и зомби и положения камер расстанавливаются при редактировании уровня, а на выходе из экспортера получается уже готовый для использования движком файл. Blender можно использовать не только для создания уровней и различных объектов, но и скелетной анимации.

Часть 3 >>