[SOLVED] QSGVertexColorMaterial alpha value not working?



  • I have a custom geometry that uses a QSGVertexColorMaterial to give each vertex in the geometry a rgba value. The rbg value is set as expected, but the alpha value has no affect if there is a background color set for anything behind the custom geometry. I modified the "Scene Graph - Custom" example to demonstrate this issue.

    In beziercurve.cpp I changed the updatePaintNode function to use a QSGVertexColorMaterial instead of a QSGFlatColorMaterial as follows:

    @
    QSGNode *BezierCurve::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *)
    {
    QSGGeometryNode *node = 0;
    QSGGeometry *geometry = 0;

    if (!oldNode) {
        node = new QSGGeometryNode;
        geometry = new QSGGeometry(QSGGeometry::defaultAttributes_ColoredPoint2D(), m_segmentCount);
        geometry->setLineWidth(2);
        geometry->setDrawingMode(GL_LINE_STRIP);
        node->setGeometry(geometry);
        node->setFlag(QSGNode::OwnsGeometry);
    

    // QSGFlatColorMaterial *material = new QSGFlatColorMaterial;
    // material->setColor(QColor(255, 0, 0));
    QSGVertexColorMaterial *material = new QSGVertexColorMaterial;
    node->setMaterial(material);
    node->setFlag(QSGNode::OwnsMaterial);
    } else {
    node = static_cast<QSGGeometryNode *>(oldNode);
    geometry = node->geometry();
    geometry->allocate(m_segmentCount);
    }

    QRectF bounds = boundingRect();
    

    // QSGGeometry::Point2D *vertices = geometry->vertexDataAsPoint2D();
    QSGGeometry::ColoredPoint2D *vertices = geometry->vertexDataAsColoredPoint2D();
    for (int i = 0; i < m_segmentCount; ++i) {
    qreal t = i / qreal(m_segmentCount - 1);
    qreal invt = 1 - t;

        QPointF pos = invt * invt * invt * m_p1
                    + 3 * invt * invt * t * m_p2
                    + 3 * invt * t * t * m_p3
                    + t * t * t * m_p4;
    
        float x = bounds.x() + pos.x() * bounds.width();
        float y = bounds.y() + pos.y() * bounds.height();
    
        vertices[i].set(x, y, 255, 0, 0, 0);
    }
    
    node->markDirty(QSGNode::DirtyGeometry);
    return node;
    

    }
    @

    In main.qml I changed the root QML element from an Item to a Rectangle in order to add a background color as follows:

    @
    Rectangle {
    width: 300
    height: 200

    // Comment this line out and it works,
    color: "black"
    
    BezierCurve {
        id: line
        anchors.fill: parent
        anchors.margins: 20
    
        property real t
        SequentialAnimation on t {
            NumberAnimation { to: 1; duration: 2000; easing.type: Easing.InOutQuad }
            NumberAnimation { to: 0; duration: 2000; easing.type: Easing.InOutQuad }
            loops: Animation.Infinite
        }
    
        p2: Qt.point(t, 1 - t)
        p3: Qt.point(1 - t, t)
    }
    
    Text {
        anchors.bottom: line.bottom
    
        x: 20
        width: parent.width - 40
        wrapMode: Text.WordWrap
    
        text: "This curve is a custom scene graph item, implemented using GL_LINE_STRIP"
    }
    

    }
    @

    If you remove the 'color' property from the rectangle, the alpha value in the vertex data works as expected. If the 'color' property is set, the alpha value has no effect.

    Can somebody explain why? Perhaps this is a bug or perhaps I don't understand how the QSGVertexColorMaterial is supposed to work.

    Thanks in advance



  • Hi there - I've been having the same problem. Vertex alpha is ignored if if you have a colored rectangle in the background. Did you ever find a solution?

    Cheers,
    Ben.



  • This was a while ago so I apologize that I don't remember all of the details. To solve this problem, I wrote my own QSGMaterial and QSGMaterialShader subclasses to replace QSGVertexColorMaterial and QSGVertexColorMaterialShader. I used the QSGFlatColorMaterial and QSGVertexColorMaterial source code as a starting point.

    I turned the color in the vertex shader from an attribute to a uniform value so I could explicitly set it in updateState() like so:

    @
    const QColor &c = newMaterial->color();

    if (oldMaterial == 0 || c != oldMaterial->color())
    {
        QVector4D v(c.redF(), c.greenF(), c.blueF(), c.alphaF());
        program()->setUniformValue(m_color_id, v);
    }
    

    @

    I never got a chance to focus too much on this problem. I ended up not needing this code and moved on to something else. It was a good exercise though since I was able to learn how QSGMaterial works.



  • The color you are specifying is r=255, g=0, b=0, a=0 (aka invisible red)

    The blend mode used by the scene graph is glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA) which gives you premultiplied blending. A "valid" color in premultiplied mode must have r <= a (same for g and b of course). If it doesn't, then that color channel will overflow, giving you additive blending instead.

    So... There is no bug, but you need to specify the colors as premultiplied. The docs could probably be a bit more helpful in this regard :)



  • That makes sense. Thanks for the answer :)

    I confirmed what you said by switching the background color to white (so I can see a black line) and the vertex color to r=0, g=0, b=0, a=0 (invisible black). Now when I switch a from 0 to 255 I get what I was expecting.


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.