Выбрать главу

Мы снова используем модуль pim, который будет или псевдонимом для модуля PIL, если он доступен, или ссылкой на нашу собственную реализацию, если PIL не доступен. Важные отличия от нашего предыдущего кода комбинирования изображений выделены. Первая выделенная часть показывает, как вычислять размер комбинированного изображения, исходя из количества строк и колонок плюс количество пикселей, необходимое для цветных окантовок вокруг изображений. Вторая выделенная строка показывает, где мы вставляем картинки в целевое изображение:

def strip(files,name='Strip',cols=4):

   rows = int(len(files)/cols)

   if len(files)%int(cols) : rows += 1

   im = pim.open(files.pop(0))

   w,h= im.size

   edge=2

   edgecolor=(0.0,0.0,0.0)

   comp =  pim.new(im.mode,

                   (w*cols+(cols+1)*edge,

                   h*rows+(rows+1)*edge),

                   edgecolor)

   for y in range(rows):

      for x in range(cols):

         comp.paste(im,(edge+x*(w+edge),edge+y*(h+edge)))

         if len(files)>0:

            im = pim.open(files.pop(0))

         else:

            comp.save(name,format='png')

            return Image.Load(name)

Функция  render(), которую мы определяем, принимает количество пропускаемых кадров в виде аргумента и рендерит любое количество кадров между начальным и конечным кадрами. Эти начальный и конечный кадры могут быть заданы пользователем в панели кнопок рендера. Эти кнопки рендера также содержат величину шага, но эта величина не доступна в API Питона. Это означает, что наша функция будет несколько избыточнее, чем нам хотелось бы, так как мы должны создать цикл, который рендерит каждый отдельный кадр (выделено в следующем коде) вместо прямого вызова  renderAnim(). Следовательно, мы должны манипулировать атрибутами startFrame и endFrame контекста рендера (как и раньше), но мы будем осторожными и восстановим эти атрибуты перед возвратом списка имён файлов отрендеренных картинок. Если бы мы не нуждались в каком-либо программном контроле значения величины пропуска, мы могли бы просто заменить вызов render() вызовом renderAnim():

def render(skip=10):

   context = Scene.GetCurrent().getRenderingContext()

   filenames = []

   e = context.endFrame()

   s = context.startFrame()

   context.displayMode=0

   for frame in range(s,e+1,skip):

      context.currentFrame(frame)

      context.startFrame(frame)

      context.endFrame(frame)

      context.renderAnim()

      filenames.append(context.getFrameFilename())

   context.startFrame(s)

   context.endFrame(e)

   return filenames

После определения этих функций сам скрипт теперь просто вызывает render(), чтобы создавать изображения, и strip(), чтобы объединить их. Результирующее изображение Блендера перезагружается (reload) для его обновления на экране, если изображение с таким именем уже присутствовало, затем все окна перерисовываются (выделено):

def run():

   files = render()

   im=strip(files)

   bpy.data.images.active = im

   im.reload()

   Window.RedrawAll()

if __name__ == "__main__":

   run()

Полный код доступен как strip.py в файле combine.blend.

Рабочий процесс — использование strip.py

Создать ленту анимационных кадров можно следующим образом:

1. Создать вашу анимацию. (Ага, это, конечно самый простой пункт ;) -прим. пер.)

2. Запустить strip.py из текстового редактора.

3. Комбинированное изображение появится в окне редактора UV/image.

4. Сохранить изображение с именем по вашему выбору.

Рендер билбордов

Слово Billboard дословно переводится как «доска для объявлений» или «рекламный щит», что конечно же мало подходит для нашего случая. В разработке  игр billboards  часто применяются, и к сожалению, адекватного перевода для этого нигде нет, везде используется эта уродливая транскрипция «билборд». Придётся и мне ей пользоваться - сожаление переводчика.