Problems with Open-Source Downloads read https://www.qt.io/blog/problem-with-open-source-downloads and https://forum.qt.io/post/638946

Qt3D: QGeometryData::detach() does not function as expected



  • StackOverflow is failing me, so I wondered if anyone here would be able to explain some Qt3D to me:

    I'm trying to get my head around how the QGeometryData class works in the Qt3D library. I understand that it encapsulates shared data, but even after calling detach() (whose description is "Force this geometry to ensure it has its own unshared internal data block, making a copy in the case that it is currently shared"), modifications to my original object are reflected in the QGeometryData object when they shouldn't be, as far as I can see.

    My process is as follows:

    • A RenderBox object (my class) is set up to reside at the origin of the world.
    • toGeomData() is called in order to convert the object's data (origin, min/max points) into actual geometry data:

    @QGeometryData RenderBox::toGeomData() const
    {
    // Calculate the min and max co-ordinates in world space.
    QVector3D min = m_vecPosition + minimum();
    QVector3D max = m_vecPosition + maximum();
    QColor colMin = colorMin();
    QColor colMax = colorMax();
    float colMinR = colMin.redF();
    float colMinG = colMin.greenF();
    float colMinB = colMin.blueF();
    float colMaxR = colMax.redF();
    float colMaxG = colMax.greenF();
    float colMaxB = colMax.blueF();
    QGeometryData geom;

    // Order of vertices:
    // 0. Minimum
    // 1. Minimum with modified X co-ord
    // 2. Minimum with modified X and Z co-ords
    // 3. Minimum with modified Z co-ord
    // 4. Maximum with modified Z co-ord
    // 5. Maximum with modified Z and X co-ords
    // 6. Maximum with modified X co-ord
    // 7. Maximum
    // This gives us an easy counter-clockwise winding for the top and bottom faces.
    
    const QVector3D verts[8] =               // Taking Z as "north" and looking down on the box (Y pointing at us), we have:
    {
        min,                                    // Lower SE 0
        QVector3D(max.x(), min.y(), min.z()),   // Lower SW 1
        QVector3D(max.x(), min.y(), max.z()),   // Lower NW 2
        QVector3D(min.x(), min.y(), max.z()),   // Lower NE 3
        QVector3D(max.x(), max.y(), min.z()),   // Upper SW 4
        QVector3D(min.x(), max.y(), min.z()),   // Upper SE 5
        QVector3D(min.x(), max.y(), max.z()),   // Upper NE 6
        max                                     // Upper NW 7
    };
    
    QColor cols[8] = 
    {
        QColor(0.0, 0.0, 0.0),
        QColor(0.0, 0.0, 0.0),
        QColor(0.0, 0.0, 0.0),
        QColor(0.0, 0.0, 0.0),
        QColor(0.0, 0.0, 0.0),
        QColor(0.0, 0.0, 0.0),
        QColor(0.0, 0.0, 0.0),
        QColor(0.0, 0.0, 0.0)
    };
    
    QVector3D dir = (max - min).normalized();
    
    // Set each vertex's colour appropriately.
    for ( int i = 0; i < 8; i++ )
    {
        float extent = scalarProjection((verts[i]-min).normalized(), dir);
        //qDebug() << "Extent for" << verts[i] << "=" << extent;
        cols[i].setRedF(colMinR + (extent * (colMaxR-colMinR)));
        cols[i].setGreenF(colMinG + (extent * (colMaxG-colMinG)));
        cols[i].setBlueF(colMinB + (extent * (colMaxB-colMinB)));
    }
    
    // Normals for faces
    const QVector3D nTop(0, 1, 0);      // Up    = +Y
    const QVector3D nBottom(0, -1, 0);  // Down  = -Y
    const QVector3D nNorth(0, 0, 1);    // North = +Z
    const QVector3D nSouth(0, 0, -1);   // South = -Z
    const QVector3D nEast(-1, 0, 0);    // East  = -X
    const QVector3D nWest(1, 0, 0);     // West  = +X
    
    int n = 0;
    // Top face
    geom.appendVertex(verts[4], verts[5], verts[6], verts[7]);
    geom.appendNormal(nTop, nTop, nTop, nTop);
    geom.appendColor(cols[4], cols[5], cols[6], cols[7]);
    geom.appendIndex(n);geom.appendIndex(n+1);geom.appendIndex(n+2);
    geom.appendIndex(n+2);geom.appendIndex(n+3);geom.appendIndex(n);
    
    n += 4;
    // Bottom face
    geom.appendVertex(verts[0], verts[1], verts[2], verts[3]);
    geom.appendNormal(nBottom, nBottom, nBottom, nBottom);
    geom.appendColor(cols[0], cols[1], cols[2], cols[3]);
    geom.appendIndex(n);geom.appendIndex(n+1);geom.appendIndex(n+2);
    geom.appendIndex(n+2);geom.appendIndex(n+3);geom.appendIndex(n);
    
    // ...and so on.
    
    // Return the GeomData.
    return geom;
    

    }@

    • A copy of the QGeometryData is returned.
    • detach() is called on the returned copy.
    • The RenderBox then has its origin changed from 0, 0, 0 to 2, 2, 2.
    • The original QGeometryData, exported before the change, is given to the scene builder; the RenderBox is not.
    • When the scene renders, the geometry is present at 2, 2, 2 and not 0, 0, 0 as expected.

    Am I interpreting this wrong? Is there a way to export an object (which contains only minimal data, ie. origin and min/max vectors) to geometry data (ie. vertices and normals) and have the geometry data then become completely independent of the object?

    Thanks.


  • Lifetime Qt Champion

    Hi,

    Since Qt3D is not yet released, I would recommend asking this question on the "interest":http://lists.qt-project.org/mailman/listinfo/interest mailing list. You'll find there Qt's developers/maintainers (this forum is more user oriented)



  • Thanks, I'll try that.

    Just for info: I realised I'd made a mistake in my rendering code. I'm still getting a problem with only one set of geometry being rendered, but it seems to be related to QGLBuilder rather than QGeometryData.


Log in to reply