-- Merges identical materials from an alembic graph based on the material pins -- that are encountered in the correspoding obj file. -- -- @author Thomas Loockx -- @shortcut ctrl+m -- figure out the abc archive and the obj file from the selection local selected = octane.project.getSelection() if #selected ~= 2 then error("expected a Scene and Mesh in the selection") end local objMesh, abcScene = nil, nil if selected[1].type == octane.NT_GEO_MESH and selected[2].type == octane.GT_GEOMETRYARCHIVE then objMesh, abcScene = selected[1], selected[2] elseif selected[2].type == octane.NT_GEO_MESH and selected[1].type == octane.GT_GEOMETRYARCHIVE then objMesh, abcScene = selected[2], selected[1] else error("expected a Scene and Mesh in the selection") end -- create a new nodegraph in which we encapsulate the "complex" abc-scene local newGraph = octane.nodegraph.create { type = octane.GT_STANDARD, name = string.format("%s (Merged Materials)", abcScene.name) } -- copy the original abc-scene into the new graph local abcSceneCopy = newGraph:copyFrom({ abcScene }, { abcScene})[1] -- create new output linker nodes and connect them to the nested abc-scene for _, outLinker in pairs(abcSceneCopy:getOutputNodes()) do local newOutLinker = octane.node.create { type = outLinker.type, name = outLinker.name, graphOwner = newGraph, } newOutLinker:connectTo(octane.P_INPUT, outLinker) end -- collect the name of each material pin on the obj-mesh in a lookup-table local materials = {} for ix=1,objMesh:getPinCount() do if objMesh:getPinInfoIx(ix).type == octane.PT_MATERIAL then materials[objMesh:getPinInfoIx(ix).name] = { -- material connected to the obj material pin ["objMaterial"] = objMesh:getInputNodeIx(ix), -- linker node "grouping" those abc inputs later on ["inputLinker"] = nil } end end -- connect each input linker (pin) of the abc archive with a fresh linker -- -> if the input linker is a material, see if we can "group" this one -- by trying to connect to an already existing input linker node -- -> if the input linker is a non-material, just create another input linker -- and make the connection for _, abcInLinker in ipairs(abcSceneCopy:getInputNodes()) do if abcInLinker.type == octane.NT_IN_MATERIAL then -- see if the name matches one of the material names of the obj-mesh local matched = false for materialName, data in pairs(materials) do if string.find(abcInLinker.name, materialName) then -- if there's no such input linker yet -> create it if not data.inputLinker then data.inputLinker = octane.node.create { type = octane.NT_IN_MATERIAL, name = materialName, graphOwner = newGraph, } -- copy the original obj material in the pin of the new linker octane.node.copyFrom(data.inputLinker, octane.P_INPUT, data.objMaterial) end -- connect the abc input to this material linker abcInLinker:connectTo(octane.P_INPUT, data.inputLinker) -- we had a match so we don't need to create a node anymore matched = true break end end -- if we didn't have a match -> add a fresh linker node if not matched then matInLinker = octane.node.create { type = octane.NT_IN_MATERIAL, name = abcInLinker.name, graphOwner = newGraph, } abcInLinker:connectTo(octane.P_INPUT, matInLinker) end else -- for a non-material linker, just connect it through local nonMatInLinker = octane.node.create { type = abcInLinker.type, name = abcInLinker.name, graphOwner = newGraph, } abcInLinker:connectTo(octane.P_INPUT, nonMatInLinker) end end