Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. General talk
  3. Qt 6
  4. [QT3D] minExtent and maxExtent not giving the right values

[QT3D] minExtent and maxExtent not giving the right values

Scheduled Pinned Locked Moved Solved Qt 6
4 Posts 1 Posters 786 Views
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • SpazzS Offline
    SpazzS Offline
    Spazz
    wrote on last edited by Spazz
    #1

    Hey there,

    I'm trying to create a pretty simple .obj viewer rendering a mesh on a floor, like the default 3D viewer in Windows 10 illustrated below.

    3DViewerWindows.jpg

    Here is my result for now :

    myViewer.jpg

    As you can see, I'm having a problem with the plane which is not correctly positionned.

    I'm using a Qt3DExtras::QPlaneMesh for it, and translating it using Qt3DCore::QTransform.

    The problem is about this translation. What I'd like to do is to apply a translation (0.0f, minY, 0.0f) to the plane where minY is the lowest y value of the bounding box of the displayed mesh. As far as I understand the documentation, I need to use the minExtent function on the QGeometry associated to the QMesh. Let's say mesh is the mesh to display, I'm doing minY = mesh.geometry()->minExtent().y(). This is not working, minY is always 0.0f.

    So basically I'm asking for help to compute this minY value :/

    I made a minimal example, here is the code (the problem is in handleStatusChanged in myscene.cpp) :
    main.cpp
    myscene.h
    myscene.cpp

    Thanks for your help !

    1 Reply Last reply
    0
    • SpazzS Offline
      SpazzS Offline
      Spazz
      wrote on last edited by Spazz
      #4

      aaaaand I found the solution :

      yippipi.jpg
      icosphere.jpg

      As you can see, the floor origin is now perfectly positionned (and fits with any mesh).

      Solution in short :

      • handle the statusChanged signal
      • once status == Qt3DRender::QMesh::Ready, the mesh is loaded BUT its bounding box is not (necessarily?) computed yet. I made this assumption and this was the mistake.
      • handle the minExtentChanged signal by connecting it to a function ONLY ONCE status == Qt3DRender::QMesh::Ready
      • update the plane position in this function

      Here is the final code :

      void MyScene::handleStatusChanged(const Qt3DRender::QMesh::Status &status)
      {
          if(status == Qt3DRender::QMesh::Ready)
          {
                connect(mesh.geometry(), &Qt3DCore::QGeometry::minExtentChanged, this, &MyScene::handleMinExtentChanged);
          }
      }
      
      void MyScene::handleMinExtentChanged(const QVector3D & minExtent)
      {
          Qt3DCore::QTransform * planeTransform = new Qt3DCore::QTransform(&floorEntity);
      
          planeTransform->setTranslation(QVector3D(0.0f,mesh.geometry()->minExtent().y(),0.0f));
      
          floorEntity.addComponent(planeTransform);
      }
      

      More details

      I was mistaken by the Qt3DRender::QMesh::Ready status : the fact that the QMesh is flagged as "Ready" does not mean that its bounding box is computed.

      Indeed, minExtent and maxExtent values are set by the function setExtent in qgeometry.cpp. By setting one breakpoint in setExtent and one breakpoint in the if statement of handleStatusChanged, you will observe that the if statement breakpoint is triggered the first. That is, even thought the QMesh is "Ready", it's extents are not yet set.

      Furthermore, you have to wait for the QMesh to be "Ready" before connecting to the minExtentChanged signal because before that, the QGeometry associated to mesh is not set. You cannot connect to mesh.geometry() immediatly after a call to setSource because the QGeometry it points to is nullptr, and change only once the QMesh is "Ready". That's the reason why I'm connecting only in the if statement of handleStatusChanged

      Hopefully this will help some people.

      PS : I still do not understand how to use updateImplicitBounds(), but I'm done with my issue here.

      1 Reply Last reply
      1
      • SpazzS Offline
        SpazzS Offline
        Spazz
        wrote on last edited by
        #2

        Still stucked, but I noticed that the call to mesh.updateImplicitBounds(); is returning false in myscene.cpp

        Sadly, the documentation is not giving any detail about the possible reasons for such a thing :/

        I'm going to debug the source code, I'll keep you informed.

        1 Reply Last reply
        0
        • SpazzS Offline
          SpazzS Offline
          Spazz
          wrote on last edited by Spazz
          #3

          Reason why updateImplicitBounds() is returning false

          I found out why mesh.updateImplicitBounds(); is returning false : mesh has no QGeometryView associated to it, and updateImplicitBounds() is defined in qboundingvolume.cpp as :

          bool QBoundingVolume::updateImplicitBounds()
          {
              Q_D(QBoundingVolume);
              if (!d->m_view) //Triggered since there is no view associated to mesh
                  return false;
          
              auto data = BoundingVolumeComputeData::fromView(d->m_view);
              if (!data.valid())
                  return false;
          
              auto res = data.compute();
              if (!res.valid())
                  return false;
          
              d->setImplicitBounds(res.m_min, res.m_max, res.m_center, res.m_radius);
              return true;
          }
          

          The fact that this function always returns false makes sense because the first conditional is always triggered since I have no QGeometryView associated to mesh.

          Now I have a new problem because I don't even understand what is a QGeometryView, which is defined in the documentation as "A GeometryView holds all the information necessary to handle a Geometry" which is way too fuzzy to be understandable.

          1 Reply Last reply
          0
          • SpazzS Offline
            SpazzS Offline
            Spazz
            wrote on last edited by Spazz
            #4

            aaaaand I found the solution :

            yippipi.jpg
            icosphere.jpg

            As you can see, the floor origin is now perfectly positionned (and fits with any mesh).

            Solution in short :

            • handle the statusChanged signal
            • once status == Qt3DRender::QMesh::Ready, the mesh is loaded BUT its bounding box is not (necessarily?) computed yet. I made this assumption and this was the mistake.
            • handle the minExtentChanged signal by connecting it to a function ONLY ONCE status == Qt3DRender::QMesh::Ready
            • update the plane position in this function

            Here is the final code :

            void MyScene::handleStatusChanged(const Qt3DRender::QMesh::Status &status)
            {
                if(status == Qt3DRender::QMesh::Ready)
                {
                      connect(mesh.geometry(), &Qt3DCore::QGeometry::minExtentChanged, this, &MyScene::handleMinExtentChanged);
                }
            }
            
            void MyScene::handleMinExtentChanged(const QVector3D & minExtent)
            {
                Qt3DCore::QTransform * planeTransform = new Qt3DCore::QTransform(&floorEntity);
            
                planeTransform->setTranslation(QVector3D(0.0f,mesh.geometry()->minExtent().y(),0.0f));
            
                floorEntity.addComponent(planeTransform);
            }
            

            More details

            I was mistaken by the Qt3DRender::QMesh::Ready status : the fact that the QMesh is flagged as "Ready" does not mean that its bounding box is computed.

            Indeed, minExtent and maxExtent values are set by the function setExtent in qgeometry.cpp. By setting one breakpoint in setExtent and one breakpoint in the if statement of handleStatusChanged, you will observe that the if statement breakpoint is triggered the first. That is, even thought the QMesh is "Ready", it's extents are not yet set.

            Furthermore, you have to wait for the QMesh to be "Ready" before connecting to the minExtentChanged signal because before that, the QGeometry associated to mesh is not set. You cannot connect to mesh.geometry() immediatly after a call to setSource because the QGeometry it points to is nullptr, and change only once the QMesh is "Ready". That's the reason why I'm connecting only in the if statement of handleStatusChanged

            Hopefully this will help some people.

            PS : I still do not understand how to use updateImplicitBounds(), but I'm done with my issue here.

            1 Reply Last reply
            1

            • Login

            • Login or register to search.
            • First post
              Last post
            0
            • Categories
            • Recent
            • Tags
            • Popular
            • Users
            • Groups
            • Search
            • Get Qt Extensions
            • Unsolved