-- @description Creates 3x4 matrices from position, rotation and scale values -- @author ruthenoid -- @version 0.1 -- @script-id posRotScale2scatter local scatter = octane.project.getSceneGraph():findNodes(octane.NT_GEO_SCATTER, true) --find all scatter nodes local selectedNode = octane.project.getSelection()[1] --get selected node local selId = 0 local allScatterNodes = {} for i = 1, #scatter do local info = octane.node.getNodeInfo(scatter[i]) local props = octane.node.getProperties(scatter[i]) local inputNode = scatter[i]:getConnectedNode(octane.P_GEOMETRY) --scatter has an input if inputNode ~= nil then allScatterNodes[i] = scatter[i].name .. " <-- " .. tostring(inputNode.name) --scatter has no input else allScatterNodes[i] = scatter[i].name end --get the index of the selected scatter node if scatter[i] == selectedNode then selId = i end end --local matrix = scatter[selId]:getAttribute(octane.A_TRANSFORMS) -- draw gui local texteditorLabel = octane.gui.createLabel({ text = "Format: posX posY posZ rotX rotY rozZ scaleX scaleY scaleZ (separated by spaces, by line)", width = 600, height = 16 }) local texteditor = octane.gui.createTextEditor({ name = "transformBox", text = "0 0 0 0 0 0 1 1 1", width = 620, height = 250, padding = {2}, border = false, multiline = true, centre = true, }) local texteditorLayoutGrp = octane.gui.create{ type = octane.gui.componentType.GROUP, text = "", rows = 2, cols = 1, children = { texteditorLabel, texteditor }, padding = { 2 }, centre = true, border = false, } local scatterSelectLabel = octane.gui.createLabel({ text = "scatter node", }) local scatterSelect = octane.gui.createComboBox({ name = "scatterSel", items = allScatterNodes, width =320, selectedIx = selId, tooltip = "Select a scatter node (please name your nodes)", }) local scatterSelectLayoutGrp = octane.gui.create{ type = octane.gui.componentType.GROUP, text = "", rows = 1, cols = 2, children = { scatterSelectLabel, scatterSelect }, padding = { 2 }, } local degOrRadLabel = octane.gui.createLabel({ text = "rotation unit", }) local degOrRadSelect = octane.gui.createComboBox({ name = "degOrRad", items = {"deg", "rad"}, selectedIx = 1, tooltip = "Choose degrees or radians", }) local degOrRadLayoutGrp = octane.gui.create{ type = octane.gui.componentType.GROUP, text = "", rows = 1, cols = 2, children = { degOrRadLabel, degOrRadSelect }, padding = { 2 }, } local rotTypeLabel = octane.gui.createLabel({ text = "rotation order", }) local rotTypeSelect = octane.gui.createComboBox({ name = "XYZ", items = {"XYZ", "XZY", "YXZ", "YZX", "ZXY", "ZYX"}, selectedIx = 6, tooltip = "Look up the default rotation order in your application or guess", }) local rotTypeLayoutGrp = octane.gui.create{ type = octane.gui.componentType.GROUP, text = "", rows = 1, cols = 2, children = { rotTypeLabel, rotTypeSelect }, padding = { 2 }, } local renderBtn = octane.gui.create{ type = octane.gui.componentType.CHECK_BOX, text = "update render", checked = true, width = width, height = editHeight, tooltip = "Will restart renderer when data is updated" } local okBtn = octane.gui.createButton{ name = "okBtn", text = "update node", width = 160, tooltip = "This overwrites data in the selected scatter node" } local closeBtn = octane.gui.createButton{ name = "closeBtn", text = "close", width = 160, } local btnLayoutGrp = octane.gui.create{ type = octane.gui.componentType.GROUP, text = "", rows = 1, cols = 3, children = { renderBtn, okBtn, closeBtn }, padding = { 2 }, border = false, } local selLayoutGrp = octane.gui.create{ type = octane.gui.componentType.GROUP, text = "", rows = 1, cols = 2, children = { degOrRadLayoutGrp, rotTypeLayoutGrp }, centre = false, padding = { 2 }, border = false, debug = false, -- true to show the outlines of the group, handy } local layoutGrp = octane.gui.create{ type = octane.gui.componentType.GROUP, text = "", rows = 4, cols = 1, children = { texteditorLayoutGrp, selLayoutGrp, scatterSelectLayoutGrp, btnLayoutGrp }, centre = true, padding = { 2 }, border = false, } -- window that holds all components local PlaneWindow = octane.gui.create { type = octane.gui.componentType.WINDOW, text = "pos rot scale to matrix3x4", children = { layoutGrp }, width = layoutGrp:getProperties().width + 16, height = layoutGrp:getProperties().height + 4, } -- callback handling the GUI elements local function guiCallback(component, event) -- okBtn if component.name == "okBtn" then local lines = mysplit(texteditor.text, "\n") --split per line local rotIndex = rotTypeSelect.selectedIx - 1 --get rotation order from gui local degOrRad = degOrRadSelect.selectedIx --get rotation unit from gui local pts = "" local matreces = {} for i = 1, #lines do pts = mysplit(lines[i], " ") local pos = {pts[1], pts[2], pts[3]} local rot = {} if degOrRad == 1 then rot = {math.rad(pts[4]), math.rad(pts[5]), math.rad(pts[6])} else rot = {pts[4], pts[5], pts[6]} end local scl = {pts[7], pts[8], pts[9]} matreces[i] = octane.matrix.make3dTransformation(rot, scl, pos, rotIndex) --create tranform matrix 3x4 end local index = scatterSelect.selectedIx scatter[index]:setAttribute(octane.A_TRANSFORMS, matreces ) scatter[index]:setAttribute(octane.A_RELOAD, true ) if renderBtn.checked then octane.changemanager.update() end -- closeBtn elseif component.name == "closeBtn" then PlaneWindow:closeWindow() end end okBtn:updateProperties { callback = guiCallback } closeBtn:updateProperties { callback = guiCallback } function mysplit(inputstr, sep) if sep == nil then sep = "%s" end local t={} ; i=1 for str in string.gmatch(inputstr, "([^"..sep.."]+)") do t[i] = str i = i + 1 end return t end function print_r ( t ) local print_r_cache={} local function sub_print_r(t,indent) if (print_r_cache[tostring(t)]) then print(indent.."*"..tostring(t)) else print_r_cache[tostring(t)]=true if (type(t)=="table") then for pos,val in pairs(t) do if (type(val)=="table") then print(indent.."["..pos.."] => "..tostring(t).." {") sub_print_r(val,indent..string.rep(" ",string.len(pos)+8)) print(indent..string.rep(" ",string.len(pos)+6).."}") elseif (type(val)=="string") then print(indent.."["..pos..'] => "'..val..'"') else print(indent.."["..pos.."] => "..tostring(val)) end end else print(indent..tostring(t)) end end end if (type(t)=="table") then print(tostring(t).." {") sub_print_r(t," ") print("}") else sub_print_r(t," ") end print() end -- the script will block here until the window closes local create = PlaneWindow:showWindow()