You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

511 lines
24 KiB
Plaintext

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
)