diff options
author | Miikka Heikkinen <miikka.heikkinen@qt.io> | 2019-02-14 18:24:17 +0200 |
---|---|---|
committer | Miikka Heikkinen <miikka.heikkinen@qt.io> | 2019-02-20 11:06:10 +0000 |
commit | 4071f251a0172df291a924eea33cc8d8274a59fb (patch) | |
tree | 131faecd9b08f47a133b4c2644dfab901ec6cf63 | |
parent | 22038fc6cbaef5ed0f400d6d77e1391ea352bb49 (diff) |
Fix picking issues when camera has a large far clip
The default QVector3D::unproject() implementation checks for
qFuzzyIsNull on w of the obj vector and inexplicably changes the value
to 1 in that case, which results in completely wrong unprojection.
Fixed by reimplementing unproject without qFuzzyIsNull check.
Task-number: QT3DS-3062
Change-Id: I2d3dea4f5e85f7fcaf576cef04dbff4fe9e3ad22
Reviewed-by: Antti Määttä <antti.maatta@qt.io>
Reviewed-by: Andy Nichols <andy.nichols@qt.io>
Reviewed-by: Laszlo Agocs <laszlo.agocs@qt.io>
-rw-r--r-- | src/runtime/q3dsinputmanager.cpp | 30 |
1 files changed, 28 insertions, 2 deletions
diff --git a/src/runtime/q3dsinputmanager.cpp b/src/runtime/q3dsinputmanager.cpp index 323b2a3..4547956 100644 --- a/src/runtime/q3dsinputmanager.cpp +++ b/src/runtime/q3dsinputmanager.cpp @@ -141,6 +141,32 @@ QMatrix4x4 calculateCameraViewMatrix(const QMatrix4x4 &cameraWorldTransform) QVector3D(upVector)); return QMatrix4x4(m); } + +// A copy of QVector3D::unproject with the difference that if obj.w() is nearly zero, we don't +// set it to one as that is extremely wrong, at least for our purposes. +// For determining pick rays, nearly zero values are good enough even if they may not result in +// completely pixel-accurate picks. +// This allows much larger far clip values to be used in cameras before picking breaks. +QVector3D unproject(const QVector3D &vector, + const QMatrix4x4 &modelView, const QMatrix4x4 &projection, + const QRect &viewport) +{ + QMatrix4x4 inverse = QMatrix4x4( projection * modelView ).inverted(); + + QVector4D tmp(vector, 1.0f); + tmp.setX((tmp.x() - float(viewport.x())) / float(viewport.width())); + tmp.setY((tmp.y() - float(viewport.y())) / float(viewport.height())); + tmp = tmp * 2.0f - QVector4D(1.0f, 1.0f, 1.0f, 1.0f); + + QVector4D obj = inverse * tmp; + // Don't change the w unless it is actually zero + if (obj.w() == 0.f) + obj.setW(0.000000001f); + obj /= obj.w(); + + return obj.toVector3D(); +} + } void Q3DSInputManager::castRayIntoLayer(Q3DSLayerNode *layer, const QPointF &pos, @@ -176,9 +202,9 @@ void Q3DSInputManager::castRayIntoLayer(Q3DSLayerNode *layer, const QPointF &pos QRect viewport(-1, -1, 2, 2); QVector3D nearPos(float(pos.x()), float(pos.y()), 0.0f); - nearPos = nearPos.unproject(viewMatrix, projectionMatrix, viewport); + nearPos = unproject(nearPos, viewMatrix, projectionMatrix, viewport); QVector3D farPos(float(pos.x()), float(pos.y()), 1.0f); - farPos = farPos.unproject(viewMatrix, projectionMatrix, viewport); + farPos = unproject(farPos, viewMatrix, projectionMatrix, viewport); QVector3D origin(nearPos); QVector3D direction((farPos - nearPos).normalized()); |