[QT3D] minExtent and maxExtent not giving the right values
-
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.

Here is my result for now :

As you can see, I'm having a problem with the plane which is not correctly positionned.
I'm using a
Qt3DExtras::QPlaneMeshfor it, and translating it usingQt3DCore::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 whereminYis the lowest y value of the bounding box of the displayed mesh. As far as I understand the documentation, I need to use theminExtentfunction on theQGeometryassociated to theQMesh. Let's saymeshis the mesh to display, I'm doingminY = mesh.geometry()->minExtent().y(). This is not working,minYis always0.0f.So basically I'm asking for help to compute this
minYvalue :/I made a minimal example, here is the code (the problem is in
handleStatusChangedinmyscene.cpp) :
main.cpp
myscene.h
myscene.cppThanks for your help !
-
aaaaand I found the solution :


As you can see, the floor origin is now perfectly positionned (and fits with any mesh).
Solution in short :
- handle the
statusChangedsignal - 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
minExtentChangedsignal by connecting it to a function ONLY ONCEstatus == 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::Readystatus : 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
ifstatement ofhandleStatusChanged, you will observe that theifstatement 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
minExtentChangedsignal because before that, the QGeometry associated tomeshis not set. You cannot connect tomesh.geometry()immediatly after a call tosetSourcebecause the QGeometry it points to isnullptr, and change only once the QMesh is "Ready". That's the reason why I'm connecting only in theifstatement ofhandleStatusChangedHopefully this will help some people.
PS : I still do not understand how to use
updateImplicitBounds(), but I'm done with my issue here. - handle the
-
Still stucked, but I noticed that the call to
mesh.updateImplicitBounds();is returningfalseinmyscene.cppSadly, 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.
-
Reason why
updateImplicitBounds()is returning falseI found out why
mesh.updateImplicitBounds();is returning false :meshhas noQGeometryViewassociated to it, andupdateImplicitBounds()is defined inqboundingvolume.cppas :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
QGeometryViewassociated tomesh.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. -
aaaaand I found the solution :


As you can see, the floor origin is now perfectly positionned (and fits with any mesh).
Solution in short :
- handle the
statusChangedsignal - 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
minExtentChangedsignal by connecting it to a function ONLY ONCEstatus == 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::Readystatus : 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
ifstatement ofhandleStatusChanged, you will observe that theifstatement 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
minExtentChangedsignal because before that, the QGeometry associated tomeshis not set. You cannot connect tomesh.geometry()immediatly after a call tosetSourcebecause the QGeometry it points to isnullptr, and change only once the QMesh is "Ready". That's the reason why I'm connecting only in theifstatement ofhandleStatusChangedHopefully this will help some people.
PS : I still do not understand how to use
updateImplicitBounds(), but I'm done with my issue here. - handle the