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
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
|
|
)
|