0

Good morning,

I developed an application that renders a textured cube and rotates it using quaternions. I used Qt6 and QOpenGL functions to make this work.

Then I wanted to load a full 3D model ( without drawing it using shaders or opengl functions ). So I kept looking for many methods and ended up using an example with QT3D to load a file.PLY.

The problem is that I need the model matrix of the object so that I can perform transformations on it.

I know I can do it using QTransform class functions but I don't want to do that. Here is the code I used to load the ply file. It works perfectly

int main(int argc, char* argv[])

{

QApplication app(argc, argv);
Qt3DExtras::Qt3DWindow *view = new Qt3DExtras::Qt3DWindow();
view->defaultFrameGraph()->setClearColor(QColor(QRgb(0x4d4d4f)));
view->defaultFrameGraph()->setClearColor(QColor(255,255,255,1));
QWidget *container = QWidget::createWindowContainer(view);
QSize screenSize = view->screen()->size();
container->setMinimumSize(QSize(200, 100));
container->setMaximumSize(screenSize);
QWidget *widget = new QWidget;
QHBoxLayout *hLayout = new QHBoxLayout(widget);
hLayout->addWidget(container, 1);


widget->setWindowTitle(QStringLiteral("Satellite"));


Qt3DInput::QInputAspect *input = new Qt3DInput::QInputAspect;
view->registerAspect(input);

// Root entity
Qt3DCore::QEntity *rootEntity = new Qt3DCore::QEntity();


// Camera
Qt3DRender::QCamera *cameraEntity = view->camera();

cameraEntity->lens()->setPerspectiveProjection(45.0f, 16.0f/9.0f, 0.1f, 100000.0f);//projection



 cameraEntity->setPosition(QVector3D(-40000, 40000, 40000.0f));
 cameraEntity->setUpVector(QVector3D(0, 0, 1));
//cameraEntity->setViewCenter(QVector3D(0, 0, 10000));
cameraEntity->setViewCenter(QVector3D(0, 0, 10));


Qt3DCore::QEntity *lightEntity = new Qt3DCore::QEntity(rootEntity);
Qt3DRender::QPointLight *light = new Qt3DRender::QPointLight(lightEntity);
light->setColor("white");
light->setIntensity(1);
lightEntity->addComponent(light);
Qt3DCore::QTransform *lightTransform = new Qt3DCore::QTransform(lightEntity);
lightTransform->setTranslation(cameraEntity->position());
lightEntity->addComponent(lightTransform);




//Loading .ply data
const QUrl data = QUrl::fromLocalFile("PATH/challengeone.PLY");
qDebug() << data << data.isValid() << data.toLocalFile() << QFileInfo(data.toLocalFile()).exists() << data.fileName();
qDebug() << QDir::currentPath();
Qt3DRender::QMesh *bodyMesh = new Qt3DRender::QMesh();
bodyMesh->setMeshName("bodyMesh");
bodyMesh->setSource(data);

Qt3DCore::QTransform *bodyTransform = new Qt3DCore::QTransform;
bodyTransform->setScale3D(QVector3D(90.0, 90.0, 90.0));

bodyTransform->setRotationX(90.0);
Qt3DExtras::QPhongMaterial *bodyMaterial = new Qt3DExtras::QPhongMaterial();
Qt3DCore::QEntity *plyEntity = new Qt3DCore::QEntity(rootEntity);
plyEntity->addComponent(bodyMesh);
plyEntity->addComponent(bodyMaterial);
plyEntity->addComponent(bodyTransform);

// Set root object of the scene
view->setRootEntity(rootEntity);


// Show window
widget->show();
widget->resize(1200, 800);

return app.exec();
}

Now I think the bodyTransform in this example is equivalent to the model matrix since we can apply transformations on it. And the camera entity is equivalent to gluLookAt or lookAt( QopenGL function).

But in the old code where I can rotate the model, I'm working with QOpenGL functions and I don't want to change all of it.

My question is the following: Is it possible to keep working with QOpenGL and inside the paintGL function, use the QT3D library to just load the model and then assign a model view matrix to it that can be manipulated using QOpenGL functions and not QTransform.

In the example of QT3D, I tried to draw objects using the old OpenGL functions like glvertex but they weren't rendered in the scene.

I want to do something like this:

 glMatrixMode(GL_PROJECTION);
