macroScript AutoBakeGLB_V45_2 category:"Paulo Tools" tooltip:"Bake v45.2" buttonText:"BAKE v45.2" ( -- Close existing dialogs try(destroyDialog rolloutBakeGLB)catch() -- STRUCTURE TO HOLD DATA struct BakeItemData ( node, listItem ) rollout rolloutBakeGLB "Auto-Bake Manager V45.2" width:600 height:860 ( -- HEADER label lblTitle "VR4LIFE" align:#center height:30 css:"font-size:30px; font-weight:bold" label lblVer "v45.2 (Fix Calc)" align:#center height:20 css:"font-size:12px; color:gray" offset:[0,-5] -- ==================================================================================== -- 1. CONFIGURATION GROUP -- ==================================================================================== group "1. Output & Tools" ( edittext edtPath "Folder:" text:"" fieldWidth:360 align:#left across:2 button btnBrowse "..." width:30 height:18 align:#right offset:[0,-2] edittext edtName "GLB Name:" text:"Scene_Exported" fieldWidth:200 align:#left across:2 button btnOpenFolder "Open Folder" width:120 height:22 align:#right button btnFix "FIX GEOMETRY (Explode & Poly)" width:280 height:30 css:"background-color:#ffcccc; font-weight:bold" across:2 align:#left button btnCheck "CHECK & ADD UNWRAP (Ch. 2)" width:280 height:30 align:#right spinner spnPolyPercent "Reduc. %:" range:[1.0, 100.0, 50.0] type:#float fieldWidth:50 across:3 align:#left offset:[0,4] spinner spnPolyLimit "Max Verts:" range:[100, 1000000, 40000] type:#integer fieldWidth:60 align:#left offset:[0,4] button btnReduce "REDUCE (ProOptimizer)" width:160 height:25 align:#right button btnInspect "INSPECT UV (Select 1)" width:580 height:30 align:#center ) group "2. Render Configuration" ( radiobuttons rdoEngine labels:#("V-Ray", "Corona", "Arnold") default:1 columns:3 across:2 align:#left spinner spnSize "Size:" range:[128, 8192, 512] type:#integer fieldwidth:50 align:#right spinner spnPasses "Pass Limit:" range:[1, 999, 5] type:#integer fieldwidth:50 across:2 align:#left checkbox chkUseNative "Use F10 Settings (Ignore Limits)" checked:false offset:[0, 4] align:#right button btnConfig "Open F10 Config" width:280 height:25 across:2 align:#left checkbox chkShowVFB "Show Render Window" checked:false offset:[0, 4] align:#right radiobuttons rdoFinalUV labels:#("UV 1 (Replace)", "UV 2 (Multi-UV)") default:1 columns:2 across:2 align:#left checkbox chkAutoFlatten "Re-Flatten + Pack" checked:true align:#right checkbox chkOverwrite "Overwrite Existing Files" checked:false align:#center css:"color:red" ) -- ==================================================================================== -- 2. LIST MANAGER -- ==================================================================================== dotNetControl lvObjects "System.Windows.Forms.ListView" width:580 height:350 pos:[10, 350] -- button btnAddSel "POST SELECTION TO LIST" width:580 height:40 pos:[10, 710] css:"font-weight:bold" -- button btnClear "CLEAR LIST" width:280 height:40 pos:[310, 710] progressbar pbProg "Progress:" color:green height:20 width:580 pos:[10, 760] button btnBakeChecked "BAKE CHECKED ITEMS" width:580 height:50 pos:[10, 790] css:"font-weight:bold; font-size:14px; background-color:#ccffcc" button btnExportSel "EXPORT SELECTED (1+ Obj)" width:580 height:40 pos:[10, 850] label lblStatus "Ready" pos:[10, 900] width:580 align:#center -- LOCAL VARIABLES -- ==================================================================================== local bakeItems = #() local userCancelled = false local ignoreCheckEvent = false -- ==================================================================================== -- HELPER FUNCTIONS -- ==================================================================================== fn InitListView = ( lvObjects.View = (dotNetClass "System.Windows.Forms.View").Details lvObjects.FullRowSelect = true lvObjects.GridLines = true lvObjects.CheckBoxes = true lvObjects.MultiSelect = true lvObjects.Columns.Add "Object Name" 280 lvObjects.Columns.Add "Status" 120 lvObjects.Columns.Add "Polys" 80 ) fn UpdateItemStatus item status colorCode = ( item.SubItems.Item[1].Text = status item.ForeColor = colorCode -- lvObjects.Refresh() -- Refreshing every item causes flicker, max handles it better usually ) fn AutoPackUV obj channel = ( try ( max modify mode select obj modPanel.addModToSelection (Unwrap_UVW ()) ui:on theMod = obj.modifiers[#Unwrap_UVW] if theMod != undefined then ( theMod.setMapChannel channel theMod.flattenMap 45.0 #() 0.01 true 0 true true theMod.setTVSubObjectMode 3 theMod.selectFaces #{1..(theMod.numberPolygons())} theMod.pack 1 0.001 true false true collapseStack obj ) ) catch ( print ("Pack UV Error: " + obj.name) ) ) fn ExportToGLB objs path = ( if objs.count == 0 then return false select objs -- MANUAL EXPORT DIALOG (File Picker) local filename = getSaveFileName caption:"Export GLB" types:"GL Transmission Format (*.glb)|*.glb|All|*.*" initialDir:path filename:edtName.text if filename != undefined then ( try ( exportFile filename selectedOnly:true using:gltf_export; return true ) catch ( messageBox "Export Cancelled or Error."; return false ) ) return false ) fn CloseAnnoyingWindows = ( try ( local desktopHWND = windows.getDesktopHWND() local children = windows.getChildrenHWND desktopHWND local targets = #("Corona", "V-Ray", "Buffer", "Render", "Warning", "Error") for output in children do ( local hwnd = output[1] local title = output[5] for t in targets do ( if (matchPattern title pattern:("*" + t + "*") ignoreCase:true) then ( try ( UIAccessor.CloseDialog hwnd ) catch () -- try ( windows.sendMessage hwnd 0x0010 0 0 ) catch () -- Alternative Close ) ) ) ) catch () ) -- ==================================================================================== -- CORE LOGIC: BAKE ONE ITEM -- ==================================================================================== fn BakeOneObject objData = ( obj = objData.node item = objData.listItem -- Update UI item.EnsureVisible() UpdateItemStatus item "Baking..." (dotNetClass "System.Drawing.Color").OrangeRed -- Validate if (isValidNode obj == false) then ( UpdateItemStatus item "Deleted" (dotNetClass "System.Drawing.Color").Red; return false) select obj max modify mode try ( ------------------------------------------------------------------------- -- 1. PREPARE GEOMETRY & UV ------------------------------------------------------------------------- if (classof obj != Editable_Poly) then convertToPoly obj needNewUV = true if (chkAutoFlatten.checked == false) then ( if (polyop.getMapSupport obj 2) then needNewUV = false else ( print "No UVs found on Channel 2. Auto-generating..." ) ) if needNewUV then ( AutoPackUV obj 2; collapseStack obj ) ------------------------------------------------------------------------- -- 2. PREPARE BAKE ELEMENTS ------------------------------------------------------------------------- obj.INodeBakeProperties.removeAllBakeElements() be = undefined fileExt = ".jpg" -- Default -- Engine Detection curRen = renderers.current isCorona = matchPattern (curRen as string) pattern:"*Corona*" isVRay = matchPattern (curRen as string) pattern:"*V_Ray*" isArnold = matchPattern (curRen as string) pattern:"*Arnold*" case rdoEngine.state of ( 1: ( try ( be = VRayCompleteMap() ) catch ( ) ) 2: ( try ( be = Corona_Beauty() ) catch ( try ( be = CShading_Beauty() ) catch ( ) ) ) 3: ( be = CompleteMap() ) ) if be == undefined then be = CompleteMap() be.outputSzX = spnSize.value be.outputSzY = spnSize.value be.fileType = fileExt -- SMART SKIP: Remove timestamp to allow stable file checking be.filename = (edtPath.text + obj.name + "_Baked" + fileExt) fileExists = doesFileExist be.filename skipRender = (fileExists) and (chkOverwrite.checked == false) if skipRender then ( UpdateItemStatus item "Skipped (Exists)" (dotNetClass "System.Drawing.Color").Blue ) else ( -- PREPARE RENDER obj.INodeBakeProperties.addBakeElement be obj.INodeBakeProperties.bakeEnabled = true obj.INodeBakeProperties.bakeChannel = 2 -- HARD ENFORCE CORONA LIMITS if isCorona and (chkUseNative.checked == false) then ( try(renderers.current.pass_limit = spnPasses.value; renderers.current.time_limit = 0; renderers.current.noise_level_limit = 0.0)catch() ) wasCancelled = false -- RENDER EXECUTION try ( render rendertype:#bakeSelected vfb:chkShowVFB.checked progressBar:true quiet:true outputSize:[spnSize.value, spnSize.value] cancelled:&wasCancelled if wasCancelled then userCancelled = true ) catch ( userCancelled = true print "Render Error/Cancel Caught." ) if userCancelled then ( UpdateItemStatus item "Cancelled" (dotNetClass "System.Drawing.Color").Red; return false ) ) ------------------------------------------------------------------------- -- 4. MATERIAL CREATION ------------------------------------------------------------------------- newMat = PhysicalMaterial() newMat.name = (obj.name + "_Baked_Mat") newMat.base_color = color 255 255 255 newMat.roughness = 1.0 newMat.emission = 0.0 -- Lit newMat.emission_color = color 0 0 0 -- Wait for File Logic fileFound = false if (skipRender) then ( fileFound = true -- File existed, we verified it before ) else ( -- We rendered, so we wait/verify waitForFile = 0 while (waitForFile < 50) and (fileFound == false) do ( if doesFileExist be.filename then fileFound = true else ( sleep 0.1; waitForFile += 1 ) ) ) if fileFound then ( bmpTex = BitmapTexture filename:be.filename if rdoFinalUV.state == 2 then bmpTex.coords.mapChannel = 2 else bmpTex.coords.mapChannel = 1 newMat.base_color_map = bmpTex showTextureMap newMat newMat.base_color_map on ) else ( print ("ERROR: Texture file not found: " + be.filename) UpdateItemStatus item "Tex Missing" (dotNetClass "System.Drawing.Color").Red return false ) ------------------------------------------------------------------------- -- 5. FINAL CLEANUP ------------------------------------------------------------------------- CloseAnnoyingWindows() -- Kill windows (V43) sleep 1.0 -- Breathing room obj.material = newMat if rdoFinalUV.state == 1 then ( channelInfo.CopyChannel obj 3 2 channelInfo.PasteChannel obj 3 1 channelInfo.ClearChannel obj 2 collapseStack obj ) else ( collapseStack obj ) UpdateItemStatus item "DONE" (dotNetClass "System.Drawing.Color").Green return true ) catch ( print ("Critical Error on Object: " + obj.name) print (getCurrentException()) UpdateItemStatus item "Error" (dotNetClass "System.Drawing.Color").Red return false ) ) -- ==================================================================================== -- EVENT HANDLERS -- ==================================================================================== on rolloutBakeGLB open do ( defaultPath = maxFilePath + "_BAKED\\" if maxFilePath == "" then defaultPath = "C:\\Temp_Bake\\" edtPath.text = defaultPath InitListView() spnPasses.enabled = (not chkUseNative.checked) ) on lvObjects ItemChecked arg do ( if ignoreCheckEvent then return () if arg.Item.Checked then ( ignoreCheckEvent = true -- Uncheck everyone else for i = 0 to lvObjects.Items.Count-1 do ( if lvObjects.Items.Item[i] != arg.Item then lvObjects.Items.Item[i].Checked = false ) ignoreCheckEvent = false ) ) on lvObjects ItemSelectionChanged arg do ( if arg.IsSelected then ( -- Find node in struct array local selectedNode = undefined for b in bakeItems do ( if b.listItem == arg.Item then ( selectedNode = b.node exit ) ) if isValidNode selectedNode then ( select selectedNode -- Optional: max zoomext selected ) ) ) on chkUseNative changed state do ( spnPasses.enabled = (not state) ) on btnBrowse pressed do ( newPath = getSavePath caption:"Save to:" initialDir:edtPath.text if newPath != undefined then edtPath.text = (newPath + "\\") ) on btnOpenFolder pressed do ( ShellLaunch edtPath.text "" ) on btnConfig pressed do ( renderSceneDialog.open() ) on btnFix pressed do ( undo "Fix Geometry" on ( local sel = selection as array if sel.count == 0 then (messageBox "Select objects in viewport first!"; return false) local groupHeads = for o in sel where isGroupHead o collect o for g in groupHeads do ( if isValidNode g then explodeGroup g ) -- Re-select max modify mode local finalSel = selection as array -- AUTO-POPULATE LIST V24 (ADDITIVE) local countAdded = 0 for obj in finalSel do ( -- STRICT FILTER: Geometry Only, No Lights, No Cameras, No Helpers if (isValidNode obj) and (superclassof obj == GeometryClass) and (classof obj != TargetObject) and (isGroupHead obj == false) then ( -- Always Ensure Poly (Re-Fix) if canConvertTo obj Editable_Poly then convertToPoly obj -- Check for Duplicates local isDuplicate = false for b in bakeItems do ( if b.node == obj then isDuplicate = true ) if (not isDuplicate) then ( li = lvObjects.Items.Add obj.name li.SubItems.Add "Pending" -- Use getPolygonCount for safety (returns array: #(faces, verts)) local fCount = (getPolygonCount obj)[1] li.SubItems.Add (fCount as string) li.Checked = false append bakeItems (BakeItemData node:obj listItem:li) countAdded += 1 ) ) ) if countAdded > 0 then messageBox (countAdded as string + " Object(s) Added to List.") else messageBox "Geometry Re-Fixed (No new items added)." ) ) on btnCheck pressed do ( undo "Check UVs" on ( objsToCheck = selection as array local countAdded = 0 max modify mode for obj in objsToCheck do ( if (superclassof obj == GeometryClass and isGroupHead obj == false) then ( if (classof obj != Editable_Poly) then convertToPoly obj -- Check if modifier already exists (Ignore internal data support) local hasModifier = false for m in obj.modifiers do ( if classof m == Unwrap_UVW then hasModifier = true ) if (not hasModifier) then ( select obj modPanel.addModToSelection (Unwrap_UVW ()) ui:on obj.modifiers[#Unwrap_UVW].setMapChannel 2 countAdded += 1 ) ) ) if countAdded > 0 then messageBox ("Unwraps Added to Channel 2: " + countAdded as string) else messageBox "Unwrap Modifier already present on selected object(s)." ) ) on btnReduce pressed do ( undo "Reduce Polys" on ( local sel = selection as array if sel.count == 0 then (messageBox "Select objects first!"; return false) max modify mode for obj in sel do ( if (superclassof obj == GeometryClass) and (isGroupHead obj == false) then ( if (classof obj != Editable_Poly) then convertToPoly obj select obj -- Ensure context local mods = ProOptimizer() addModifier obj mods mods.KeepUV = true -- Keep Textures! Keep UV Boundaries off by default for smooth mods.OptimizationMode = 1 -- Protect Borders mods.Calculate = true -- Trigger Calculation Explicitly -- Use Percentage AFTER Calculation mods.VertexPercent = spnPolyPercent.value -- Update List Count if compatible -- Force refresh of geometry for count local newFCount = (getPolygonCount obj)[1] for b in bakeItems do ( if b.node == obj then ( b.listItem.SubItems.Item[2].Text = (newFCount as string) ) ) ) ) messageBox "ProOptimizer Applied (User Settings) \u0026 List Updated." ) ) on btnInspect pressed do ( if selection.count != 1 then (messageBox "Select EXACTLY ONE object."; return false) obj = selection[1] max modify mode if (isGroupHead obj) then (messageBox "It is a group! Use Fix Geometry."; return false) theMod = undefined for m in obj.modifiers do ( if classof m == Unwrap_UVW then theMod = m ) if theMod != undefined then ( modPanel.setCurrentObject theMod theMod.setMapChannel 2 theMod.flattenMap 45.0 #() 0.01 true 0 true true theMod.setTVSubObjectMode 3 theMod.selectFaces #{1..(theMod.numberPolygons())} theMod.pack 1 0.001 true false true try ( theMod.edit() ) catch () ) else ( messageBox "No Unwrap found. Use CHECK & ADD first." ) ) on btnBakeChecked pressed do ( userCancelled = false -- 1. Setup Render Limits GLOBALLY curRen = renderers.current isCorona = matchPattern (curRen as string) pattern:"*Corona*" isVRay = matchPattern (curRen as string) pattern:"*V_Ray*" isArnold = matchPattern (curRen as string) pattern:"*Arnold*" makeDir edtPath.text -- Store old logic similar to V19... -- For brevity, we assume the BakeOneObject handles the per-object enforcement -- But we should disable global time limits once here if not native undo off ( suspendEditing() for b in bakeItems do ( if userCancelled then exit if b.listItem.Checked then ( -- Check if already done? Optional. For now we force re-bake if checked. success = BakeOneObject b ) ) resumeEditing() completeRedraw() ) lblStatus.text = "Finished!" ) on btnExportSel pressed do ( if selection.count >= 1 then ( local exportObj = selection as array ExportToGLB exportObj edtPath.text messageBox "Export Process Initiated." ) else ( messageBox "Please select AT LEAST ONE object in the viewport." ) ) ) createDialog rolloutBakeGLB height:930 )