C++和Qt:绘图程序 - 渲染没有Alpha关节重叠的透明线

lam*_*bda 5 c++ qt

我已经开始创建一个与绘图平板电脑交互的绘图程序.根据笔在平板电脑上的压力,我改变了绘制线的alpha值.该机制有效.

细线看起来不错,它看起来很真实.但是因为我在两点之间绘制线条(比如在Qt涂鸦教程中)来绘制线条关节之间存在alpha重叠,所以对于粗笔划非常明显.

这是线对线结合的效果:

如您所见,线段之间存在难看的alpha混合.

为了解决这个问题,我决定使用a QPainterPath来渲染线条.这有两个问题:

  1. 一条长而连续的厚路径很快就会滞后于程序.
  2. 由于路径是连接的,因此它作为一个路径,因此对alpha值的任何更改都会影响整个路径(我不希望这样做,因为我想保留混合效果).

以下图片使用a QPainterPath.

我希望保持混合效果.

下图显示了第2个问题,它改变了整个路径的alpha和厚度在此输入图像描述

红色文字应显示为:"如果在不从平板电脑表面移除笔的情况下添加更多压力,则线条变粗"(并且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();
Run Code Online (Sandbox Code Playgroud)

我想要作为单一路径的期望效果(使用Krita绘图程序创建的图像):在此输入图像描述

Yak*_*ont 5

要模拟 Krita 绘画程序:

  1. 保留原始目标表面的备份。
  2. 用画笔在开始时完全透明的划痕表面上绘画。
  3. 在该表面上,您的堆肥规则是“采用最大不透明度”。
  4. 跟踪该表面的脏区域,并在(原始目标表面)上进行(划痕表面)的传统合成并显示结果。确保此操作不会损坏原始目标表面。

现在,您不必保留整个原始目标表面 - 只需保留您使用此工具绘制的部分即可。(一个好的基于平铺的延迟写入成像系统将使这变得容易)。

根据您绘制的线段大小,您可能需要在线段之间进行插值,以使画笔的强度变得不那么锐利。刷子的形状可能也需要修改。但这些与透明度问题无关。

至于Qt的怪事,我对Qt的了解还不够多,无法告诉大家如何应对Qt刷码的怪癖。但是上面的“key-mask”策略应该可以解决您的 alpha 重叠问题。

我不知道如何在 Qt 中做到这一点。浏览一下Qt 合成模式,我没有看到一个明显的方式来表示“取最大值”作为结果 alpha。也许某些东西以某种巧妙的方式涉及颜色和 Alpha 通道。


小智 5

我知道这个问题已经很老了,并且有一个可接受的答案,但万一其他人需要答案,这里是:

您需要将画家的构图模式设置为源.它现在绘制了源和目的地.

painter.setCompositionMode(QPainter::CompositionMode_Source);
Run Code Online (Sandbox Code Playgroud)

如果希望通过底层图形显示透明区域,则需要将结果的合成模式设置回CompositionMode_SourceOver并绘制目标.

我不知道你是否还在寻找答案,但我希望这对某人有所帮助.