Oh dear. If only we could make it look like this:
Today we will wrap the Alembic node into another node graph, and then we can hook up all inputs which should have the same material with one input linker of our wrapping node graph, so we avoid a lot of spaghetti on the outside.
Download the entire script here:
You will see the names of the objects in the input pins of the Scene node, suffixed with "-Material". 3D-applications usually use some pattern to name these objects, so we can use a script to recognize these patterns and hook up the linkers automatically.
At the top of the script there is a function which gets the name of a material input on our Alembic scene node, and it returns which material name we want to assign to it. You may have to adapt it to your specific file.
In our case the Alembic file came from Cinema 4D. It will add a sequence number and the "Shape" suffix to object names. Octane adds a dash and the default material name, "Material". Our function chops all the extra pieces off and uses the original object name as material input. This way all objects with the same name in Cinema 4D get the same material in Octane.
- Code: Select all
function getMaterialInputName(name)
-- These are Lua patterns. See <http://lua-users.org/wiki/PatternsTutorial>
-- chop off the "Shape" and "-Material" parts
name = name:gsub("Shape%-Material$", "")
-- chop off any sequence numbers
name = name:gsub("_%d+$", "")
return name
end
We get our node graph from the selection, and check if it is not in the root node graph. (use the "Group item" feature in the context menu to automatically wrap the alembic scene).
- Code: Select all
local scene = octane.project.getSelection()[1]
if not scene or scene:getProperties().type ~= octane.GT_GEOMETRYARCHIVE
or scene:getProperties().graphOwner == octane.nodegraph.getRootGraph() then
octane.gui.showDialog
{
type = octane.gui.dialogType.BUTTON_DIALOG,
title = "Metal.",
text = "Please select a scene inside a node graph. If your scene is"..
" in the root node graph wrap it using the \"group items\" feature.",
}
return
end
local parent = scene:getProperties().graphOwner
Then we look if our parent graph already has material inputs so we can recycle them. This way if you reload the file and it gets some new inputs you can run this script again without losing the connections into the inputs of the parent graph.
- Code: Select all
local links = {}
for _, l in pairs(parent:getInputNodes()) do
local prop = l:getProperties()
if prop.type == octane.NT_IN_MATERIAL then
links[prop.name] = l
end
end
local used = {}
Now we loop over the material inputs of the Alembic scene and use our
getMaterialInputName
function to decide what material assignment it should get. If possible we recycle an existing input node, otherwise we have to create a new one. We also put them into a nice row above the alembic scene node. Remember the positions of the linkers decide the order of the input pins of the parent graph.- Code: Select all
for _, l in ipairs(scene:getInputNodes()) do
local prop = l:getProperties()
local name = getMaterialInputName(prop.name)
if prop.type == octane.NT_IN_MATERIAL then
if used[name] == nil then
used[name] = links[name]
links[name] = nil
if used[name] == nil then
used[name] = octane.node.create{type=octane.NT_IN_MATERIAL, name=name, graphOwner=parent}
end
used[name]:updateProperties{position=pos}
pos[1] = pos[1] + 100
end
l:disconnect(octane.P_INPUT)
l:connectTo(octane.P_INPUT, used[name])
end
end
We may have some existing linker nodes left which didn't get hooked up to anything. As a finishing touch we just add them at the end of the row. If there are no materials embedded into the input pins corresponding to these input linker nodes you may delete these extra linkers afterwards.
--
Roeland