Скрипты в 3D/VFX — Python в eyeon Fusion 6.1

16 Янв
2012

Приветствую всех блогажителей! Не так давно пришлось написать несколько небольших скриптов для 3D и VFX пакетов, тема это довольно интересная, но нужную информацию найти не всегда просто. С некоторыми пакетами, например Nuke, дела обстоят весьма неплохо, есть очень качественные доки и большой, активный комьюнити, тогда как с другими, в том числе Fusion, все гораздо более плачевно. Fusion это довольно популярный пакет композа ака compositing, используется очень серьезными студиями, credits включает себя кучу голливудских блокбастеров. Основным скриптовым языком во Fusion до 6-ой версии был Lua, но в 6-ой версии появился Python — ребята из eyeon software решили последовать за разработчиками других пакетов и трендом последних лет который сделал Python the language of choice в индустрии 3D и VFX. Сие знаменательное событие было встречено (заслуженными) аплодисментами комьюнити, вот только как я упоминал выше, их документация по работе с Python весьма скудная, и информации в сети тоже не густо. Под катом небольшой набор snippets которые я сохранял по мере работы, надеюсь что они помогут кому то сохранить немного времени.



Простой пример того как одни и те же вещи делаются на Lua и на Python:

#Lua
fusion = Fusion()

#Python
fusion = eyeon.scriptapp("Fusion")

#Lua
mycomp = fusion:NewComp()
#Python
mycomp = fusion.NewComp()

#Lua
currentComp = fusion:GetCurrentComp()

#Python
currentComp = fusion.GetCurrentComp()

#Lua
toollist = composition:GetToolList()

#Python
toollist = currentComp.GetToolList()


Работа с PeyeonScript (Python Bindings для eyeonscript):

import PeyeonScript as eyeon
fusion = eyeon.scriptapp("Fusion")
comp = fusion.CurrentComp


Поиск .EXE файла Fusion:

fusion = eyeon.scriptapp("Fusion")
FusionPath = fusion.MapPath("Fusion:\\") + "Fusion.exe"
print (FusionPath)


Запираем (locking) композицию:

comp.Lock()
.. do stuff ..
comp.Unlock()


Get и Set attributes ноды/композиции:

print(comp.GetAttrs())
print(object.GetAttrs())

# получаем нужные атрибуты
print(comp.GetAttrs('SOME_ATTR'))

# задаем нужные атрибуты
comp.SetAttrs({'COMPN_RenderEnd': 50})
object.SetAttrs({'TOOLB_PassThrough': True})


Get и Set preferences у композиции:

print(comp.GetPrefs())
comp.SetPrefs({})


Get и Set inputs у ноды:

object.GetInputList()
print(object.GetInputList())


Работа с нодами лоадеров (loader):

loader = comp.Loader({'Clip' : 'C:\\Path_To_File.jpg'})

mat = comp.MtlBlinn({'Diffuse.Color.Material' : 'C:\\Path_To_File.jpg', 'Specular.Intensity.Material' : 'C:\\Path_To_File.jpg'})
geo = comp.SurfaceFBXMesh({'ImportFile' : 'C:\\Path_To_File.fbx', 'ObjName' : 'Sphere', 'Size' : 0.5})
disp_tex = comp.Loader({'Clip' : 'C:\\Path_To_File.jpg'})
disp = comp.Displace3D({'Scale' : 7.5, 'Bias' : -0.5, 'Input' : disp_tex, 'SceneInput' : geo})


Еще лоадеры немного по другому:

diff_tex = comp.Loader({'Clip' : 'C:\\Path_To_File.jpg'})
spec_tex = comp.Loader({'Clip' : 'C:\\Path_To_File.jpg'})
disp_tex = comp.Loader({'Clip' : 'C:\\Path_To_File.jpg'})

mat = comp.MtlBlinn({})
mat.Diffuse.Color.Material = diff_tex
mat.Specular.Intensity.Material = spec_tex

geo = comp.SurfaceFBXMesh({})
geo.ImportFile = 'C:\\Path_To_File.fbx'
geo.ObjName = 'Sphere'
geo.Size = 0.5
geo.MaterialInput = mat

disp = comp.Displace3D({})
disp.Input = disp_tex
disp.SceneInput = geo
disp.Scale = 7.5
disp.Bias = -0.5


Работа с NormalBump нодой:

norm = comp.Loader({'Clip' : 'C:\\Path_To_File.jpg'})
norm_tex = comp.BumpMap({})
norm_tex.Input = norm
norm_tex.SourceImageType = 1

norm_tex = comp.BumpMap({'Input' : norm, 'SourceImageType' : 1})


Экспорт FBX геометрии:

fus_geo = 'C:\\Path_To_File.fbx'

geo_out = comp.ExporterFBX({})
geo_out.Input = disp_tex
geo_out.Filename = fus_geo

# атрибуты форматов FBX экспортера
print(geo_out.Format.GetAttrs())
print(geo_out.Format.GetAttrs()['INPIDT_ComboControl_ID'])

# Форматы сохранения геометрии
geo_out.Format = 'FBX_binary'
geo_out.Format = '_3D_Studio_3DS'
geo_out.Format = 'Alias_OBJ'


Работа с Views (видовые окна):

# создаем лоадер с картинкой
image = comp.Loader({'Clip' : 'C:\\Temp\\image.png'})

# создаем переменные с view (L_view = Left View A, L2_view = Left View B)
L_view = comp.GetPreviewList()["Left"]
L2_view = comp.GetPreviewList()["Left.B"]
R_view = comp.GetPreviewList()["Right"]
R2_view = comp.GetPreviewList()["Right.B"]

