-- Create a Baking Node Graph from selection. -- -- @description Create a Baking Node Graph from an Obj Mesh node and a Render Target node -- @author Beppe Gullotta aka "bepeg4d" local version = "2.0" -------- BACKING default settings -------- UVset = 1 -- values from 1 to 3 paddingSize = 4 -- values from 0 to 16 edgeNoise = 0.5 -- values from 0 to 1 ------------------------------------------ local mesh = nil local rt = nil -- figure out the selection of the Render Target and the mesh node local selection = octane.project.getSelection() if #selection ~= 2 then error("a mesh and a render target node need to be selected") end if selection[1]:getProperties().type == octane.NT_GEO_MESH and selection[2]:getProperties().type == octane.NT_RENDERTARGET then mesh, rt = selection[1], selection[2] elseif selection[1]:getProperties().type == octane.NT_RENDERTARGET and selection[2]:getProperties().type == octane.NT_GEO_MESH then mesh, rt = selection[2], selection[1] else error("a mesh and a render target node need to be selected") end -- get the position of the selected node in the graph editor pos = {} if selection[1]:getProperties().type == octane.NT_RENDERTARGET then pos = selection[1].position elseif selection[2]:getProperties().type == octane.NT_RENDERTARGET then pos = selection[2].position end -- Create the baking graph that collect everything params = {} params.type = octane.GT_STANDARD params.name = mesh.name.."_BAKING" params.position = {pos[1], pos[2]+35} root = octane.nodegraph.create(params) copy = root:copyItemTree(rt) RT = root:findFirstNode(octane.NT_RENDERTARGET) RT.name = rt.name.."_BAKING" -- Create object layer nodes for all the pins of the mesh node for pinIx=1, mesh:getPinCount() do objectLayer = octane.node.create { type = octane.NT_OBJECTLAYER, name = mesh:getPinInfoIx(pinIx).name, position = {pos[1]+(75*pinIx), pos[2]+35}, graphOwner = root } objectLayer:setPinValue(octane.P_LAYER_ID, (pinIx+1), true) objectLayer:setPinValue(octane.P_BAKING_GROUP_ID, (pinIx+1), true) end -- Create the object layer map nodes Object_Layer_Map = octane.node.create { type = octane.NT_OBJECTLAYER_MAP, name = mesh.name .."_Object_Layer_Map", position = {pos[1]+(150), pos[2]+75}, graphOwner = root } Mesh = octane.nodegraph.findNodes(root, octane.NT_GEO_MESH) Object_Layer_Map:connectTo(octane.P_GEOMETRY, Mesh[1], false) -- prepare the object layers for connection objl = root:findNodes(octane.NT_OBJECTLAYER) --print ("i layuer sono: ", unpack(objl)) objlName = {} --print("\nBaking Layers are:\n") for i, v in pairs(objl) do objlName[i] = v.name --print(objlName[#objlName]) end -- connect the object layer nodes to the proper pins of the object layer map --print("Connecting Baking Layers\n------") for pinIy=2, Object_Layer_Map:getPinCount() do local nameX = string.gsub (Object_Layer_Map:getPinInfoIx(pinIy).name, "%A+", " ") for i, v in pairs (objlName) do local objlName1 = string.gsub (objlName[i], "%A+", " ") nameP = string.find (nameX, objlName1) if nameP ~= nil then --print("Pin name is ", nameX) --print(nameP) --print("Serch for ", objlName1) nameY = string.sub (nameX, nameP) --print("Change to ", nameY) z = objl[i] --print("Connect to ", z) Object_Layer_Map:connectToIx(pinIy, z) --print("-----") end end end -- check if there is only one material in the graph and connect it to the object layer map node if #objl == 1 and #objl[1]:getDestinationNodes() == 0 then for pinIx=2, Object_Layer_Map:getPinCount() do Object_Layer_Map:connectToIx(pinIx, objl[1]) end end -- check if the object layers node have been connected check = {} for pinIy=2, Object_Layer_Map:getPinCount() do check[pinIy-1] = octane.node.getConnectedNodeIx(Object_Layer_Map, pinIy) if check[pinIy-1] ~= octane.NT_OBJECTLAYER and check[pinIy-1] == nil then Object_Layer_Map:connectToIx(pinIy, objl[pinIy-1]) end end -- create all the neccssary stuff for baking the layers Bcam = octane.node.create { type = octane.NT_CAM_BAKING, name = "Baking_Camera", position = {RT.position[1]-(250), RT.position[2]-(40)}, graphOwner = root } Bcam:setPinValue(octane.P_BAKING_GROUP_ID, 2) Bcam:setPinValue(octane.P_UV_SET, UVset) Bcam:setPinValue(octane.P_PADDING, paddingSize) Bcam:setPinValue(octane.P_TOLERANCE, edgeNoise) RT:connectTo(octane.P_MESH, Object_Layer_Map) RT:connectTo(octane.P_CAMERA, Bcam) RT:disconnect(octane.P_POST_PROCESSING) Res = octane.node.create { type = octane.NT_IMAGE_RESOLUTION, name = "Baking_Resolution", position = {RT.position[1]-(100), RT.position[2]-(40)}, graphOwner = root } Res:setAttribute(octane.A_VALUE, {1024, 1024}) Res:setAttribute(octane.A_ASPECT_RATIO, 1) RT:connectTo(octane.P_RESOLUTION, Res) Rpass = octane.node.create { type = octane.NT_RENDER_PASSES, name = "Baking_Passes", position = {RT.position[1]+(200), RT.position[2]-(70)}, graphOwner = root } Rpass:setPinValue(octane.P_RENDER_PASS_INFO_MAX_SAMPLES, 1024) Rpass:setPinValue(octane.P_BUMP, true) Rpass:setPinValue(octane.P_RENDER_PASS_TANGENT_NORMAL, true) Rpass:setPinValue(octane.P_RENDER_PASS_AMBIENT_OCCLUSION, true) Rpass:setPinValue(octane.P_RENDER_PASS_OPACITY, true) Rpass:setPinValue(octane.P_RENDER_PASS_ROUGHNESS, true) Rpass:setPinValue(octane.P_RENDER_PASS_IOR, true) Rpass:setPinValue(octane.P_RENDER_PASS_DIFFUSE_FILTER_INFO, true) Rpass:setPinValue(octane.P_RENDER_PASS_REFLECTION_FILTER_INFO, true) Rpass:setPinValue(octane.P_RENDER_PASS_REFRACTION_FILTER_INFO, true) Rpass:setPinValue(octane.P_RENDER_PASS_TRANSMISSION_FILTER_INFO, true) RT:connectTo(octane.P_RENDER_PASSES, Rpass) -- create a copy of the render target for each object layer node rtBase = root:findNodes(octane.NT_RENDERTARGET) rtCopy = {} BcamCopy = {} groupedO = {} objlm = root:findNodes(octane.NT_OBJECTLAYER_MAP) rtNum = root:findNodes(octane.NT_OBJECTLAYER) --print ("RT total = ", #rtNum) --print("map= ", unpack(objlm)) --print("quindi = ", objlm[1]) kernelNode = RT:getConnectedNode(octane.P_KERNEL) envNode = RT:getConnectedNode(octane.P_ENVIRONMENT) imgNode = RT:getConnectedNode(octane.P_IMAGER) --print(kernelNode, envNode, imgNode) for pinIy=1, #rtNum do rtCopy[pinIy] = root:copyFrom(rtBase) rtCopy[pinIy][1]:connectTo(octane.P_MESH, objlm[1]) rtCopy[pinIy][1]:connectTo(octane.P_RENDER_PASSES, Rpass) rtCopy[pinIy][1]:connectTo(octane.P_RESOLUTION, Res) rtCopy[pinIy][1]:copyFrom(octane.P_KERNEL, kernelNode) rtCopy[pinIy][1]:copyFrom(octane.P_ENVIRONMENT, envNode) rtCopy[pinIy][1]:copyFrom(octane.P_IMAGER, imgNode) rtCopy[pinIy][1].name = "RT_BAKE_"..rtNum[pinIy].name BcamCopy[pinIy] = rtCopy[pinIy][1]:copyFrom(octane.P_CAMERA, Bcam) BcamCopy[pinIy]:setPinValue(octane.P_BAKING_GROUP_ID, rtNum[pinIy]:getPinValue(octane.P_LAYER_ID)) --print("RT bake = ", rtCopy[pinIy][1].name) end -- create an annotation node Note = octane.node.create { type = octane.NT_ANNOTATION, name = "Baking_Group_IDs", position = {RT.position[1]-(250), RT.position[2]}, graphOwner = root } items = root:findNodes(octane.NT_OBJECTLAYER) -- Let's print some infos in the annotation object and in the log print("\nTotal number of Baking Layers: ", #items) print("\nBaking Layers ID:\n") pText = {} for i, v in pairs(items) do print("ID "..items[i]:getPinValue(octane.P_BAKING_GROUP_ID).."\t > \t"..items[i].name.."\n") pText[i] = "ID "..items[i]:getPinValue(octane.P_BAKING_GROUP_ID).."\t > \t"..items[i].name.."\n" end function add (a) local sum = "" for i,v in ipairs(a) do sum = sum..a[i] end return sum end Note:setAttribute(octane.A_VALUE, "Baking Layers = "..#items .." \nIDs from 2 to "..(#items +1).."\n---\n"..add(pText)) -- group the object layer map: itemsG = root:findNodes(octane.NT_OBJECTLAYER_MAP) grouped = octane.nodegraph.group(root, itemsG, true) grouped.name = "OBJECTLAYER_MAP_GRAPH" -- let's make a bit of order in the graph octane.nodegraph.unfold(root) -- new position for the generic RT and the annotation node rtBase[1].position = {grouped.position[1], grouped.position[2]+150,} Note.position = {grouped.position[1], grouped.position[2]+200,}