Qt3D: Create mirrored object



  • Hi, I'm new to Qt3D and 3D programming in general, but using Qt for 6 years.

    Does anyone know a simple way to to mirror a mesh in Qt3D along the x-Axis?

    Right now I'm working on a 3D viewer (using QML) for my company. A similar viewer already exists, which was written in BabylonJS (by an external worker). So I already have the model and texture files, but the models contain only the objects from one side in the scene. The other side needs to be created by mirroring the existing models along the x axis.

    So far I have tried to use a Transform with scale3d: Qt.vector3d(-1,1,1), but now all the vertex windings are inverted. So all I'm seeing are the backfaces. See my code below.

    Entity{
        Mesh{
            id: zahnfleischMirrorMesh
            source: "file:///D:/3D_Models/Dental/Test/Zahnfleisch/zahnfleisch.obj"
        }
    
        TextureLoader{
            id: zahnfleischMirrorTexture
            source: "file:///D:/3D_Models/Dental/Test/Zahnfleisch/unterkieferFarbe.jpg"
            mirrored: true
        }
    
        DiffuseMapMaterial{
            id: zahnfleischMirrorMaterial
            diffuse: zahnfleischMirrorTexture
            ambient: Qt.rgba( 1, 1, 1, 1.0 )
            specular: Qt.rgba( 0.113561, 0.113561, 0.113561, 1.0 )
        }
    
        Transform{
            id: mirrorTransform
            scale3D: Qt.vector3d(-1,1,1)
        }
    
        components: [mirrorTransform, zahnfleischMirrorMesh, zahnfleischMirrorMaterial]
    }
    

    So far I have come up with the following ideas to solve my problem:

    1. Go to blender and mirror the models manually
      • I don't really like this option.
      • This would double the data, which will result in longer loading times and more memory usage
      • Also it's a lot of work... and the models might change in the future
    2. Try to manually reorder the vertices, obtained from the mesh's geometry
      • not sure how much work this would be or if this is the optimal solution

    Thank you in advance
    Jan



  • Ok, solution 2 was simpler than i expected. I'll post my code below, in case someone else needs something similar. It flips a QEntity along the x-axis and the winding of the triangles. It only works with the primitive type QGeometryRenderer.Triangles.

    Jan

    void mirrorEntity(Qt3DCore::QEntity *entity)
    {
        for (QNode* node: entity->childNodes())
        {
            if (QEntity* e = dynamic_cast<QEntity*>(node))
                mirrorEntity(e);
            if (QGeometryRenderer* r = dynamic_cast<QGeometryRenderer*>(node))
                mirrorGeometryRenderer(r);
        }
    }
    
    void mirrorGeometryRenderer(QGeometryRenderer *geometryRenderer)
    {
        QGeometry* geometry = geometryRenderer->geometry();
        for (QAttribute* a : geometry->attributes())
        {
            if (a->name() == QAttribute::defaultPositionAttributeName())
            {
                QByteArray data = a->buffer()->data();
    
                // flip along x-axis
                float *bufferContent = reinterpret_cast<float*>(data.data());
                int chunkSize = a->byteStride()/sizeof(float);
                int positionOffset = a->byteOffset();
                for (uint i=0; i<a->count()*chunkSize; i+=chunkSize)
                {
                    int offsetI = i + positionOffset;
                    bufferContent[offsetI] = -bufferContent[offsetI]; // invert x
                }
    
                // change winding
                const int size = a->byteStride();
                char* tmp = new char[size];
                for (int i=0; i<data.length(); i+=a->byteStride()*3)
                {
                    memcpy(tmp, &data.data()[i+size], size);
                    memcpy(&data.data()[i+size], &data.data()[i+size*2], size);
                    memcpy(&data.data()[i+size*2], tmp, size);
                }
                delete[] tmp;
    
                a->buffer()->setData(data);
                break;
            }
        }
    }
    
    

Log in to reply