Рендер в Dagon 2.0 и Blender 5.0 / Eevee. Как говорится, найдите десять отличий 😀

Не так давно столкнулся с интересной задачей при создании 2D-анимации в Blender: мне нужно было сделать плоскую сетку по форме объекта из PNG-изображения с прозрачным фоном. На обычную плоскость ее натянуть нельзя, так как предполагалось, что объект будет деформироваться при помощи скелета и shape keys. И таких сеток нужно было создать довольно много. Создавать их вручную, расставляя вершины по контуру картинки, как-то очень уж трудоемко — захотелось этот процесс как-то оптимизировать. И тут я вспомнил, что GIMP умеет преобразовывать маски в кривые, которые затем можно сохранить как SVG и импортировать в Blender. Осталось лишь заскриптовать эту последовательность действий!

Я решил, что переносить SVG вручную из одной программы в другую я тоже не хочу — пусть будет условно одна-единственная кнопка, по нажатию на которую слой из GIMP переносится в текущий открытый проект Blender. Подобное взаимодействие двух приложений можно реализовать при помощи технологий RPC (remote procedure call) — в частности XML-RPC, который позволяет через HTTP на клиенте вызвать серверную функцию, передав ей параметры, и затем получить результат. Преимущество XML-RPC в том, что он полностью скрывает транспортный механизм такого вызова — в скриптовых языках он выглядит просто как обычный вызов функции. Сервером я решил сделать плагин для Blender, клиентом — плагин для GIMP. Оба плагина я написал на Python, где протокол XML-RPC реализован в стандартной библиотеке. В GIMP и Blender используются разные версии Python, поэтому код работы с XML-RPC немного отличается.
Серверная часть выглядит достаточно тривиально: нужна лишь функция, которая принимает на вход строку, содержащую SVG — эта функция регистрируется как серверная функция в объекте SimpleXMLRPCServer:
import os
import bpy
import threading
import tempfile
from xmlrpc.server import SimpleXMLRPCServer
HOST = "127.0.0.1"
PORT = 8000
def svg_to_curve(svg:str):
tmp = tempfile.NamedTemporaryFile(delete=False, mode="w")
tmp.write(svg)
tmp.close()
bpy.ops.import_curve.svg(filepath=tmp.name, filter_glob='*')
os.unlink(tmp.name)
return {}
def launch_server():
server = SimpleXMLRPCServer((HOST, PORT))
server.register_function(svg_to_curve)
server.serve_forever()
(для краткости я опустил служебный код для регистрации плагина)
Проблема возникает лишь в момент импорта SVG — Blender умеет импортировать только по файловому имени, поэтому пришлось сохранить строку во временный файл. Выглядит не очень элегантно, но работает.
На стороне GIMP делается следующее: текущему слою создается маска из альфа-канала, из маски создается выделение (gimp_image_select_item), из выделения, в свою очередь — кривая (plug_in_sel2path). Кривая экспортируется в SVG (gimp_vectors_export_to_string), а затем мы просто вызываем удаленную функцию svg_to_curve, после чего удаляем все служебные объекты.
import xmlrpclib
from gimpfu import *
def export_svg(svg):
proxy = xmlrpclib.ServerProxy("http://localhost:8000/")
try:
proxy.svg_to_curve(svg)
except xmlrpclib.Fault as err:
pdb.gimp_message(err.faultString)
def layer_to_blender_curve(image, layer):
if not pdb.gimp_item_is_group(layer):
mask = layer.mask
if not mask:
mask = layer.create_mask(ADD_ALPHA_TRANSFER_MASK)
layer.add_mask(mask)
pdb.gimp_image_select_item(image, CHANNEL_OP_REPLACE, mask)
path = pdb.plug_in_sel2path(image, None)
pdb.gimp_selection_none(image)
vector_name = pdb.gimp_path_list(image)[1][0]
vec = pdb.gimp_image_get_vectors_by_name(image, vector_name)
vec.name = "mask_path"
svg = pdb.gimp_vectors_export_to_string(image, path)
export_svg(svg)
pdb.gimp_image_remove_vectors(image, vec)
pdb.gimp_layer_remove_mask(layer, 0)
Ошибки, которые могли возникнуть в процессе передачи данных, удобно выводить в лог функцией gimp_message.
Исходники плагинов вы можете найти в репозитории https://github.com/gecko0307/image2curve.
Недостатком данного решения является то, что на стороне Blender будет постоянно работать HTTP-сервер на localhost:8000, так что вы в это время не сможете привязать к этому порту ничего другого. В Python есть способы получить случайный незанятый номер порта, чтобы не конфликтовать с другими серверами, однако в этом случае придется как-то передать порт в GIMP, что, как мне кажется, несколько усложняет весь процесс и добавляет лишнюю точку отказа.
Близится конец года, и это значит, что наступило время для традиционного подведения итогов по проектам.
Ну и, конечно, не могу не назвать самые значимые для меня события в мире CG, СПО и геймдева:
В грядущем Dagon 0.11 будет поддерживаться дополнительный метод тональной компрессии схожий по результату с тем, что используется в Blender 2.8 (Filmic View Transform). Ниже — сравнение рендеров Eevee в Blender 2.82 и Dagon на примере сцены со шлемом из коллекции примеров glTF. Моя картинка чуть более контрастна, но зато нет «передержаных» бликов.

Ну и, конечно, не могу не назвать самые значимые для меня события в мире CG, СПО и геймдева:
Кстати, модель средневекового дома (и еще несколько моих игровых моделей) вы можете купить по более чем скромным ценам на CGTrader, чем поддержите мой проект по созданию современного 3D-движка для D.
Напоследок, по сложившейся традиции, перечислю самые значимые для меня события в мире CG, СПО и геймдева:
Чем для меня был интересен прошедший 2015 год? Вот самые, на мой скромный взгляд, значимые события в мире CG, СПО и любительского геймдева:
А в этом выпуске FPS вы найдете следующие материалы:
Журнал доступен для онлайн-чтения и загрузки на Документах Google, на Dropbox, а также на Issuu.com.
Последние новости по проекту вы можете узнать в публичной странице журнала в социальной сети Google+: http://gplus.to/fpsmag. Добавляйте нас в круги, оставляйте свои комментарии и отписывайтесь в нашем сообществе.
Архив номеров журнала вы можете найти здесь.
Вышел 27 номер электронного PDF-журнала «FPS», посвященного разработке игр, программированию, компьютерной графике и звуку.
Читайте в этом номере:
> Подборка новостей по Blender
> Тон Розендаль о будущем интерфейса Blender
> GIMP: цветокоррекция на Python
> От мольберта — к дисплею. Заметки о цифровой живописи
> Физический движок своими руками. Часть IV
> Математика в dlib
> Ranges: диапазоны в D
> Игровые новости из мира Linux
> Право на творчество
Номер доступен для онлайн-чтения и загрузки на сервисе Issuu.com, Документах Google и Dropbox.
Последние новости по проекту вы можете узнать в публичной странице журнала в социальной сети Google+: http://gplus.to/fpsmag. Добавляйте нас в круги, оставляйте свои комментарии и отписывайтесь в нашем сообществе.
Архив номеров журнала здесь.