C++和Qt: 绘画程序 - 渲染透明线条而不重叠alpha联接

6

我开始编写一个与绘图板交互的画图程序。根据笔在平板上施加的压力,我会改变正在绘制的线条的Alpha值。这个机制是有效的。

细的线看起来不错,看起来就像真正的草图。但由于我是在两点之间画线(就像Qt涂鸦教程中一样)进行绘画,所以在线接头处有一个Alpha重叠,对于粗的笔触非常明显。

下面是线之间连接的效果:

您可以看到,线段之间有一个丑陋的Alpha混合。

为了解决这个问题,我决定使用QPainterPath来渲染线条。 两个问题如下:

  1. 长时间连续使用粗路径会使程序很卡。
  2. 由于路径是连接的,因此对Alpha值的任何更改都会影响整个路径(但我不想这样做,因为我想保留混合效果)。

以下图像使用了QPainterPath

我想保留的混合效果。

下图显示了第2个问题,即会更改整个路径的Alpha值和粗细程度。 enter image description here

红色文本应该是:“如果在不从平板表面移除笔的情况下增加压力,则线条变粗”(Alpha变为不透明)

另一件事是,使用这种方法我只能得到从深到浅(或从粗到细)路径宽度的混合轨迹,但不能得到从浅到深的轨迹。我不确定为什么会出现这种效果,但我最好的猜测是与路径的线段更新有关。

我确实让程序基于笔在平板上施加的压力增加/减少Alpha值和线条厚度。

问题是我想渲染没有Alpha重叠的线条,而QPainterPath会更新整个路径的Alpha值和厚度,这是我不想要的。

这是创建路径的代码:

    switch(event->type()){
    case QEvent::TabletPress:
        if(!onTablet){
            onTablet = true;

            //empty for new segment
            freePainterPath();
            path = new QPainterPath(event->pos());
        }   break;

    case QEvent::TabletRelease:
        if(onTablet)
            onTablet = false;
            break;

    case QEvent::TabletMove:
        if(path != NULL)
            path->lineTo(event->pos());

        if(onTablet){

            //checks for pressure of pen on tablet to change alpha/line thickness
            brushEffect(event);

            QPainter painter(&pixmap);

            //renders the path
            paintPixmap(painter, event);
        }   break;
    default:;
}
update();

我希望将单一路径效果应用于由Krita绘画程序创建的图像:enter image description here

那么,关于Krita中的最后一个波浪线:您是否打算让回头的画笔不与画笔的前一笔叠加?如果画笔在同一区域来回涂抹,它不会变得更暗吗? - Yakk - Adam Nevraumont
这是一条单线路径。我在平板上加强按压以更改Alpha值。在Krita中,如果相同路径交叉,则会覆盖绘制。如果两个不同路径相交,则会出现可见的透明度交叉。但我并不真的关心那个细节。我只想像第一张图片那样绘制没有Alpha重叠的直线。 - lambda
2个回答

5
我知道这个问题很古老,已经有了一个被接受的答案,但是如果有其他人需要答案,那么这里就是答案:
您需要将painter的合成模式设置为源。它现在会同时绘制源和目标。
painter.setCompositionMode(QPainter::CompositionMode_Source);

如果您想让透明区域显示出底层绘图,请将结果的组合模式设置回CompositionMode_SourceOver,并在目标上绘制。我不知道您是否仍在寻找答案,但我希望这可以帮助某些人。

5
为了模拟Krita绘画程序:
  1. 保留原目标表面的备份。
  2. 使用画笔在一个完全透明的刮擦表面上进行绘画。
  3. 在该表面上,您的合成规则是“采用最大不透明度”。
  4. 跟踪该表面的脏区域,并对(刮擦表面)和(原目标表面)进行传统合成并显示结果。确保此操作不会损坏原目标表面。

现在,您不必保留整个原目标表面 - 只需保留使用此工具绘制的部分即可。(良好的基于瓦片的惰性写入图像系统将使此过程变得简单)。

根据您正在绘制的段大小,您可能需要在段之间插值,以使画笔的强度稍微减弱。您的画笔形状也可能需要改进。但这些与透明度问题无关。

至于Qt的奇怪之处,我不了解足够的Qt来告诉您如何处理Qt画笔代码的怪癖。但上述“键掩码”策略应解决您的Alpha重叠问题。

我不知道如何在Qt中实现这个。看了一下Qt合成模式,我没有看到明显的方法来指定“取最大值”作为结果alpha通道。也许可以巧妙地结合颜色和alpha通道来实现。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接