You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何自定义带模糊效果的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

火山引擎 最新活动