Alembic and material assignments

Forums: Alembic and material assignments
Forum for OctaneRender Lua scripting examples, discussion and support.

Alembic and material assignments

Postby roeland » Tue Jan 14, 2014 11:24 pm

roeland Tue Jan 14, 2014 11:24 pm
So you imported an Alembic file, only to get a single material input called "Material"? You can disable merging of materials, but now you have 100's of input pins for all the objects in your scene. At least we can give every object its own material.

without extra graph.png


Oh dear. If only we could make it look like this:

with extra graph.png


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:
Material assignment graph.lua
(2.44 KiB) Downloaded 538 times

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
User avatar
roeland
OctaneRender Team
OctaneRender Team
 
Posts: 1741
Joined: Wed Mar 09, 2011 10:09 pm

Re: Alembic and material assignments

Postby bepeg4d » Wed Jan 15, 2014 11:27 am

bepeg4d Wed Jan 15, 2014 11:27 am
thanks roeland ;)
it works smoothly, another weapon in the lua arsenal ;)
ciao beppe
User avatar
bepeg4d
Octane Guru
Octane Guru
 
Posts: 6692
Joined: Wed Jun 02, 2010 6:02 am
Location: Italy

Re: Alembic and material assignments

Postby glimpse » Wed Jan 15, 2014 12:09 pm

glimpse Wed Jan 15, 2014 12:09 pm
thanks Guys for putting all this info! =)
tomGlimps | [email protected] | 32GB | TitanBlack
Available for Freelance, Coaching & Mentoring
User avatar
glimpse
Licensed Customer
Licensed Customer
 
Posts: 3607
Joined: Wed Jan 26, 2011 2:17 pm

Re: Alembic and material assignments

Postby César » Fri Mar 14, 2014 10:12 am

César Fri Mar 14, 2014 10:12 am
I don't understand, how can you know wich material link to the objects when Alembic don't support materials ?

In addition, the script don't work with the Standalone 1.36.
User avatar
César
Licensed Customer
Licensed Customer
 
Posts: 101
Joined: Wed May 30, 2012 7:54 am
Location: France

Re: Alembic and material assignments

Postby Witwatersrand » Wed Jul 22, 2015 12:48 pm

Witwatersrand Wed Jul 22, 2015 12:48 pm
Hey guys

Using Octance 2.32.2 and I am getting an error when using this script .

[String "Material assignment graph.lua"]:26: attempt to call field 'getRootGraph' (a nil value)

Is there an update in the script needed or did I just not use it correctly?

Kind regards

Angus
Octane 2.03 : Mac Book Pro Retina, 16 Gig Ram, Nvidia 640m gfx, Octane 2.03. Dell T5500, 32 Gig Ram, Nvidia Quadro 4000
Witwatersrand
Licensed Customer
Licensed Customer
 
Posts: 12
Joined: Mon Jan 06, 2014 4:13 am

Re: Alembic and material assignments

Postby stratified » Wed Jul 22, 2015 9:30 pm

stratified Wed Jul 22, 2015 9:30 pm
Witwatersrand wrote:Hey guys

Using Octance 2.32.2 and I am getting an error when using this script .

[String "Material assignment graph.lua"]:26: attempt to call field 'getRootGraph' (a nil value)

Is there an update in the script needed or did I just not use it correctly?

Kind regards

Angus


Hi,

In subsequent versions getRootGraph() was renamed to getSceneGraph(). If you change this on line 26, it should work.

cheers,
Thomas
User avatar
stratified
OctaneRender Team
OctaneRender Team
 
Posts: 945
Joined: Wed Aug 15, 2012 6:32 am
Location: Auckland, New Zealand

Re: Alembic and material assignments

Postby bepeg4d » Tue Sep 15, 2015 9:47 am

bepeg4d Tue Sep 15, 2015 9:47 am
Hi, it seems that this script gives some issues again :roll:
Here is a modified version that get one material per geometry name, I had to change the chop pattern from "-Material" to "-Diffuse material" because C4D now use this pattern.
I had to quote the getSceneGraph for make it working. Anyway, the abc materials pins are still there :roll:
Schermata 2015-09-15 alle 11.42.07.jpg

Code: Select all
local scene = octane.project.getSelection()[1]
if not scene or scene:getProperties().type ~= octane.GT_GEOMETRYARCHIVE then
    --or scene:getProperties().graphOwner == octane.nodegraph.getSceneGraph() 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

function getMaterialInputName(name)
    -- These are Lua patterns. See <http://lua-users.org/wiki/PatternsTutorial>
    -- chop off the "-Diffuse material" parts
    name = name:gsub( "-Diffuse material", "")
    -- chop off any sequence numbers
    name = name:gsub(" %d+$", "")
    return name
end


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 = {}

local pos = scene:getProperties().position
pos[2] = pos[2] - 100
pos[1] = pos[1] - 100

for _, l in ipairs(scene:getInputNodes()) do
    local prop = l:getProperties()
   
    local name = getMaterialInputName(prop.name)
    print (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

for _, l in pairs(links) do
    l:updateProperties{position=pos}
    pos[1] = pos[1] + 100
end

ciao beppe
User avatar
bepeg4d
Octane Guru
Octane Guru
 
Posts: 6692
Joined: Wed Jun 02, 2010 6:02 am
Location: Italy

Return to Lua Scripting


Who is online

Users browsing this forum: No registered users and 2 guests

Fri Nov 15, 2019 12:32 am [ UTC ]