-- -- create a Plane mesh with Lua. -- -- This script create a node-group with a plane mesh, a diffuse material and a placement node -- @author Beppe "bepeg4d" Gullotta with the great help of Thomas "stratified" Loockx local version = "1.0" --GUI-- --Dimension-- -- create the width label local noteLbl1 = octane.gui.create { type = octane.gui.componentType.LABEL, text = "width =", width = 60, } -- create a numeric field for the width Plane dimension local num1 = octane.gui.create { type = octane.gui.componentType.NUMERIC_BOX, minValue = 0, name = "boxX", width = 60, enable = true, value = 1, maxValue = 1000000 } -- create the height label local noteLbl2 = octane.gui.create { type = octane.gui.componentType.LABEL, text = " height =", width = 60, } -- create a numeric field for the height Plane dimension local num2 = octane.gui.create { type = octane.gui.componentType.NUMERIC_BOX, minValue = 0, name = "boxY", width = 60, enable = true, value = 1, maxValue = 1000000 } -- create the meter label local noteLbl4 = octane.gui.create { type = octane.gui.componentType.LABEL, text = "m", width = 20, } -- create the axis label local noteLbl5 = octane.gui.create { type = octane.gui.componentType.LABEL, text = "axis", width = 35, } -- create a combo-box to choose the axis of the plane local axisCombo = octane.gui.create { type = octane.gui.componentType.COMBO_BOX, --text = "axis", width = 50, height = 20, items = { "XY", "YZ", "XZ" }, selectedIx = 1 } -- for layouting all the elements of the Plane dimensions we use a group local dimGrp = octane.gui.create { type = octane.gui.componentType.GROUP, text = "Plane dimensions", rows = 1, cols = 7, children = { noteLbl1, num1, noteLbl2, num2, noteLbl4, noteLbl5, axisCombo }, padding = { 2 }, inset = { 5 }, } -- TEXT -- -- lets create a text label local textLbl1 = octane.gui.createLabel { text = "Create a Plane object with the desired width, height and axis.", width = 370, } local textLbl2 = octane.gui.createLabel { text = "Attention - The scene must to be saved before running the script.", width = 370, textColour = { 224, 224, 0, 255 } } local textD = octane.gui.createLabel { text = "", width = 370, } local parentPrjc = octane.project.getCurrentProject() local parentPath = octane.file.getParentDirectory(parentPrjc) local exists = octane.file.isAbsolute(parentPrjc) if exists == true then textD = textLbl1 elseif exists ~= true then textD = textLbl2 end -- for layouting the text we use a group local textGrp = octane.gui.create { type = octane.gui.componentType.GROUP, text = "", rows = 1, cols = 1, children = { textD, }, padding = { 2 }, inset = { 2 }, } -- EMISSION -- -- create the checkbox for activate/deactivate the emission node local emitCheckBox = octane.gui.create { type = octane.gui.componentType.CHECK_BOX, text = "activate/deactivate the emission node.", width = 240, checked = false, } -- BUTTONS -- local createButton = octane.gui.create { type = octane.gui.componentType.BUTTON, text = "Create", width = 120, height = 20, tooltip = "Create the Plane object", } local exitButton = octane.gui.create { type = octane.gui.componentType.BUTTON, text = "Exit", width = 120, height = 20, tooltip = "Exit from the script without creating the Plane", } local buttonGrp = octane.gui.create { type = octane.gui.componentType.GROUP, text = "", rows = 1, cols = 2, children = { createButton, exitButton}, padding = { 5 }, border = false, } -- group that layouts the other groups local layoutGrp = octane.gui.create { type = octane.gui.componentType.GROUP, text = "", rows = 4, cols = 1, children = { textGrp, dimGrp, emitCheckBox, buttonGrp, }, centre = true, padding = { 2 }, border = false, debug = false, -- true to show the outlines of the group, handy } -- window that holds all components local PlaneWindow = octane.gui.create { type = octane.gui.componentType.WINDOW, text = "Create a Plane v"..version, children = { layoutGrp }, width = layoutGrp:getProperties().width, height = layoutGrp:getProperties().height, } -- END GUI CODE -- -- enable all the ui num1 :updateProperties{ enable = true } axisCombo :updateProperties{ enable = true } emitCheckBox :updateProperties{ enable = true } createButton :updateProperties{ enable = false} exitButton :updateProperties{ enable = true } --button functions local function createGraph() PlaneWindow:closeWindow(true) end local function exitAndDontCreateGraph() PlaneWindow:closeWindow(false) end -- global variable that holds the input path INS_PATH = nil parentPrjc = octane.project.getCurrentProject() print (parentPrjc) parentPath = octane.file.getParentDirectory(parentPrjc) print (parentPath) local exists = octane.file.isAbsolute(parentPrjc) -- callback handling the GUI elements local function guiCallback(component, event) -- FILE SAVING -- if exists == true then xyz = "" if axisCombo.selectedIx == 1 then xyz = "XY" elseif axisCombo.selectedIx == 2 then xyz = "YZ" else xyz = "XZ" end print (xyz) INS_PATH = octane.file.join(parentPath .. "/assets/Plane_" .. xyz .. ".obj") createButton:updateProperties{ enable = true } exitButton:updateProperties{ enable = true } print("Plane path: ", INS_PATH) else createButton:updateProperties{ enable = false } exitButton:updateProperties{ enable = true } INS_PATH = nil print ("Please, save the scene first") end -- close -- if component == createButton then createGraph() elseif component == exitButton then exitAndDontCreateGraph() print ("ciao") elseif component == PlaneWindow then --when the window closes, print something if event == octane.gui.eventType.WINDOW_CLOSE then print ("Happy rendering :-)") end end end -- hookup the callback with all the GUI elements num1 :updateProperties { callback = guiCallback } axisCombo :updateProperties { callback = guiCallback } emitCheckBox :updateProperties { callback = guiCallback } createButton :updateProperties { callback = guiCallback } exitButton :updateProperties { callback = guiCallback } PlaneWindow :updateProperties { callback = guiCallback } -- the script will block here until the window closes local create = PlaneWindow:showWindow() -- stop the script if the user clicked the exit button if not create then return end --Create the Plane-- params = {} params.type = octane.GT_STANDARD params.name = ("Plane" .. xyz) params.position = {100, 100} -- creates the "macro" node graph, ie. root for all other nodes root = octane.nodegraph.create(params) if axisCombo.selectedIx == 1 then -- vertices for the Plane XY vertices = { { (num1.value/2) , -(num2.value/2) , (0)} , { (num1.value/2) , (num2.value/2) , (0)} , { -(num1.value/2) , (num2.value/2) , (0)} , { -(num1.value/2) , -(num2.value/2) , (0)} , } elseif axisCombo.selectedIx == 2 then -- vertices for the Plane YZ vertices = { { (0) , -(num2.value/2) , (num1.value/2)} , { (0) , -(num2.value/2) , -(num1.value/2)} , { (0) , (num2.value/2) , -(num1.value/2)} , { (0) , (num2.value/2) , (num1.value/2)} , } elseif axisCombo.selectedIx == 3 then -- vertices for the Plane XZ vertices = { { (num1.value/2) , (0) , -(num2.value/2)} , { -(num1.value/2) , (0) , -(num2.value/2)} , { -(num1.value/2) , (0) , (num2.value/2)} , { (num1.value/2) , (0) , (num2.value/2)} , } end -- 4 vertices per poly (each face is a quad) verticesPerPoly = { 4, -- face } -- NOTE: indices are 0-based! polyVertexIndices = { 0 , 1 , 2 , 3 , -- face } -- material names materialNames = { "material" } -- NOTE: indices are 0-based! polyMaterialIndices = { 0 } -- create the actual mesh node, at this point the mesh node isn't usable yet! meshNode = octane.node.create{ type=octane.NT_GEO_MESH , name= ("plane_".. xyz), graphOwner=root, position={ 100, 100 } } -- set up the geometry attributes. we shouldn't evaluate them immediately! meshNode:setAttribute(octane.A_VERTICES , vertices , false) meshNode:setAttribute(octane.A_VERTICES_PER_POLY , verticesPerPoly , false) meshNode:setAttribute(octane.A_POLY_VERTEX_INDICES , polyVertexIndices , false) meshNode:setAttribute(octane.A_MATERIAL_NAMES , materialNames , false) meshNode:setAttribute(octane.A_POLY_MATERIAL_INDICES, polyMaterialIndices, false) -- all is set up correctly, now we can evaluate the geometry meshNode:evaluate() meshNode:exportToFile(parentPath) print("save out mesh to file: ", meshNode:getAttribute(octane.A_FILENAME)) -- get the position of the selected node in the graph editor pos = meshNode.position -- create a placement node and connect the mesh with it local placeOb = octane.node.create { type =octane.NT_GEO_PLACEMENT, name = "Plane-Pos", position ={pos[1]-15, pos[2]+55}, graphOwner =root } placeOb:connectTo(octane.P_GEOMETRY, meshNode) -- create a transform node and connect to the placement node local inTansOb = octane.node.create { type = octane.NT_IN_TRANSFORM, name = "Plane-PSR", position = {pos[1]-75, pos[2]+25}, graphOwner = root } placeOb:connectTo(octane.P_TRANSFORM, inTansOb) -- create a transform node and connect to the placement node local tansOb = octane.node.create { type = octane.NT_TRANSFORM_VALUE, pinOwned = true, pinOwnerNode = inTansOb, pinOwnerId = octane.P_INPUT, } -- create a geometry output node and connect to the placement node local fogOut = octane.node.create { type =octane.NT_OUT_GEOMETRY, name = "Plane-out", position ={pos[1]-30, pos[2]+110}, graphOwner =root } fogOut:connectTo(octane.P_INPUT, placeOb) -- create a in-material node and connect the mesh with it local inMat = octane.node.create { type =octane.NT_IN_MATERIAL, name = "Plane-mat", position ={pos[1], pos[2]-50}, graphOwner =root } -- Connect the in-material node with the material pin of the mesh node meshNode:connectToIx(1, inMat) -- create a diffuse material pin matNode = octane.node.create { type = octane.NT_MAT_DIFFUSE, name = "PlaneMat", pinOwned = true, pinOwnerNode = inMat, pinOwnerId=octane.P_INPUT } if emitCheckBox.checked == true then -- create a blackbody node pin emitNode = octane.node.create { type = octane.NT_EMIS_BLACKBODY, name = "Emit", pinOwned = true, pinOwnerNode = matNode, pinOwnerId = octane.P_EMISSION, } end -- to make it a bit tidier, just unfold everything root:unfold()