# выводим картинку на viewer
L_view.ViewOn(image)

# очищаем viewer
L_view.ViewOn(0)

# масштабируем viewer (50% = .5, 100% = 1, Fit = 0)
L_view.View.SetScale(.5)
L_view.View.SetScale(1)
L_view.View.SetScale(0)

# делаем A/B view
L_view.View.SetBuffer(2)

# делаем split между A and B view
L_view.View.SetSplit(.5, .5, 45)

# reset view
L_view.View.ResetView()

# делаем QuadView
L_view.View.ShowQuadView(True)
L_view.View.ShowQuadView(False)

# проверяем если view это QuadView, возвращаем true или false (смотрим через print)
L_view.View.ShowingQuadView()

# делаем sub view
L_view.View.ShowSubView(True)
L_view.View.ShowSubView(False)

# проверяем если view это SubView, возвращаем true или false (смотрим через print)
L_view.View.ShowingSubView()

# своп между SubView и main view
L_view.View.SwapSubView()

# включаем или отключаем LUT для current Buffer
L_view.View.EnableLUT()

# проверяем если current Buffer LUT включен, возвращаем true или false (смотрим через print)
L_view.View.IsLUTEnabled()

# image is operator object to be view. If this is nil, the view will be cleared. If this is omitted completely, the currently active tool will be viewed.
# integer it is the number of the image view to view the tool on, as numbered within the Fusion user interface. 1 is the Left image view, 2 is the Right image view, and higher numbers may be available depending available floating views or hardware. If omitted, all views will be cleared.


comp.CurrentFrame.ViewOn(image, 1) # смотрим картинку на left view
comp.CurrentFrame.ViewOn(image, 2) # смотрим картинку на right view
comp.CurrentFrame.ViewOn(1) # смотрим активную ноду на left view, также toogle on/off
comp.CurrentFrame.ViewOn(2) # смотрим активную ноду на right view, также toogle on/off
comp.CurrentFrame.ViewOn(1, 0) # очищаем left view
comp.CurrentFrame.ViewOn(2, 0) # очищаем right view
comp.CurrentFrame.ViewOn() # очищаем все views

# переключаем main views
comp.CurrentFrame.SwitchMainView('ToolView')
comp.CurrentFrame.SwitchMainView('SplineEditorView')
comp.CurrentFrame.SwitchMainView('TimelineView')
comp.CurrentFrame.SwitchMainView('TransportView')
comp.CurrentFrame.SwitchMainView('ModifierView')
comp.CurrentFrame.SwitchMainView('MaskView')
comp.CurrentFrame.SwitchMainView('TimeRulerView')
comp.CurrentFrame.SwitchMainView('ConsoleView')
comp.CurrentFrame.SwitchMainView('InfoView')
comp.CurrentFrame.SwitchMainView('FlowView')
comp.CurrentFrame.SwitchMainView('CurrentView')
comp.CurrentFrame.SwitchMainView('Composition')

# переключаем Controls views
comp.CurrentFrame.SwitchControlView('ControlView')
comp.CurrentFrame.SwitchControlView('ModifierView')


Selections, выбор нод:

# определяем object
object = comp.Loader({})

# определяем flow
flow = comp.CurrentFrame.FlowView

# выбираем object (оба варианта валидны)
flow.Select(object)
flow.Select(object, True)

# сбрасываем выбор (deselect)
flow.Select(object, False)


Делаем нашу ноду активной:

# определяем object
object = comp.Loader({})

# делаем его активным
comp.SetActiveTool(object)


Узнаем какая нода активна:

print(comp.GetAttrs('COMPH_ActiveTool'))
print(comp.ActiveTool())


Двигаем ноды по flow:

# определяем flow
flow = comp.CurrentFrame.FlowView

# определяем object
object = comp.Loader({'Clip' : 'C:\\Temp\\image.png'})

# задаем object position во flow
flow.SetPos(object, 5, 5)

# узнаем object position во flow
flow.GetPos(object) # возвращает только X position
flow.GetPosTable(object) # возвращает X и Y как dictionary


Группируем ноды:

# создаем группу
group = comp.GroupOperator({})

# задаем имя группы
group.SetAttrs({'TOOLS_Name': 'GroupName'})

# вставляем ноды в группу
object.SetAttrs({'TOOLH_GroupParent': group})


Rendering aka Визуализация:

# рендерим композицию
comp.Render(True, 0, 1) # Render(wait_for_render, renderstart, renderend, step, proxy, hiQ, mblur)

# задаем start time
comp.SetAttrs({'COMPN_RenderStart': 0.0}) # integer = render start time in frames

# задаем end time
comp.SetAttrs({'COMPN_RenderEnd': 50}) # integer = render end time in frames

# задаем global start time
comp.SetAttrs({'COMPN_GlobalStart': 10}) # integer = global start time in frames

# задаем global end time
comp.SetAttrs({'COMPN_GlobalEnd': 10}) # integer = global end time in frames

# рендерим в фоне (background rendering)
comp.SetAttrs({'COMPB_Rendering': True})
comp.SetAttrs({'COMPB_Rendering': False})

# узнаем render start/end у композиции
print(comp.GetAttrs('COMPN_RenderStartTime'))
print(comp.GetAttrs('COMPN_RenderEndTime'))

# задаем render start/end для композиции
comp.SetAttrs({'COMPN_RenderStart': 5})
comp.SetAttrs({'COMPN_RenderEnd': 50})
По материалам Хабрахабр.



загрузка...

Комментарии:

Наверх