@ -11,22 +11,13 @@ def get_vdenoise_path():
if os . path . exists ( p ) : return f ' " { p } " '
if os . path . exists ( p ) : return f ' " { p } " '
return " vdenoise.exe "
return " vdenoise.exe "
def deep_log_and_kill ( ) :
try :
time . sleep ( 0.5 ) ; tgts = [ " 3d66 " , " V-Ray " , " Buffer " , " RGBA " , " Render " ]
for w in rt . windows . getChildrenHWND ( 0 ) :
for t in tgts :
if t . lower ( ) in str ( w [ 4 ] ) . lower ( ) : rt . windows . sendMessage ( w [ 0 ] , 0x0010 , 0 , 0 ) ; rt . windows . sendMessage ( w [ 0 ] , 0x0002 , 0 , 0 )
except : pass
def load_bake_elements ( ui ) :
def load_bake_elements ( ui ) :
ui . cmb_bake_elem . clear ( )
ui . cmb_bake_elem . clear ( )
found = [ " CompleteMap " , " VRayCompleteMap " , " Corona_Beauty " , " CShading_Beauty " ]
found = [ " CompleteMap " , " VRayCompleteMap " , " Corona_Beauty " , " CShading_Beauty " ]
try :
try :
r_list = rt . execute ( " for c in bake_elements.classes collect (c as string) " )
r_list = rt . execute ( " for c in bake_elements.classes collect (c as string) " )
if r_list :
for c in r_list :
for c in r_list :
if str ( c ) not in found : found . append ( str ( c ) )
if str ( c ) not in found : found . append ( str ( c ) )
except : pass
except : pass
ui . cmb_bake_elem . addItems ( sorted ( list ( set ( found ) ) ) )
ui . cmb_bake_elem . addItems ( sorted ( list ( set ( found ) ) ) )
try :
try :
@ -45,332 +36,428 @@ def load_selection(ui):
tl . sort ( key = lambda x : x [ ' poly ' ] , reverse = True )
tl . sort ( key = lambda x : x [ ' poly ' ] , reverse = True )
for d in tl :
for d in tl :
i = QtWidgets . QTreeWidgetItem ( [ d [ ' name ' ] , " Pronto " , f " { d [ ' poly ' ] : , } " , " " , " " ] )
i = QtWidgets . QTreeWidgetItem ( [ d [ ' name ' ] , " Pronto " , f " { d [ ' poly ' ] : , } " , " " , " " ] )
i . setFlags ( i . flags ( ) | QtCore . Qt . ItemIsUserCheckable ) ; i . setCheckState ( 0 , QtCore . Qt . Checked )
i . setFlags ( i . flags ( ) | QtCore . Qt . ItemIsUserCheckable )
ui . tree . addTopLevelItem ( i ) ; ui . bake_items . append ( { ' name ' : d [ ' name ' ] , ' item ' : i } )
i . setCheckState ( 0 , QtCore . Qt . Checked )
ui . pb . setFormat ( f " Carregados: { len ( tl ) } " ) ; ui . pb . setValue ( 0 ) ; ui . upd_res_col ( )
ui . tree . addTopLevelItem ( i )
ui . bake_items . append ( { ' name ' : d [ ' name ' ] , ' item ' : i } )
ui . pb . setFormat ( f " Carregados: { len ( tl ) } " )
ui . pb . setValue ( 0 )
ui . upd_res_col ( )
def attach_grouped_objects ( ui , from_auto = False ) :
def attach_grouped_objects ( ui , from_auto = False ) :
thr = ui . spn_max_sz . value ( )
ui . pb . setFormat ( " Fundindo grupos inteiros... " )
ui . pb . setFormat ( " Filtando e Fundindo grupos... " ) ; QtWidgets . QApplication . processEvents ( )
QtWidgets . QApplication . processEvents ( )
ms = f """ (
ms = """ (
local act = 0 ; local new_objs = #(); local orig_sel = selection as array
local act = 0 ; local new_objs = #(); local orig_sel = selection as array; local loose = for o in orig_sel where not isGroupHead o and not isGroupMember o collect o; local heads = for o in orig_sel where isGroupHead o collect o
local loose = for o in orig_sel where not isGroupHead o and not isGroupMember o collect o
for h in heads do ( local valid_cg = for c in h . children where superclassof c == GeometryClass and classof c != TargetObject collect c ; if valid_cg . count > 0 do ( local b = valid_cg [ 1 ] ; if not isKindOf b Editable_Poly do try ( convertToPoly b ) catch ( ) ; if isKindOf b Editable_Poly do ( for i = 2 to valid_cg . count do ( local n = valid_cg [ i ] ; if not isKindOf n Editable_Poly do try ( convertToPoly n ) catch ( ) ; if isKindOf n Editable_Poly do try ( polyOp . attach b n ) catch ( ) ) ; b . name = h . name ; setGroupMember b false ; append new_objs b ; act + = 1 ) ) ; try ( delete h ) catch ( ) )
local heads = for o in orig_sel where isGroupHead o collect o
local limit = { thr }
for h in heads do (
local cg = for c in h . children where superclassof c == GeometryClass and classof c != TargetObject collect c
local valid_cg = #()
- - O SEGURANÇA DA BALADA : Expulsa quem for maior que o limite
for c in cg do (
local md = amax #(abs(c.max.x - c.min.x), abs(c.max.y - c.min.y), abs(c.max.z - c.min.z))
if md > limit then (
setGroupMember c false
append loose c - - Joga pros VIPs soltos
) else (
append valid_cg c - - Fica pra ser fundido
)
)
if valid_cg . count > 0 do (
local b = valid_cg [ 1 ] ; if not isKindOf b Editable_Poly do try ( convertToPoly b ) catch ( )
if isKindOf b Editable_Poly do (
for i = 2 to valid_cg . count do ( local n = valid_cg [ i ] ; if not isKindOf n Editable_Poly do try ( convertToPoly n ) catch ( ) ; if isKindOf n Editable_Poly do try ( polyOp . attach b n ) catch ( ) )
b . name = h . name ; setGroupMember b false ; append new_objs b ; act + = 1
)
)
try ( delete h ) catch ( )
)
local final_sel = loose ; for no in new_objs do append final_sel no ; if final_sel . count > 0 do select final_sel ; act
local final_sel = loose ; for no in new_objs do append final_sel no ; if final_sel . count > 0 do select final_sel ; act
) """
) """
try :
try :
act = rt . execute ( ms )
act = rt . execute ( ms )
load_selection ( ui )
load_selection ( ui )
if not from_auto :
if not from_auto :
if act > 0 : QtWidgets . QMessageBox . information ( ui , " Atlas Welder" , f " Sucesso! { act } Grupos processados. \n Objetos gigantes foram ejetados do grupo com segurança! " )
if act > 0 : QtWidgets . QMessageBox . information ( ui , " Sucesso " , f " { act } Grupos fundidos. " )
else : QtWidgets . QMessageBox . information ( ui , " Aviso " , " Nenhum Grupo encontrado na seleção ." )
else : QtWidgets . QMessageBox . information ( ui , " Aviso " , " Nenhum Grupo encontrado. " )
except Exception as e : print ( " Erro Solda: " , e )
except Exception as e : print ( " Erro Solda: " , e )
ui . pb . setValue ( 0 ) ; ui . pb . setFormat ( " Pronto " )
ui . pb . setValue ( 0 ) ; ui . pb . setFormat ( " Pronto " )
def super_attach_objects ( ui , from_auto = False ) :
ui . pb . setFormat ( " Super Solda VR... " )
QtWidgets . QApplication . processEvents ( )
ms = """ ( local sel = for o in selection where superclassof o == GeometryClass and classof o != TargetObject collect o; if sel.count > 1 do ( local b = sel[1]; if not isKindOf b Editable_Poly do try(convertToPoly b)catch(); if isKindOf b Editable_Poly do ( for i = 2 to sel.count do ( local n = sel[i]; if not isKindOf n Editable_Poly do try(convertToPoly n)catch(); if isKindOf n Editable_Poly do try(polyOp.attach b n)catch() ); b.name = uniqueName " VR_Bloco_Fundido " ; select b ) ); sel.count ) """
try :
act = rt . execute ( ms )
load_selection ( ui )
if not from_auto :
if act > 1 : QtWidgets . QMessageBox . information ( ui , " Sucesso " , f " { act } objetos fundidos. " )
else : QtWidgets . QMessageBox . information ( ui , " Aviso " , " Selecione pelo menos 2 objetos. " )
except Exception as e : print ( " Erro Super Solda: " , e )
ui . pb . setValue ( 0 ) ; ui . pb . setFormat ( " Pronto " )
def optimize_geometry ( ui ) :
def optimize_geometry ( ui ) :
sp = ui . spn_pct . value ( ) ; tg = ui . spn_min_poly . value ( ) ; tgs = ui . get_processable_items ( ) ; tot = len ( tgs )
sp = ui . spn_pct . value ( )
ui . pb . setMaximum ( tot ) ; ui . pb . setValue ( 0 ) ; rt . execute ( " max modify mode " )
tg = ui . spn_min_poly . value ( )
tgs = ui . get_processable_items ( )
tot = len ( tgs )
ui . pb . setMaximum ( tot )
ui . pb . setValue ( 0 )
rt . execute ( " max modify mode " )
for i , d in enumerate ( tgs ) :
for i , d in enumerate ( tgs ) :
if ui . _is_cancelled : break
if ui . _is_cancelled : break
ui . pb . setFormat ( f " Opt ( { i + 1 } / { tot } ): { d [ ' name ' ] } ... " ) ; ui . pb . setValue ( i ) ; QtWidgets . QApplication . processEvents ( )
ui . pb . setFormat ( f " Opt ( { i + 1 } / { tot } ): { d [ ' name ' ] } ... " )
ui . pb . setValue ( i )
QtWidgets . QApplication . processEvents ( )
o = rt . getNodeByName ( d [ ' name ' ] )
o = rt . getNodeByName ( d [ ' name ' ] )
if o :
if o :
try :
try :
cp = rt . getPolygonCount ( o ) [ 0 ] if rt . canConvertTo ( o , rt . Editable_Poly ) else 0
cp = rt . getPolygonCount ( o ) [ 0 ] if rt . canConvertTo ( o , rt . Editable_Poly ) else 0
if cp < = tg : d [ ' item ' ] . setText ( 1 , " Já < Meta " )
if cp < 50 :
elif cp < 50 : d [ ' item ' ] . setText ( 1 , " Geo Base " )
d [ ' item ' ] . setText ( 1 , " Geo Base " )
else :
else :
rt . select ( o ) ; p = 0
rt . select ( o )
while cp > tg and cp > = 50 and p < 20 :
if not rt . isKindOf ( o , rt . Editable_Poly ) :
if not rt . isKindOf ( o , rt . Editable_Poly ) : rt . convertTo ( o , rt . Editable_Poly )
rt . convertTo ( o , rt . Editable_Poly )
opt = rt . ProOptimizer ( ) ; rt . addModifier ( o , opt ) ; opt . KeepTextures = False ; opt . KeepNormals = False ; opt . Calculate = True ; opt . VertexPercent = sp
rt . collapseStack ( o )
opt = rt . ProOptimizer ( )
if not rt . isKindOf ( o , rt . Editable_Poly ) : rt . convertTo ( o , rt . Editable_Poly )
rt . addModifier ( o , opt )
opt . KeepTextures = True
opt . KeepNormals = True
opt . KeepBorders = True
opt . LockMat = True
opt . Calculate = True
current_pct = 100.0
p = 0
while True :
if ui . _is_cancelled : break
current_pct = current_pct * ( sp / 100.0 )
opt . VertexPercent = current_pct
rt . redrawViews ( )
QtWidgets . QApplication . processEvents ( )
np = rt . getPolygonCount ( o ) [ 0 ]
np = rt . getPolygonCount ( o ) [ 0 ]
if np > = cp or np == 0 : break
p + = 1
cp = np ; p + = 1 ; QtWidgets . QApplication . processEvents ( )
d [ ' item ' ] . setText ( 2 , f " { np : , } " )
d [ ' item ' ] . setText ( 2 , f " { cp : , } " ) ; d [ ' item ' ] . setText ( 1 , f " Opt ( { p } x) " )
d [ ' item ' ] . setText ( 1 , f " Opt ( { p } x) " )
except : d [ ' item ' ] . setText ( 1 , " Erro Opt " )
QtWidgets . QApplication . processEvents ( )
ui . pb . setValue ( tot ) ; ui . pb . setFormat ( " Opt Concluída! " )
if np < = tg or np < 50 or p > = 20 or ( np > = cp and p > 1 ) : break
cp = np
rt . collapseStack ( o )
if not rt . isKindOf ( o , rt . Editable_Poly ) :
rt . convertTo ( o , rt . Editable_Poly )
if not ui . _is_cancelled :
d [ ' item ' ] . setText ( 2 , f " { rt . getPolygonCount ( o ) [ 0 ] : , } " )
d [ ' item ' ] . setText ( 1 , f " Opt OK ( { p } x) " )
except Exception as e :
d [ ' item ' ] . setText ( 1 , " Erro Opt " )
print ( f " Erro Opt { d [ ' name ' ] } : { e } " )
ui . pb . setValue ( tot )
ui . pb . setFormat ( " Opt Concluída! " )
def slice_large_objects ( ui , from_auto = False ) :
def slice_large_objects ( ui , from_auto = False ) :
if not ui . bake_items : return
if not ui . bake_items : return
thr = ui . spn_max_sz . value ( )
thr = ui . spn_max_sz . value ( )
act = 0
rt . execute ( " max modify mode " )
tgs = ui . get_processable_items ( )
tgs = ui . get_processable_items ( )
pn = [ d [ ' name ' ] for d in tgs ]
fn = [ d [ ' name ' ] for d in ui . bake_items if d [ ' name ' ] not in pn ]
tot = len ( tgs )
tot = len ( tgs )
ui . pb . setMaximum ( tot )
ui . pb . setMaximum ( tot )
ui . pb . setValue ( 0 )
ui . pb . setValue ( 0 )
rt . execute ( " max modify mode " )
print ( " \n " + " = " * 50 )
print ( " 🔍 INICIANDO LOG: MULTI-UV (P4) " )
print ( f " -> Tamanho de corte (Threshold): { thr } " )
print ( " = " * 50 )
for i , d in enumerate ( tgs ) :
for i , d in enumerate ( tgs ) :
if ui . _is_cancelled : break
if ui . _is_cancelled : break
ui . pb . setFormat ( f " Cortando ( { i + 1 } / { tot } ): { d [ ' name ' ] } ... " )
ui . pb . setFormat ( f " Multi-UV ({ i + 1 } / { tot } ): { d [ ' name ' ] } ... " )
ui . pb . setValue ( i )
ui . pb . setValue ( i )
QtWidgets . QApplication . processEvents ( )
QtWidgets . QApplication . processEvents ( )
chk = [ d [ ' name ' ] ]
print ( f " \n --- Processando objeto: { d [ ' name ' ] } --- " )
sc = 0
while len ( chk ) > 0 and sc < 300 :
# CÓDIGO CORRIGIDO: Tudo embrulhado num "fn" (função) nativo para o return funcionar.
QtWidgets . QApplication . processEvents ( )
ms = f """ (
if ui . _is_cancelled : break
fn applyMultiMatID objName thrVal = (
local o = getNodeByName objName
cn = chk . pop ( 0 )
if o == undefined do return - 1
o = rt . getNodeByName ( cn )
if not isKindOf o Editable_Poly do convertToPoly o
if not o or not rt . isValidNode ( o ) :
continue
md = max ( abs ( o . max . x - o . min . x ) , abs ( o . max . y - o . min . y ) , abs ( o . max . z - o . min . z ) )
local dx = abs ( o . max . x - o . min . x )
if md > thr :
local dy = abs ( o . max . y - o . min . y )
ax = " X " if md == abs ( o . max . x - o . min . x ) else " Y " if md == abs ( o . max . y - o . min . y ) else " Z "
local dz = abs ( o . max . z - o . min . z )
local md = amax #(dx, dy, dz)
ms = f """ (
if md < = thrVal do (
fn bsp objN ax = (
for f = 1 to ( polyop . getNumFaces o ) do polyop . setFaceMatID o f 1
local o = getNodeByName objN
return 1
if o == undefined or not ( canConvertTo o Editable_Poly ) do return #()
)
if not isKindOf o Editable_Poly do try ( convertToPoly o ) catch ( )
if not isKindOf o Editable_Poly do return #()
local numChunks = ( ceil ( md / thrVal ) ) as integer
if numChunks > 10 do numChunks = 10
local v = polyop . getNumVerts o
if v > 0 do ( try ( o . weldThreshold = 0.001 ) catch ( ) ; try ( polyop . weldVertsByThreshold o #{{1..v}})catch() )
local axis = if md == dx then 1 else if md == dy then 2 else 3
local minVal = if axis == 1 then o . min . x else if axis == 2 then o . min . y else o . min . z
CenterPivot o
local step = md / numChunks
local o2 = copy o name : ( uniqueName ( o . name + " _F " ) )
local rot = if ax == " X " then eulerAngles 0 90 0 else if ax == " Y " then eulerAngles 90 0 0 else eulerAngles 0 0 0
local s1 = SliceModifier ( ) ; s1 . Slice_Type = 2 ; s1 . slice_plane . rotation = rot ; addModifier o s1 ; try ( addModifier o ( Cap_Holes ( ) ) ) catch ( ) ; collapseStack o
local s2 = SliceModifier ( ) ; s2 . Slice_Type = 3 ; s2 . slice_plane . rotation = rot ; addModifier o2 s2 ; try ( addModifier o2 ( Cap_Holes ( ) ) ) catch ( ) ; collapseStack o2
if not isKindOf o Editable_Poly do try ( convertToPoly o ) catch ( )
if not isKindOf o2 Editable_Poly do try ( convertToPoly o2 ) catch ( )
local r = #()
if isValidNode o then (
if ( polyop . getNumFaces o ) < 1 then try ( delete o ) catch ( ) else append r o . name
)
if isValidNode o2 then (
if ( polyop . getNumFaces o2 ) < 1 then try ( delete o2 ) catch ( ) else append r o2 . name
)
return r
)
bsp " {cn} " " {ax} "
) """
try :
for f = 1 to ( polyop . getNumFaces o ) do (
n_p = rt . execute ( ms )
local center = polyop . getFaceCenter o f
if n_p is not None :
local val = if axis == 1 then center . x else if axis == 2 then center . y else center . z
n_p_list = list ( n_p )
local id = ( floor ( ( val - minVal ) / step ) ) as integer + 1
if len ( n_p_list ) > 1 :
if id > numChunks do id = numChunks
act + = 1
if id < 1 do id = 1
for p in n_p_list :
polyop . setFaceMatID o f id
po = rt . getNodeByName ( p )
)
if po and rt . isValidNode ( po ) :
return numChunks
pd = max ( abs ( po . max . x - po . min . x ) , abs ( po . max . y - po . min . y ) , abs ( po . max . z - po . min . z ) )
)
if pd > = md * 0.98 :
try ( applyMultiMatID " {d['name']} " { thr } ) catch ( - 2 )
fn . append ( p )
) """
else :
chk . append ( p )
try :
else :
print ( " -> Executando MaxScript de Fatiamento Lógico... " )
# Se falhou em pegar o node pelo nome (nomes duplicados), forçamos a string
r = rt . execute ( ms )
fn . append ( p )
print ( f " -> Resposta do MaxScript: { r } " )
elif len ( n_p_list ) == 1 :
fn . append ( n_p_list [ 0 ] )
else :
fn . append ( cn )
except Exception as e :
print ( f " Erro ao fatiar { cn } : { str ( e ) } " )
fn . append ( cn )
else :
fn . append ( cn )
sc + = 1
ui . pb . setValue ( tot )
if r == - 1 :
ui . pb . setFormat ( " Fatiador Concluído! Limpando a cena... " )
print ( " 🚨 ERRO: Objeto não encontrado na cena pelo MaxScript. " )
d [ ' item ' ] . setText ( 1 , " Erro: Objeto " )
rt . clearSelection ( )
elif r == - 2 :
final_sel = [ ]
print ( " 🚨 ERRO: MaxScript falhou internamente (Topologia corrompida?). " )
d [ ' item ' ] . setText ( 1 , " Erro: Script " )
# 1. Filtra a lista oficial do script
elif r and int ( r ) > 1 :
for n in fn :
print ( f " ✅ SUCESSO: Objeto dividido em { int ( r ) } IDs! " )
o = rt . getNodeByName ( n )
d [ ' item ' ] . setText ( 1 , f " IDs: { int ( r ) } " )
if o and rt . isValidNode ( o ) :
else :
try :
print ( " -> Objeto menor que a Meta. Mantido como 1 ID. " )
if rt . canConvertTo ( o , rt . Editable_Poly ) :
d [ ' item ' ] . setText ( 1 , " 1 ID (Normal) " )
if rt . getPolygonCount ( o ) [ 0 ] > 0 :
final_sel . append ( o )
except Exception as e :
else :
d [ ' item ' ] . setText ( 1 , " Erro Python " )
rt . delete ( o )
print ( f " 🚨 ERRO CRÍTICO PYTHON no Multi-UV: { e } " )
except : pass
# ========================================================
ui . pb . setValue ( tot )
# 🕵️♂️ MÓDULO DETETIVE: COMPARA SCRIPT vs CENA REAL
ui . pb . setFormat ( " Multi-IDs Gerados! " )
# ========================================================
print ( " \n " + " = " * 50 )
print ( " \n " + " = " * 50 )
print ( " 🕵️♂️ DETETIVE VR4LIFE: RELATÓRIO PÓS-FATIAMENTO " )
print ( " ✅ FIM DO LOG MULTI-UV " )
print ( " = " * 50 )
script_names = [ o . name for o in final_sel if rt . isValidNode ( o ) ]
print ( f " -> Objetos validados na lista do Script: { len ( script_names ) } " )
# Varre a cena buscando toda a geometria que existe agora
ms_all_geo = " for o in objects where superclassof o == GeometryClass and classof o != TargetObject collect o.name "
cena_names = list ( rt . execute ( ms_all_geo ) )
print ( f " -> Geometrias reais encontradas na Cena: { len ( cena_names ) } " )
# Encontra quem está na cena mas ficou de fora do script
perdidos = [ n for n in cena_names if n not in script_names ]
print ( f " -> Diferença (Objetos perdidos): { len ( perdidos ) } " )
if perdidos :
print ( " \n 🚨 LISTA DE SUSPEITOS: " )
for p in perdidos :
po = rt . getNodeByName ( p )
if po and rt . isValidNode ( po ) :
try :
faces = rt . getPolygonCount ( po ) [ 0 ] if rt . canConvertTo ( po , rt . Editable_Poly ) else " N/A "
t_x = abs ( po . max . x - po . min . x )
t_y = abs ( po . max . y - po . min . y )
t_z = abs ( po . max . z - po . min . z )
maior_eixo = max ( t_x , t_y , t_z )
print ( f " [!] NOME: { p } " )
print ( f " Faces: { faces } | Maior Eixo: { maior_eixo : .1f } | Dims: ( { t_x : .1f } , { t_y : .1f } , { t_z : .1f } ) " )
# Se eles são válidos, nós resgatamos eles à força para a seleção final!
if faces != " N/A " and faces > 0 :
final_sel . append ( po )
print ( " >> STATUS: Resgatado e adicionado à lista! " )
except Exception as e :
print ( f " >> ERRO ao ler suspeito: { e } " )
else :
print ( " ✅ Nenhum objeto foi perdido no processo! " )
print ( " = " * 50 + " \n " )
print ( " = " * 50 + " \n " )
# ========================================================
if final_sel :
rt . select ( final_sel )
if act > 0 :
load_selection ( ui )
def prepare_mesh ( ui ) :
def prepare_mesh ( ui ) :
tgs = ui . get_processable_items ( ) ; tot = len ( tgs ) ; ui . pb . setMaximum ( tot ) ; ui . pb . setValue ( 0 ) ; rt . execute ( " max modify mode " )
tgs = ui . get_processable_items ( )
tot = len ( tgs )
ui . pb . setMaximum ( tot )
ui . pb . setValue ( 0 )
rt . execute ( " max modify mode " )
for i , d in enumerate ( tgs ) :
for i , d in enumerate ( tgs ) :
if ui . _is_cancelled : break
if ui . _is_cancelled : break
ui . pb . setFormat ( f " UV ( { i + 1 } / { tot } ): { d [ ' name ' ] } ... " ) ; ui . pb . setValue ( i ) ; QtWidgets . QApplication . processEvents ( )
ui . pb . setFormat ( f " UV ( { i + 1 } / { tot } ): { d [ ' name ' ] } ... " )
ui . pb . setValue ( i )
QtWidgets . QApplication . processEvents ( )
o = rt . getNodeByName ( d [ ' name ' ] )
o = rt . getNodeByName ( d [ ' name ' ] )
if o :
if o :
rt . select ( o )
rt . select ( o )
try :
try :
if not rt . isKindOf ( o , rt . Editable_Poly ) : rt . convertTo ( o , rt . Editable_Poly )
ms = f """ (
rt . execute ( f """ ( local o = getNodeByName " { d [ ' name ' ] } " ; local m = Unwrap_UVW(); addModifier o m; m.setMapChannel 1; m.setTVSubObjectMode 3; local nf = polyOp.getNumFaces o; m.selectFaces # {{ 1..nf }} ; m.flattenMap 45.0 #() 0.002 true 0 true false; m.pack 1 0.002 true false false; collapseStack o ) """ )
local o = getNodeByName " {d['name']} "
if not rt . isKindOf ( o , rt . Editable_Poly ) : rt . convertTo ( o , rt . Editable_Poly )
if not isKindOf o Editable_Poly do convertToPoly o
d [ ' item ' ] . setText ( 1 , " UV Packed " )
local m = Unwrap_UVW ( )
except : d [ ' item ' ] . setText ( 1 , " Erro UV " )
addModifier o m
ui . pb . setValue ( tot ) ; ui . pb . setFormat ( " UV Pack Concluído! " )
m . setMapChannel 3
m . setTVSubObjectMode 3
local maxID = 1
for f = 1 to ( polyop . getNumFaces o ) do (
local id = polyop . getFaceMatID o f
if id > maxID do maxID = id
)
for x = 1 to maxID do (
m . selectByMatID x
local sel = m . getSelectedFaces ( )
if not sel . isEmpty do (
m . flattenMap 45.0 #() 0.002 true 0 true false
m . pack 1 0.002 true false false
)
)
collapseStack o
) """
rt . execute ( ms )
if not rt . isKindOf ( o , rt . Editable_Poly ) :
rt . convertTo ( o , rt . Editable_Poly )
d [ ' item ' ] . setText ( 1 , " UV Packed (C3) " )
except :
d [ ' item ' ] . setText ( 1 , " Erro UV " )
ui . pb . setValue ( tot )
ui . pb . setFormat ( " UV Pack Concluído! " )
def process_bake_logic ( ui , auto_export = False ) :
def process_bake_logic ( ui , auto_export = False ) :
el = ui . cmb_bake_elem . currentText ( ) ; p_bk = ui . edt_p_bake . text ( )
ui . _is_cancelled = False
rnd = str ( rt . execute ( " renderers.current as string " ) ) ; i_vr = " V_Ray " in rnd ; i_cor = " Corona " in rnd
el = ui . cmb_bake_elem . currentText ( )
u_den = ui . chk_denoise . isChecked ( ) ; a_res = ui . chk_a_res . isChecked ( )
p_bk = ui . edt_p_bake . text ( )
rnd = str ( rt . execute ( " renderers.current as string " ) )
i_vr = " V_Ray " in rnd
i_cor = " Corona " in rnd
u_den = ui . chk_denoise . isChecked ( )
a_res = ui . chk_a_res . isChecked ( )
if not os . path . exists ( p_bk ) : os . makedirs ( p_bk )
if not os . path . exists ( p_bk ) : os . makedirs ( p_bk )
tgs = ui . get_processable_items ( ) ; tot = len ( tgs ) ; ui . pb . setMaximum ( tot ) ; ui . pb . setValue ( 0 )
tgs = ui . get_processable_items ( )
tot = len ( tgs )
ui . pb . setMaximum ( tot )
ui . pb . setValue ( 0 )
print ( " \n " + " = " * 50 )
print ( " 🎬 INICIANDO LOG: MOTOR DE BAKE (P6) " )
print ( f " -> Pasta Alvo: { p_bk } " )
print ( f " -> Renderizador: { rnd } " )
print ( " = " * 50 )
for i , d in enumerate ( tgs ) :
for i , d in enumerate ( tgs ) :
if ui . _is_cancelled : break
if ui . _is_cancelled : break
ui . pb . setFormat ( f " Bake ( { i + 1 } / { tot } ): { d [ ' name ' ] } ... " ) ; ui . pb . setValue ( i ) ; QtWidgets . QApplication . processEvents ( )
ui . pb . setFormat ( f " Bake ( { i + 1 } / { tot } ): { d [ ' name ' ] } ... " )
t_jpg = os . path . join ( p_bk , f " { d [ ' name ' ] } _B.jpg " ) . replace ( " \\ " , " / " )
ui . pb . setValue ( i )
if os . path . exists ( t_jpg ) : d [ ' item ' ] . setText ( 1 , " Já existe " ) ; continue
QtWidgets . QApplication . processEvents ( )
cr = ui . spn_res . value ( ) ; o = rt . getNodeByName ( d [ ' name ' ] )
if o and a_res :
md = max ( abs ( o . max . x - o . min . x ) , abs ( o . max . y - o . min . y ) , abs ( o . max . z - o . min . z ) )
cr = 256 if md < = ui . s256 . value ( ) else 512 if md < = ui . s512 . value ( ) else 1024 if md < = ui . s1024 . value ( ) else cr
ext = " .exr " if ( i_vr and u_den ) else " .jpg "
print ( f " \n --- Preparando Bake: { d [ ' name ' ] } --- " )
t_rnd = t_jpg . replace ( " .jpg " , " .exr " ) if ext == " .exr " else t_jpg
rt . execute ( " max select none " ) ; rt . select ( o ) ; rt . execute ( " max modify mode " ) ; rt . execute ( " max zoomext sel all " ) ; rt . redrawViews ( ) ; time . sleep ( 0.5 )
o = rt . getNodeByName ( d [ ' name ' ] )
if not o :
print ( " 🚨 ERRO: Objeto não encontrado. " )
continue
try :
try :
rt . execute ( " freeSceneBitmaps(); try(vfbControl #clearimage)catch() " )
# 1. Conta quantos IDs existem no objeto
ms = """ (
ms_mid = f """ (local o = getNodeByName " { d [ ' name ' ] } " ; local mid = 1; if o != undefined and isKindOf o Editable_Poly do ( for f = 1 to (polyop.getNumFaces o) do ( local id = polyop.getFaceMatID o f; if id > mid do mid = id ) ); mid) """
local o = getNodeByName " {0} " ; if { 5 } and { 6 } do try ( renderers . current . denoise_enable = true ) catch ( )
max_id = rt . execute ( ms_mid )
renderWidth = { 2 } ; renderHeight = { 2 } ; o . INodeBakeProperties . removeAllBakeElements ( )
if not max_id : max_id = 1
local be = { 1 } ( ) ; be . outputSzX = { 2 } ; be . outputSzY = { 2 } ; be . fileType = " {3} " ; be . fileName = " {4} "
max_id = int ( max_id )
o . INodeBakeProperties . addBakeElement be ; o . INodeBakeProperties . bakeEnabled = true ; o . INodeBakeProperties . bakeChannel = 1
print ( f " -> Total de IDs a renderizar: { max_id } " )
render rendertype : #bakeSelected vfb:true quiet:true outputfile:"{4}"
) """ .format(d[ ' name ' ], el, cr, ext, t_rnd, str(i_cor).lower(), str(u_den).lower())
rt . execute ( ms )
wt = 0
rt . execute ( " max select none " )
while not os . path . exists ( t_rnd ) and wt < 60 : time . sleep ( 0.5 ) ; wt + = 0.5 ; QtWidgets . QApplication . processEvents ( )
rt . select ( o )
rt . execute ( " max modify mode " )
rt . execute ( " max zoomext sel all " )
rt . redrawViews ( )
time . sleep ( 0.5 )
if os . path . exists ( t_rnd ) :
for mid in range ( 1 , max_id + 1 ) :
if i_vr and u_den :
if ui . _is_cancelled : break
d [ ' item ' ] . setText ( 1 , " IA Limpando... " )
print ( f " \n -> Assando ID: { mid } de { max_id } " )
c_in = t_rnd . replace ( " / " , " \\ " ) ; c_out = t_rnd . replace ( " .exr " , " _denoised.exr " ) . replace ( " / " , " \\ " )
try :
if max_id == 1 :
p = subprocess . Popen ( f ' { get_vdenoise_path ( ) } -inputFile= " { c_in } " -outputFile= " { c_out } " -display=0 ' , shell = True , creationflags = 0x08000000 ) ; dt = 0
t_jpg_id = os . path . join ( p_bk , f " { d [ ' name ' ] } _B.jpg " ) . replace ( " \\ " , " / " )
while p . poll ( ) is None and dt < 60 : QtWidgets . QApplication . processEvents ( ) ; time . sleep ( 0.5 ) ; dt + = 0.5
else :
if p . poll ( ) is None : p . terminate ( )
t_jpg_id = os . path . join ( p_bk , f " { d [ ' name ' ] } _B_ID { mid } .jpg " ) . replace ( " \\ " , " / " )
except : pass
f_exr = c_out . replace ( " \\ " , " / " ) if os . path . exists ( c_out . replace ( " \\ " , " / " ) ) else t_rnd
rt . execute ( f """ ( try(vfbControl #clearimage)catch(); try ( local bI = openBitmap @ " { f_exr } " ; if bI != undefined do ( local bO = bitmap bI.width bI.height filename:@ " { t_jpg } " hdr:true; copy bI bO; save bO; close bI; close bO; free bI; free bO ) ) catch() ) """ )
rt . execute ( " freeSceneBitmaps(); gc light:true " ) ; time . sleep ( 0.5 )
try : os . remove ( t_rnd ) ; os . remove ( c_out . replace ( " \\ " , " / " ) )
except : pass
if os . path . exists ( t_jpg ) : d [ ' item ' ] . setText ( 1 , " Bake OK " ) ; deep_log_and_kill ( )
if os . path . exists ( t_jpg_id ) :
else : d [ ' item ' ] . setText ( 1 , " Erro Conv " )
d [ ' item ' ] . setText ( 1 , f " Já existe ID { mid } " )
else : d [ ' item ' ] . setText ( 1 , " Erro Save " )
print ( " -> Ficheiro já existe. Pulando. " )
except : d [ ' item ' ] . setText ( 1 , " Erro Render " )
continue
ui . pb . setValue ( tot ) ; ui . pb . setFormat ( " Bake Concluído! " )
if auto_export and not ui . _is_cancelled : cld . finalize_export ( ui , p_bk , ui . edt_p_glb . text ( ) )
cr = ui . spn_res . value ( )
if a_res :
md = max ( abs ( o . max . x - o . min . x ) , abs ( o . max . y - o . min . y ) , abs ( o . max . z - o . min . z ) )
cr = 256 if md < = ui . s256 . value ( ) else 512 if md < = ui . s512 . value ( ) else 1024 if md < = ui . s1024 . value ( ) else cr
ext = " .exr " if ( i_vr and u_den ) else " .jpg "
t_rnd_id = t_jpg_id . replace ( " .jpg " , " .exr " ) if ext == " .exr " else t_jpg_id
if max_id > 1 :
print ( " -> Isolando UV do ID atual... " )
# CÓDIGO CORRIGIDO 1: Embrulhado em 'fn'
ms_uv = f """ (
fn isolateUV currentMid = (
global temp_uv_mod = Unwrap_UVW ( )
addModifier $ temp_uv_mod
temp_uv_mod . setMapChannel 3
temp_uv_mod . setTVSubObjectMode 3
local allF = #{{1..(polyop.getNumFaces $)}}
temp_uv_mod . selectByMatID currentMid
local tgtF = temp_uv_mod . getSelectedFaces ( )
local hideF = allF - tgtF
if hideF . numberset > 0 do (
temp_uv_mod . selectFaces hideF
temp_uv_mod . moveSelected [ - 10 , - 10 , 0 ]
)
return 1
)
try ( isolateUV { mid } ) catch ( 0 )
) """
res_uv = rt . execute ( ms_uv )
if res_uv == 0 : print ( " 🚨 ERRO: O MaxScript não conseguiu manipular as UVs. " )
print ( f " -> Disparando o Render: { t_rnd_id } " )
# CÓDIGO CORRIGIDO 2: Embrulhado em 'fn'
ms_bake = f """ (
fn doBake fileOut szX szY fileExt cor den elem = (
try ( freeSceneBitmaps ( ) ; vfbControl #clearimage)catch()
if cor and den do try ( renderers . current . denoise_enable = true ) catch ( )
$ . INodeBakeProperties . removeAllBakeElements ( )
local be = ( execute ( elem + " () " ) )
be . outputSzX = szX
be . outputSzY = szY
be . fileType = fileExt
be . fileName = fileOut
$ . INodeBakeProperties . addBakeElement be
$ . INodeBakeProperties . bakeEnabled = true
$ . INodeBakeProperties . bakeChannel = 3
render rendertype : #bakeSelected vfb:true quiet:true outputfile:fileOut
return 1
)
try ( doBake " {t_rnd_id} " { cr } { cr } " {ext} " { str ( i_cor ) . lower ( ) } { str ( u_den ) . lower ( ) } " {el} " ) catch ( 0 )
) """
res_bk = rt . execute ( ms_bake )
if res_bk == 0 : print ( " 🚨 ERRO: O Renderizador rejeitou o comando de Bake! " )
wt = 0
while not os . path . exists ( t_rnd_id ) and wt < 60 :
time . sleep ( 0.5 )
wt + = 0.5
QtWidgets . QApplication . processEvents ( )
if os . path . exists ( t_rnd_id ) :
if i_vr and u_den :
print ( " -> Passando Denoise IA... " )
c_in = t_rnd_id . replace ( " / " , " \\ " )
c_out = t_rnd_id . replace ( " .exr " , " _denoised.exr " ) . replace ( " / " , " \\ " )
try :
p = subprocess . Popen ( f ' { get_vdenoise_path ( ) } -inputFile= " { c_in } " -outputFile= " { c_out } " -display=0 ' , shell = True , creationflags = 0x08000000 ) ; dt = 0
while p . poll ( ) is None and dt < 60 : QtWidgets . QApplication . processEvents ( ) ; time . sleep ( 0.5 ) ; dt + = 0.5
if p . poll ( ) is None : p . terminate ( )
except : pass
f_exr = c_out . replace ( " \\ " , " / " ) if os . path . exists ( c_out . replace ( " \\ " , " / " ) ) else t_rnd_id
rt . execute ( f """ ( try(vfbControl #clearimage)catch(); try ( local bI = openBitmap @ " { f_exr } " ; if bI != undefined do ( local bO = bitmap bI.width bI.height filename:@ " { t_jpg_id } " hdr:true; copy bI bO; save bO; close bI; close bO; free bI; free bO ) ) catch() ) """ )
rt . execute ( " freeSceneBitmaps(); gc light:true " ) ; time . sleep ( 0.5 )
try : os . remove ( t_rnd_id ) ; os . remove ( c_out . replace ( " \\ " , " / " ) )
except : pass
if max_id > 1 :
print ( " -> Removendo modificador temporário de UV... " )
rt . execute ( " try(deleteModifier $ globalvars.get #temp_uv_mod)catch() " )
if os . path . exists ( t_jpg_id ) :
d [ ' item ' ] . setText ( 1 , " Bake OK " )
print ( " -> SUCESSO: Textura gravada no disco. " )
else :
d [ ' item ' ] . setText ( 1 , " Erro Conv " )
print ( " 🚨 ERRO: A textura não foi salva. Timeout? " )
if not ui . _is_cancelled :
print ( " -> Restaurando UV final do objeto... " )
rt . execute ( f """ ( local o = getNodeByName " { d [ ' name ' ] } " ; try( ChannelInfo.CopyChannel o 3 3; ChannelInfo.PasteChannel o 3 1; collapseStack o )catch() ) """ )
except Exception as e :
d [ ' item ' ] . setText ( 1 , " Erro Render " )
print ( f " 🚨 EXCEÇÃO PYTHON: { e } " )
ui . pb . setValue ( tot )
ui . pb . setFormat ( " Bake Concluído! " )
print ( " \n " + " = " * 50 )
print ( " ✅ FIM DO LOG DE BAKE " )
print ( " = " * 50 + " \n " )
if auto_export and not ui . _is_cancelled :
cld . finalize_export ( ui , p_bk , ui . edt_p_glb . text ( ) )
def upd_res_col ( ui ) :
def upd_res_col ( ui ) :
a_r = ui . chk_a_res . isChecked ( ) ; m_r = ui . spn_res . value ( )
a_r = ui . chk_a_res . isChecked ( )
m_r = ui . spn_res . value ( )
for d in ui . bake_items :
for d in ui . bake_items :
o = rt . getNodeByName ( d [ ' name ' ] )
o = rt . getNodeByName ( d [ ' name ' ] )
if o :
if o :
try :
try :
md = max ( abs ( o . max . x - o . min . x ) , abs ( o . max . y - o . min . y ) , abs ( o . max . z - o . min . z ) )
md = max ( abs ( o . max . x - o . min . x ) , abs ( o . max . y - o . min . y ) , abs ( o . max . z - o . min . z ) )
r = 256 if md < = ui . s256 . value ( ) else 512 if md < = ui . s512 . value ( ) else 1024 if md < = ui . s1024 . value ( ) else m_r if a_r else m_r
r = 256 if md < = ui . s256 . value ( ) else 512 if md < = ui . s512 . value ( ) else 1024 if md < = ui . s1024 . value ( ) else m_r if a_r else m_r
d [ ' item ' ] . setText ( 3 , f " { r } px " ) ; d [ ' item ' ] . setText ( 4 , f " { md : .1f } " )
d [ ' item ' ] . setText ( 3 , f " { r } px " )
d [ ' item ' ] . setText ( 4 , f " { md : .1f } " )
if r == 256 : d [ ' item ' ] . setForeground ( 3 , QtGui . QColor ( 0 , 255 , 255 ) )
if r == 256 : d [ ' item ' ] . setForeground ( 3 , QtGui . QColor ( 0 , 255 , 255 ) )
elif r == 512 : d [ ' item ' ] . setForeground ( 3 , QtGui . QColor ( 0 , 255 , 0 ) )
elif r == 512 : d [ ' item ' ] . setForeground ( 3 , QtGui . QColor ( 0 , 255 , 0 ) )
elif r == 1024 : d [ ' item ' ] . setForeground ( 3 , QtGui . QColor ( 255 , 165 , 0 ) )
elif r == 1024 : d [ ' item ' ] . setForeground ( 3 , QtGui . QColor ( 255 , 165 , 0 ) )