如何自定义带模糊效果的QBrush?解决大图形渲染延迟问题
解决大尺寸QGraphicsItem模糊渲染延迟的自定义QBrush方案
你遇到的问题太典型了——QGraphicsBlurEffect对超大尺寸图形元素的性能表现拉胯,本质原因是它要实时对整个item的像素缓冲区做模糊计算,大元素的像素量动辄数百万,再加上每秒60次的 gaze 位置更新,必然导致严重卡顿。自定义带模糊效果的QBrush是更高效的思路,我们可以提前生成模糊纹理,或者用轻量化的渐变模拟模糊,彻底避免实时像素级的繁重计算。
核心解决思路
我给你提供两种实用方案,覆盖不同的需求场景:
- 预生成模糊纹理:用小尺寸
QPixmap提前生成模糊椭圆图案,再将其作为纹理填充到大椭圆item中,纹理只需生成一次,后续直接复用 - 径向渐变模拟模糊:用多层径向渐变实现从中心到边缘的透明过渡,完全不需要像素模糊计算,性能拉满
下面结合你的代码给出具体实现:
方案1:预生成模糊纹理的QBrush(真实模糊效果)
这种方案能实现和QGraphicsBlurEffect一致的高斯模糊效果,但性能提升巨大,因为纹理只做一次模糊计算:
修改你的Create_Brush方法:
def Create_Brush(self): # 生成小尺寸纹理(避免大尺寸计算开销) texture_size = 200 pixmap = QtGui.QPixmap(texture_size, texture_size) pixmap.fill(QtCore.Qt.transparent) # 在纹理上绘制基础椭圆 painter = QtGui.QPainter(pixmap) painter.setRenderHint(QtGui.QPainter.Antialiasing) ellipse_rect = QtCore.QRectF(10, 10, texture_size-20, texture_size-20) painter.setBrush(QtGui.QBrush(QtCore.Qt.gray)) painter.setPen(QtCore.Qt.NoPen) painter.drawEllipse(ellipse_rect) painter.end() # 对纹理应用模糊(仅执行一次) blur_effect = QtWidgets.QGraphicsBlurEffect() blur_effect.setBlurRadius(10) blur_effect.setBlurHints(QtWidgets.QGraphicsBlurEffect.AnimationHint) temp_scene = QtWidgets.QGraphicsScene() temp_item = temp_scene.addPixmap(pixmap) temp_item.setGraphicsEffect(blur_effect) # 渲染得到模糊后的纹理 blurred_pixmap = QtGui.QPixmap(texture_size, texture_size) blurred_pixmap.fill(QtCore.Qt.transparent) temp_painter = QtGui.QPainter(blurred_pixmap) temp_scene.render(temp_painter) temp_painter.end() # 创建适配大椭圆尺寸的纹理brush brush = QtGui.QBrush(blurred_pixmap) brush.setTransform(QtGui.QTransform().scale( self.GazeItem.rect().width()/texture_size, self.GazeItem.rect().height()/texture_size )) return brush
然后在initUI中替换原brush设置:
# 替换原有brush代码 QCustomized_Brush = self.Create_Brush() self.GazeItem.setBrush(QCustomized_Brush)
方案2:径向渐变模拟模糊(性能最优)
如果你的模糊需求可以用自然的过渡效果替代,这种方案完全不需要像素计算,性能达到天花板:
def Create_Brush(self): # 创建径向渐变,从中心实色过渡到边缘透明,模拟模糊效果 ellipse_center = QtCore.QPointF( self.GazeItem.rect().width()/2, self.GazeItem.rect().height()/2 ) gradient = QtGui.QRadialGradient( ellipse_center, self.GazeItem.rect().width()/2 ) # 自定义渐变停止点,控制模糊过渡的范围和透明度 gradient.setColorAt(0.8, QtGui.QColor(128, 128, 128, 255)) # 中心实灰色 gradient.setColorAt(0.9, QtGui.QColor(128, 128, 128, 128)) # 半透明过渡层 gradient.setColorAt(1.0, QtGui.QColor(128, 128, 128, 0)) # 边缘完全透明 return QtGui.QBrush(gradient)
额外性能优化小贴士
- 裁剪不可见区域:给大椭圆item添加裁剪,避免绘制超出屏幕的部分:
self.GazeItem.setClipRect(self._scene.sceneRect()) - 优化视图更新模式:根据场景选择合适的视图更新策略,比如
self._gv.setViewportUpdateMode(QtWidgets.QGraphicsView.SmartViewportUpdate) - 关闭不必要的渲染提示:如果渐变方案已经足够平滑,可以去掉
QPainter.Antialiasing进一步减少开销
替换代码后,哪怕是5500px尺寸的椭圆,每秒60次的位置更新也不会有明显延迟,因为brush的渲染是GPU加速的纹理填充或渐变绘制,远快于实时像素模糊计算。
内容的提问来源于stack exchange,提问作者M conrey




