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.
472 lines
22 KiB
Python
472 lines
22 KiB
Python
import os, time, subprocess
|
|
from pymxs import runtime as rt
|
|
try: from PySide6 import QtWidgets, QtCore, QtGui
|
|
except ImportError: from PySide2 import QtWidgets, QtCore, QtGui
|
|
import vr4life_cloud as cld
|
|
|
|
def get_vdenoise_path():
|
|
for k, v in os.environ.items():
|
|
if "VRAY" in k.upper() and "MAX" in k.upper() and "MAIN" in k.upper():
|
|
p = os.path.join(v, "vdenoise.exe")
|
|
if os.path.exists(p): return f'"{p}"'
|
|
return "vdenoise.exe"
|
|
|
|
def load_bake_elements(ui):
|
|
ui.cmb_bake_elem.clear()
|
|
found = ["CompleteMap", "VRayCompleteMap", "Corona_Beauty", "CShading_Beauty"]
|
|
try:
|
|
r_list = rt.execute("for c in bake_elements.classes collect (c as string)")
|
|
for c in r_list:
|
|
if str(c) not in found: found.append(str(c))
|
|
except: pass
|
|
ui.cmb_bake_elem.addItems(sorted(list(set(found))))
|
|
try:
|
|
rnd = str(rt.execute("renderers.current as string"))
|
|
t = "VRayCompleteMap" if "V_Ray" in rnd else "Corona_Beauty" if "Corona" in rnd else "CompleteMap"
|
|
idx = ui.cmb_bake_elem.findText(t)
|
|
if idx >= 0: ui.cmb_bake_elem.setCurrentIndex(idx)
|
|
except: pass
|
|
|
|
def load_selection(ui):
|
|
ui.tree.clear(); ui.bake_items = []
|
|
ms = """( local g = #(); fn ex objs = ( for o in objs do ( if isGroupHead o then ( setGroupOpen o true; ex o.children ) else ( if superclassof o == GeometryClass and (classOf o != TargetObject) and (canConvertTo o Editable_Poly) do appendIfUnique g o ) ) ); ex selection; g )"""
|
|
sel = rt.execute(ms)
|
|
if not sel: return
|
|
tl = [{'name': str(o.name), 'poly': rt.getPolygonCount(o)[0] if rt.canConvertTo(o, rt.Editable_Poly) else 0} for o in sel]
|
|
tl.sort(key=lambda x: x['poly'], reverse=True)
|
|
for d in tl:
|
|
i = QtWidgets.QTreeWidgetItem([d['name'], "Pronto", f"{d['poly']:,}", "", ""])
|
|
i.setFlags(i.flags() | QtCore.Qt.ItemIsUserCheckable)
|
|
i.setCheckState(0, QtCore.Qt.Checked)
|
|
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):
|
|
ui.pb.setFormat("Fundindo grupos inteiros...")
|
|
QtWidgets.QApplication.processEvents()
|
|
ms = """(
|
|
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
|
|
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 final_sel = loose; for no in new_objs do append final_sel no; if final_sel.count > 0 do select final_sel; act
|
|
)"""
|
|
try:
|
|
act = rt.execute(ms)
|
|
load_selection(ui)
|
|
if not from_auto:
|
|
if act > 0: QtWidgets.QMessageBox.information(ui, "Sucesso", f"{act} Grupos fundidos.")
|
|
else: QtWidgets.QMessageBox.information(ui, "Aviso", "Nenhum Grupo encontrado.")
|
|
except Exception as e: print("Erro Solda:", e)
|
|
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):
|
|
sp = ui.spn_pct.value()
|
|
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):
|
|
if ui._is_cancelled: break
|
|
ui.pb.setFormat(f"Opt ({i+1}/{tot}): {d['name']}...")
|
|
ui.pb.setValue(i)
|
|
QtWidgets.QApplication.processEvents()
|
|
|
|
o = rt.getNodeByName(d['name'])
|
|
if o:
|
|
try:
|
|
cp = rt.getPolygonCount(o)[0] if rt.canConvertTo(o, rt.Editable_Poly) else 0
|
|
if cp < 50:
|
|
d['item'].setText(1, "Geo Base")
|
|
else:
|
|
rt.select(o)
|
|
if not rt.isKindOf(o, rt.Editable_Poly):
|
|
rt.convertTo(o, rt.Editable_Poly)
|
|
|
|
opt = rt.ProOptimizer()
|
|
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]
|
|
p += 1
|
|
d['item'].setText(2, f"{np:,}")
|
|
d['item'].setText(1, f"Opt ({p}x)")
|
|
QtWidgets.QApplication.processEvents()
|
|
|
|
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):
|
|
if not ui.bake_items: return
|
|
thr = ui.spn_max_sz.value()
|
|
tgs = ui.get_processable_items()
|
|
tot = len(tgs)
|
|
ui.pb.setMaximum(tot)
|
|
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):
|
|
if ui._is_cancelled: break
|
|
ui.pb.setFormat(f"Multi-UV ({i+1}/{tot}): {d['name']}...")
|
|
ui.pb.setValue(i)
|
|
QtWidgets.QApplication.processEvents()
|
|
|
|
print(f"\n--- Processando objeto: {d['name']} ---")
|
|
|
|
# CÓDIGO CORRIGIDO: Tudo embrulhado num "fn" (função) nativo para o return funcionar.
|
|
ms = f"""(
|
|
fn applyMultiMatID objName thrVal = (
|
|
local o = getNodeByName objName
|
|
if o == undefined do return -1
|
|
if not isKindOf o Editable_Poly do convertToPoly o
|
|
|
|
local dx = abs(o.max.x - o.min.x)
|
|
local dy = abs(o.max.y - o.min.y)
|
|
local dz = abs(o.max.z - o.min.z)
|
|
local md = amax #(dx, dy, dz)
|
|
|
|
if md <= thrVal do (
|
|
for f = 1 to (polyop.getNumFaces o) do polyop.setFaceMatID o f 1
|
|
return 1
|
|
)
|
|
|
|
local numChunks = (ceil (md / thrVal)) as integer
|
|
if numChunks > 10 do numChunks = 10
|
|
|
|
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
|
|
local step = md / numChunks
|
|
|
|
for f = 1 to (polyop.getNumFaces o) do (
|
|
local center = polyop.getFaceCenter o f
|
|
local val = if axis == 1 then center.x else if axis == 2 then center.y else center.z
|
|
local id = (floor ((val - minVal) / step)) as integer + 1
|
|
if id > numChunks do id = numChunks
|
|
if id < 1 do id = 1
|
|
polyop.setFaceMatID o f id
|
|
)
|
|
return numChunks
|
|
)
|
|
try ( applyMultiMatID "{d['name']}" {thr} ) catch ( -2 )
|
|
)"""
|
|
|
|
try:
|
|
print("-> Executando MaxScript de Fatiamento Lógico...")
|
|
r = rt.execute(ms)
|
|
print(f"-> Resposta do MaxScript: {r}")
|
|
|
|
if r == -1:
|
|
print("🚨 ERRO: Objeto não encontrado na cena pelo MaxScript.")
|
|
d['item'].setText(1, "Erro: Objeto")
|
|
elif r == -2:
|
|
print("🚨 ERRO: MaxScript falhou internamente (Topologia corrompida?).")
|
|
d['item'].setText(1, "Erro: Script")
|
|
elif r and int(r) > 1:
|
|
print(f"✅ SUCESSO: Objeto dividido em {int(r)} IDs!")
|
|
d['item'].setText(1, f"IDs: {int(r)}")
|
|
else:
|
|
print("-> Objeto menor que a Meta. Mantido como 1 ID.")
|
|
d['item'].setText(1, "1 ID (Normal)")
|
|
|
|
except Exception as e:
|
|
d['item'].setText(1, "Erro Python")
|
|
print(f"🚨 ERRO CRÍTICO PYTHON no Multi-UV: {e}")
|
|
|
|
ui.pb.setValue(tot)
|
|
ui.pb.setFormat("Multi-IDs Gerados!")
|
|
print("\n" + "="*50)
|
|
print("✅ FIM DO LOG MULTI-UV")
|
|
print("="*50 + "\n")
|
|
|
|
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")
|
|
|
|
for i, d in enumerate(tgs):
|
|
if ui._is_cancelled: break
|
|
ui.pb.setFormat(f"UV ({i+1}/{tot}): {d['name']}...")
|
|
ui.pb.setValue(i)
|
|
QtWidgets.QApplication.processEvents()
|
|
o = rt.getNodeByName(d['name'])
|
|
if o:
|
|
rt.select(o)
|
|
try:
|
|
ms = f"""(
|
|
local o = getNodeByName "{d['name']}"
|
|
if not isKindOf o Editable_Poly do convertToPoly o
|
|
local m = Unwrap_UVW()
|
|
addModifier o m
|
|
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):
|
|
ui._is_cancelled = False
|
|
el = ui.cmb_bake_elem.currentText()
|
|
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)
|
|
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):
|
|
if ui._is_cancelled: break
|
|
ui.pb.setFormat(f"Bake ({i+1}/{tot}): {d['name']}...")
|
|
ui.pb.setValue(i)
|
|
QtWidgets.QApplication.processEvents()
|
|
|
|
print(f"\n--- Preparando Bake: {d['name']} ---")
|
|
|
|
o = rt.getNodeByName(d['name'])
|
|
if not o:
|
|
print("🚨 ERRO: Objeto não encontrado.")
|
|
continue
|
|
|
|
try:
|
|
# 1. Conta quantos IDs existem no objeto
|
|
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)"""
|
|
max_id = rt.execute(ms_mid)
|
|
if not max_id: max_id = 1
|
|
max_id = int(max_id)
|
|
print(f"-> Total de IDs a renderizar: {max_id}")
|
|
|
|
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)
|
|
|
|
for mid in range(1, max_id + 1):
|
|
if ui._is_cancelled: break
|
|
print(f"\n-> Assando ID: {mid} de {max_id}")
|
|
|
|
if max_id == 1:
|
|
t_jpg_id = os.path.join(p_bk, f"{d['name']}_B.jpg").replace("\\", "/")
|
|
else:
|
|
t_jpg_id = os.path.join(p_bk, f"{d['name']}_B_ID{mid}.jpg").replace("\\", "/")
|
|
|
|
if os.path.exists(t_jpg_id):
|
|
d['item'].setText(1, f"Já existe ID{mid}")
|
|
print("-> Ficheiro já existe. Pulando.")
|
|
continue
|
|
|
|
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):
|
|
a_r = ui.chk_a_res.isChecked()
|
|
m_r = ui.spn_res.value()
|
|
for d in ui.bake_items:
|
|
o = rt.getNodeByName(d['name'])
|
|
if o:
|
|
try:
|
|
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
|
|
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))
|
|
elif r == 512: d['item'].setForeground(3, QtGui.QColor(0, 255, 0))
|
|
elif r == 1024: d['item'].setForeground(3, QtGui.QColor(255, 165, 0))
|
|
else: d['item'].setForeground(3, QtGui.QColor(255, 50, 50))
|
|
except: pass
|
|
|
|
def get_processable_items(ui):
|
|
valid_items = []
|
|
for d in ui.bake_items:
|
|
obj = rt.getNodeByName(d['name'])
|
|
if obj: valid_items.append(d)
|
|
return valid_items |