glLoadMatrixf(cameraEntity->lens());

glMatrixMode(GL_MODELVIEW);
glLoadMatrixf(bodyTransform);
gluLookAt(2.0,2.0,0.0,0.0,0.0,-5.0,0.0,1.0,0.0);


glTranslatef(0.0,0.0,-5.0);

glRotatef(180.0,0.0,1.0,0.0);
glRotatef(-90.0,1.0,0.0,0.0);

glScalef(0.4,0.4,0.4);
DrawOribtalFrame();

I mean I want to load both projection and modelview matrices into the openGL pipeline and use the modelview to draw and manipulate other objects.

Of course the code I wrote above isn't correct because bodyTransform is a QTransform and cameraEntity is a QCamera. they're not Matrices (QMatrix4x4 class).

EDIT: What I did is that I store the projection and model matrices values like this:

projection=cameraEntity->projectionMatrix();
viewmatrix=cameraEntity->viewMatrix();
model=bodyTransform->matrix();

then I calculated the modelview matrix ( product of viewmatrix and model)

And then:

   glMatrixMode(GL_PROJECTION);

   glLoadMatrixf(projection.constData());
   glMatrixMode(GL_MODELVIEW);

   glLoadMatrixf(modelview.constData());


   glTranslatef(0.0,0.0,-5.0);
   glRotatef(180.0,0.0,1.0,0.0);

   glRotatef(-90.0,1.0,0.0,0.0);
   glScalef(0.4,0.4,0.4);

//draw coordinate system

I loaded them in the OpenGL pipeline and tried to draw a coordinate system but that didn't work.

Thank you all for your help.

1 Answers1

0

It's a bit difficult to answer your question because it's so packed with things but I'll try to answer anyways:

Maybe regarding your question "is it possible to combine Qt3D and OpenGL"? Well, it's definitely possible but you'd have to get all the data that has been loaded in Qt3D and transfer it to OpenGL, that's going to be a lot of work.

So a couple of suggestions/remarks:

  1. Stick to one of either. I did mix Qt3D and OpenGL in my Qt3DWidget implementation but to render Qt3D offscreen and then draw that using OpenGL, that's something different.
  2. Use shaders in OpenGL (unrelated to your concrete problem). They're not that difficult and give you way more flexibility than the old programmable pipeline. Believe me, I found them really scary but if you can program C++ (which you obviously can) then you are more than capable of programming shaders. Find a simple tutorial and implement a simple shader in OpenGL and all the black magic will become more reasonable.
  3. Use QSceneLoader to load models in Qt3D. This will automatically load all respective materials, etc. Qt3D uses Assimp in the background. You could of course also use Assimp for your existing code to load the model. But it's a lot of work, I'd stick to Qt3D.
  4. Why exactly don't you want to use QTransform? For me it seems the biggest step was to load the model and show it. Adding simple functionality to rotate the object using the transform's matrix shouldn't be hard. Like you even already mentioned, you can get the matrix from the transform and also set it. Means you can manipulate it as a 4x4 matrix and set the result on the transform.
  5. Maybe a bit too complex but if you're interested in understanding more how to manipulate objects in Qt3D, I also implemented a Qt3DGizmo. It takes a bit of work to setup because you need a dedicated branch for the gizmo to make sure it's always drawn ontop of other objects but works fine otherwise.

It's a good first question you asked with a lot of examples and code, maybe just try to make it a bit more concise next time it's a bit difficult to answer like this ;) (which I guess is apparent in the many points I wanted to make)

Florian Blume
  • 3,237
  • 17
  • 37
  • First of all, thank you for your precious help, you made it so clear. I checked the example you provided, are you using windows or Linux ? I tried to run the example but I get many errors such as : undefined reference to `__imp_glDisable' undefined reference to `__imp_glEnable' undefined reference to `__imp_glClear' undefined reference to `__imp_glBindTexture' undefined reference to `__imp_glDrawArrays' I think these are linker errors related maybe to the OS I'm using no ? – AppDev2022 Jul 07 '22 at 11:17
  • What exactly did you try? The widget or the gizmo? Either way, you cannot use the pre-built binaries as I'm on Linux, just as you thought :) So build it yourself and you should be able to use it (I only used Qt and no external libraries) – Florian Blume Jul 07 '22 at 11:19