自定义视图信息显示 根据屏幕空间自适应位置,将代码拷贝到shelf tool 就可以。esc 键退出显示
相关帮助文档:https://www.sidefx.com/docs/houdini/hom/hou/ViewerStateTemplate.html
import hou, socket, os
from hutil.Qt import QtCore, QtWidgets, QtGui
_col = hou.Color(1.0, 0.9, 0.2)
_size = {'hip':7,'frange':7,'fps':7,'cframe':7,'pc':7,'res':7}
_margin = 2.0
_show = {'hip':1,'frange':1,'fps':1,'cframe':1,'pc':1,'res':1}
_lbl = {'hip':'HIP','frange':'Frame','fps':'FPS','cframe':'Frame','pc':'PC','res':'Res'}
_pc = socket.gethostname()
_hip_n = "" # 自定义 HIP 名(空=自动)
_pc_n = "" # 自定义机器名(空=自动)
class _HudState:
def __init__(s, state_name, scene_viewer):
s.sv = scene_viewer; s._d = None
def _hex(s,c):
r,g,b=[max(0,min(255,int(v*255)))for v in c.rgb()]
return f"#{r:02X}{g:02X}{b:02X}"
def _rt(s,t,c,sz,b=False):
h=s._hex(c); be="<b>"if b else""; bee="</b>"if b else""
return f'<font size={sz} color="{h}">{be}{t}{bee}</font>'
def _hip(s):
p=hou.hipFile.path(); return os.path.splitext(os.path.basename(p))[0]if p else"untitled"
def _cam(s):
try:
if s.sv is None: return None
vp=s.sv.curViewport()
if vp is None: return None
cr=vp.camera()
cam=None
if cr is not None:
if isinstance(cr,hou.ObjNode): cam=cr
elif isinstance(cr,str)and cr:
try: cam=hou.node(cr)
except: pass
if cam is not None:
for pn in('resx','res','resx_override'):
px=cam.parm(pn)
if px is not None:
py=cam.parm(pn.replace('x','y'))
if py is None: py=cam.parm('resy')
rx=int(px.eval()); ry=int(py.eval())if py else rx
return(rx,ry)
_,_,w,h=vp.size(); return(int(w),int(h))
except: return None
def onEnter(s,k): pass
def onResume(s,k):
if s._d:
for d in s._d.values():
try: d.show(True)
except: pass
def onInterrupt(s,k): pass
def onExit(s,k):
if s._d:
for d in s._d.values():
try: d.show(False)
except: pass
def _gd(s):
if s._d: return s._d
s._d={k:hou.TextDrawable(s.sv,'h'+k)for k in('tl','tc','tr','bl','bc','br')}
return s._d
def onDraw(s,kw):
global _col,_size,_margin,_show,_lbl,_pc,_hip_n,_pc_n
try: h=kw['draw_handle']
except: return
try: sv=s.sv
except: return
if sv is None: return
vp=sv.curViewport()
if vp is None: return
_,_,W,H=vp.size()
if W<=0 or H<=0: return
col=_col; mp=_margin/100.0
tx={}
if _show['hip']: tx['tl']=s._rt(f"{_lbl['hip']}: {_hip_n or s._hip()}",col,_size['hip'],True)
if _show['frange']:
a,b=hou.playbar.frameRange();a=int(a);b=int(b)
tx['tc']=s._rt(f"{_lbl['frange']}: {a} - {b}",col,_size['frange'],True)
if _show['fps']: tx['tr']=s._rt(f"{_lbl['fps']}: {hou.fps():.1f}",col,_size['fps'],True)
if _show['pc']: tx['bl']=s._rt(f"{_lbl['pc']}: {_pc_n or _pc}",col,_size['pc'],True)
if _show['res']:
r=s._cam()
if r: tx['bc']=s._rt(f"{_lbl['res']}: {r[0]}x{r[1]}",col,_size['res'],True)
if _show['cframe']: tx['br']=s._rt(f"{_lbl['cframe']}: {int(hou.frame())}",col,_size['cframe'],True)
if not tx: return
r=s._cam()if _show['res']else None
ox=oy=0.0; fw,fh=float(W),float(H)
if r:
cw,ch=r
if cw>0 and ch>0:
cr=float(cw)/ch; vr=float(W)/H
if abs(cr-vr)>0.005:
if cr>vr: fh=W/cr; oy=(H-fh)/2.0
else: fw=H*cr; ox=(W-fw)/2.0
M=max(6,int(min(fw,fh)*mp))
D=s._gd()
DT=hou.drawableTextOrigin
UL,UR,BL,BR=DT.UpperLeft,DT.UpperRight,DT.BottomLeft,DT.BottomRight
pm={
'tl':(UL,(ox+M,oy+fh-M,0)),
'tc':(UL,(ox+fw/2-100,oy+fh-M,0)),
'tr':(UR,(ox+fw-M,oy+fh-M,0)),
'bl':(BL,(ox+M,oy+M,0)),
'bc':(BL,(ox+fw/2-100,oy+M,0)),
'br':(BR,(ox+fw-M,oy+M,0)),
}
for key in('tl','tc','tr','bl','bc','br'):
if key not in tx: D[key].show(False); continue
D[key].show(True); o,a=pm[key]
try: D[key].draw(h,{'text':tx[key],'multi_line':False,'origin':o,'translate':a,'color1':col})
except: pass
class HudUI(QtWidgets.QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle("Viewport HUD"); self.setMinimumWidth(480)
self.setWindowFlags(QtCore.Qt.Window)
ly = QtWidgets.QVBoxLayout(self); ly.setSpacing(6)
g1 = QtWidgets.QGroupBox("显示"); gg1 = QtWidgets.QGridLayout(g1); gg1.setSpacing(4)
gg1.addWidget(QtWidgets.QLabel(""),0,0)
gg1.addWidget(QtWidgets.QLabel("标签"),0,1)
gg1.addWidget(QtWidgets.QLabel("字号"),0,2)
self.cb = {}; self.le = {}; self.sz = {}
items = [('hip','hip'),('frange','frange'),('fps','fps'),
('cframe','cframe'),('pc','pc'),('res','res')]
for row,(k,pos) in enumerate(items,1):
cb=QtWidgets.QCheckBox(pos); cb.setChecked(_show[k]); cb.toggled.connect(self._sync)
self.cb[k]=cb; gg1.addWidget(cb,row,0)
le=QtWidgets.QLineEdit(_lbl[k]); le.setMinimumWidth(100); le.editingFinished.connect(self._sync)
self.le[k]=le; gg1.addWidget(le,row,1)
sp=QtWidgets.QSpinBox(); sp.setRange(4,20); sp.setValue(_size[k]); sp.setMaximumWidth(50)
sp.valueChanged.connect(self._sync)
self.sz[k]=sp; gg1.addWidget(sp,row,2)
ly.addWidget(g1)
gn = QtWidgets.QGroupBox("自定义名称(空=自动)"); gnl = QtWidgets.QGridLayout(gn); gnl.setSpacing(4)
gnl.addWidget(QtWidgets.QLabel("HIP"),0,0)
self.le_hip = QtWidgets.QLineEdit(_hip_n); self.le_hip.editingFinished.connect(self._sync); gnl.addWidget(self.le_hip,0,1)
gnl.addWidget(QtWidgets.QLabel("PC"),1,0)
self.le_pc = QtWidgets.QLineEdit(_pc_n); self.le_pc.editingFinished.connect(self._sync); gnl.addWidget(self.le_pc,1,1)
ly.addWidget(gn)
g2=QtWidgets.QGroupBox("样式"); gg2=QtWidgets.QGridLayout(g2); gg2.setSpacing(6)
gg2.addWidget(QtWidgets.QLabel("边距%"),0,0)
self.sm=QtWidgets.QDoubleSpinBox(); self.sm.setRange(0.5,15); self.sm.setValue(_margin)
self.sm.valueChanged.connect(self._sync); gg2.addWidget(self.sm,0,1)
self.bc=QtWidgets.QPushButton(); self._uc(); self.bc.clicked.connect(self._pick)
gg2.addWidget(self.bc,1,0,1,2); ly.addWidget(g2)
def _uc(self):
r,g,b=[int(v*255)for v in _col.rgb()]
self.bc.setStyleSheet(f"background:rgb({r},{g},{b});min-height:22px;border:1px solid #555;border-radius:3px")
def _pick(self):
global _col
c=QtWidgets.QColorDialog.getColor(QtGui.QColor(*[int(v*255)for v in _col.rgb()]),self,"颜色")
if c.isValid(): _col=hou.Color(c.redF(),c.greenF(),c.blueF()); self._uc(); self._sync()
def _sync(self,*_):
global _show,_lbl,_size,_margin,_hip_n,_pc_n
for k in _show:
_show[k]=self.cb[k].isChecked()
_lbl[k]=self.le[k].text().strip()or k
_size[k]=self.sz[k].value()
_margin=self.sm.value()
_hip_n=self.le_hip.text().strip()
_pc_n=self.le_pc.text().strip()
def _start(self):
for old in("hud_tool","hud_ui","hud_ctrl"):
try: hou.ui.unregisterViewerState(old)
except: pass
t=hou.ViewerStateTemplate("hud_tool","HUD",hou.objNodeTypeCategory()); t.bindFactory(_HudState)
hou.ui.registerViewerState(t)
sv=hou.ui.paneTabOfType(hou.paneTabType.SceneViewer)
if sv: sv.setCurrentState("hud_tool",wait_for_exit=False)
def _stop(self):
try: hou.ui.unregisterViewerState("hud_tool")
except: pass
def showEvent(self,e):
self._sync(); self._start()
def closeEvent(self,e):
self.hide(); e.ignore() # 只隐藏,HUD 继续运行
# 删除旧窗口
for w in QtWidgets.QApplication.topLevelWidgets():
if w.objectName() == "ViewportHUD":
w.close(); w.deleteLater()
# 强制重建确保 UI 最新
hou.session._hud_panel = None
_win = HudUI()
_win.setObjectName("ViewportHUD")
hou.session._hud_panel = _win
if not _win.isVisible():
_win._start()
_win.show(); _win.raise_()
文章作者:Luo7758
文章标题:houdini veiwport HUD 显示信息
文章链接:https://cfxer.cn/?post=53
本站所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议,转载请注明来自Luo7758 !
文章标题:houdini veiwport HUD 显示信息
文章链接:https://cfxer.cn/?post=53
本站所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议,转载请注明来自Luo7758 !
设备上扫码阅读
版权说明
文章采用: 《署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0)》许可协议授权。版权声明:未标注转载均为本站原创,转载时请以链接形式注明文章出处。如有侵权、不妥之处,请联系站长删除。敬请谅解!

请保持你的学习热情!!...