Uploaded image for project: 'Qt'
  1. Qt
  2. QTBUG-78313

viewEntity does not compute smallest bounding sphere

    XMLWordPrintable

Details

    • Bug
    • Resolution: Unresolved
    • P2: Important
    • None
    • 5.13.0
    • Qt3D
    • None
    • All

    Description

      The following code shows a 3D Scene with two spheres with centers at (20,-10,0) and (20,10,0) and radii 0.5.

      Both spheres are below an empty QEntity called rootEntity.

      Calling viewEntity on this rootEntity, should result in a spherical bounding volume centered at (20,0,0) with radius (20+2*0.5)/2.

      Instead the program returns:

      Bounding Sphere: QVector3D(12.1432, 2.14455, -1.32699e-08) 14.9644

      Calling viewEntity on sphere1 and sphere2 gave the desired results of:

      Bounding Sphere: QVector3D(20, 10, -2.18557e-08) 0.5
      Bounding Sphere: QVector3D(20, -10, -2.18557e-08) 0.5

      My best guess is that there is an error inside the ComputeFilteredBoundingVolumeJob.cpp on lines 61-68, but I was not able to nail it down.

      #include <QApplication>
      #include <QWidget>
      #include <QLoggingCategory>
      #include <QVBoxLayout>
      #include <QFrame>
      #include <Qt3DRender/QRenderSettings>
      #include <Qt3DCore/QTransform>
      #include <Qt3DRender/QCamera>
      #include <Qt3DExtras/QSphereMesh>
      #include <Qt3DExtras/QDiffuseSpecularMaterial>
      #include <Qt3DExtras/QForwardRenderer>
      #include <Qt3DExtras/Qt3DWindow>
      #include <Qt3DRender/QCamera>
      #include <Qt3DRender/QCameraLens>
      #include <QPushButton>
      Qt3DCore::QEntity* createSphereMesh()
      {
       auto sphereMat = new Qt3DExtras::QDiffuseSpecularMaterial;
       sphereMat->setDiffuse(QColor(Qt::blue));
      auto mesh = new Qt3DExtras::QSphereMesh();
       mesh->setRadius(0.5);
      auto meshEntity = new Qt3DCore::QEntity;
       meshEntity->addComponent(mesh);
       meshEntity->addComponent(sphereMat);
      return meshEntity;
      }
      int main(int argc, char* argv[])
      {
       QApplication a(argc, argv);
       auto view = new Qt3DExtras::Qt3DWindow();
       view->defaultFrameGraph()->setClearColor(QColor(127, 127, 127));
       auto settings = view->renderSettings();
       settings->setActiveFrameGraph(view->activeFrameGraph());
      auto rootEntity = new Qt3DCore::QEntity();
       view->setRootEntity(rootEntity);
      auto sphere1 = createSphereMesh();
       sphere1->setParent(rootEntity);
       auto trafo1 = new Qt3DCore::QTransform;
       trafo1->setTranslation(QVector3D(20, 10, 0));
       sphere1->addComponent(trafo1);
       auto sphere2 = createSphereMesh();
       sphere2->setParent(rootEntity);
       auto trafo2 = new Qt3DCore::QTransform;
       trafo2->setTranslation(QVector3D(20, -10, 0));
       sphere2->addComponent(trafo2);
      QObject::connect(view->camera()->lens(), &Qt3DRender::QCameraLens::viewSphere, [&](const QVector3D& center, float radius) {
       qDebug() << "Bounding Sphere:" << center << radius;
       auto boundingSphereEntity = new Qt3DCore::QEntity;
      auto sphereMat = new Qt3DExtras::QDiffuseSpecularMaterial;
       sphereMat->setAlphaBlendingEnabled(true);
       sphereMat->setDiffuse(QColor(255,255,255,80));
      auto mesh = new Qt3DExtras::QSphereMesh();
       mesh->setRadius(radius);
      boundingSphereEntity->addComponent(sphereMat);
       boundingSphereEntity->addComponent(mesh);
      auto trafoAll = new Qt3DCore::QTransform;
       trafoAll->setTranslation(center);
       boundingSphereEntity->addComponent(trafoAll);
       boundingSphereEntity->addComponent(mesh);
       boundingSphereEntity->addComponent(sphereMat);
       boundingSphereEntity->setParent(rootEntity);
       });
       auto container = QWidget::createWindowContainer(view);
      auto viewAllBtn = new QPushButton("View Root Entity");
       QObject::connect(viewAllBtn, &QPushButton::clicked, [&]() {
       view->camera()->viewEntity(rootEntity);
       });
       QFrame frame;
       frame.setFixedSize(500, 500);
       frame.setLayout(new QVBoxLayout);
       frame.layout()->addWidget(container);
       frame.layout()->addWidget(viewAllBtn);
      frame.show();
      return a.exec();
      }
      
      

       

      I further investigated, as I really needed this feature and stumbled across the source tst_boundingsphere.cpp in qt3d/tests/auto/render/boundingsphere.

      There I found the following interesting line:

      QTest::newRow("CubeMesh") << "qrc:/cube.qml" << QVector3D(0.0928356f, -0.212021f, -0.0467958f) << 1.07583f; // weird!

      It is indeed not obvious, why a cube mesh of extents 1. should have a bounding volume like this. At least the radius of the bounding sphere should be sqrt(3)/2. The center of the cube should be something like (0.5,0.5,0.5).

      I guess the problem lies in the implementation of the qt3d/src/render/frontend/sphere.cpp, as there is a fault in the implementation of an invalid sphere. Assume that there is an void entity without any points, then it will have a bounding sphere with center=(0,0,0) with r=0. Assume now, that you will another bounding sphere with center=(1,1,1) and r=0.1.

      Then expandToContain should just give center=(1,1,1) and r=0.1, but expandToContain will give something around center=(0.55,0.55,0.55) and r=0.55.

      I would suggest to implement invalid spheres being the ones having a radius being < 0. 

      In case the method transformed is called on an invalid sphere, there should be nothing to do.

       

       

       

      Attachments

        No reviews matched the request. Check your Options in the drop-down menu of this sections header.

        Activity

          People

            seanharmer Sean Harmer
            aleph0 Frank Simon
            Votes:
            1 Vote for this issue
            Watchers:
            2 Start watching this issue

            Dates

              Created:
              Updated:

              Gerrit Reviews

                There are no open Gerrit changes