Merge "Merge remote-tracking branch 'origin/5.13' into 5.14"

This commit is contained in:
Paul Lemire 2019-10-15 09:40:09 +02:00
commit 0ff2215bb0
27 changed files with 385 additions and 59 deletions

View File

@ -125,6 +125,11 @@ QAbstractClipAnimator::QAbstractClipAnimator(QAbstractClipAnimatorPrivate &dd, Q
QAbstractClipAnimator::~QAbstractClipAnimator() QAbstractClipAnimator::~QAbstractClipAnimator()
{ {
} }
/*!
\qmlproperty bool Qt3DAnimation::AbstractClipAnimator::running
This property holds a boolean indicating whether the animation is currently running.
*/
/*! /*!
\property Qt3DAnimation::QAbstractClipAnimator::running \property Qt3DAnimation::QAbstractClipAnimator::running
@ -141,6 +146,13 @@ bool QAbstractClipAnimator::isRunning() const
return d->m_running; return d->m_running;
} }
/*!
\qmlproperty ChannelMapper Qt3DAnimation::AbstractClipAnimator::channelMapper
This property holds the ChannelMapper that controls how the channels in
the animation clip map onto the properties of the target objects.
*/
/*! /*!
\property Qt3DAnimation::QAbstractClipAnimator::channelMapper \property Qt3DAnimation::QAbstractClipAnimator::channelMapper
@ -198,6 +210,12 @@ int QAbstractClipAnimator::loopCount() const
Q_D(const QAbstractClipAnimator); Q_D(const QAbstractClipAnimator);
return d->m_loops; return d->m_loops;
} }
/*!
\qmlproperty Clock Qt3DAnimation::AbstractClipAnimator::clock
The clock controls the speed with which an animation is played.
*/
/*! /*!
\property Qt3DAnimation::QAbstractClipAnimator::clock \property Qt3DAnimation::QAbstractClipAnimator::clock
@ -208,7 +226,11 @@ QClock *QAbstractClipAnimator::clock() const
Q_D(const QAbstractClipAnimator); Q_D(const QAbstractClipAnimator);
return d->m_clock; return d->m_clock;
} }
/*!
\qmlproperty real Qt3DAnimation::AbstractClipAnimator::normalizedTime
This property holds the clips normalized time.
*/
/*! /*!
\property Qt3DAnimation::QAbstractClipAnimator::normalizedTime \property Qt3DAnimation::QAbstractClipAnimator::normalizedTime

View File

@ -56,6 +56,7 @@ QBlendedClipAnimatorPrivate::QBlendedClipAnimatorPrivate()
\qmltype BlendedClipAnimator \qmltype BlendedClipAnimator
\instantiates Qt3DAnimation::QBlendedClipAnimator \instantiates Qt3DAnimation::QBlendedClipAnimator
\inqmlmodule Qt3D.Animation \inqmlmodule Qt3D.Animation
\inherits AbstractClipAnimator
\since 5.9 \since 5.9
\brief BlendedClipAnimator is a component providing animation playback capabilities of a tree \brief BlendedClipAnimator is a component providing animation playback capabilities of a tree

View File

@ -66,6 +66,7 @@ bool QClipAnimatorPrivate::canPlay() const
\qmltype ClipAnimator \qmltype ClipAnimator
\instantiates Qt3DAnimation::QClipAnimator \instantiates Qt3DAnimation::QClipAnimator
\inqmlmodule Qt3D.Animation \inqmlmodule Qt3D.Animation
\inherits AbstractClipAnimator
\since 5.9 \since 5.9
\brief ClipAnimator is a component providing simple animation playback capabilities. \brief ClipAnimator is a component providing simple animation playback capabilities.

View File

@ -2,7 +2,7 @@ TEMPLATE = subdirs
# QNX is not supported, and Linux GCC 4.9 on ARM chokes on the assimp # QNX is not supported, and Linux GCC 4.9 on ARM chokes on the assimp
# sources (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66964). # sources (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66964).
QT_FOR_CONFIG += 3dcore-private QT_FOR_CONFIG += 3dcore-private
qtConfig(assimp):if(qtConfig(system-assimp)|android-clang|gcc:greaterThan(QT_GCC_MAJOR_VERSION, 4)): { !ios:!tvos:!qcc:qtConfig(assimp):if(qtConfig(system-assimp)|android-clang|clang|win32-msvc)|if(gcc:greaterThan(QT_GCC_MAJOR_VERSION, 4)) {
SUBDIRS += assimp SUBDIRS += assimp
} }
SUBDIRS += gltf SUBDIRS += gltf

View File

@ -529,6 +529,7 @@ void Scene3DItem::setWindowSurface(QObject *rootObject)
m_dummySurface = new QOffscreenSurface; m_dummySurface = new QOffscreenSurface;
m_dummySurface->setParent(qGuiApp); // parent to something suitably long-living m_dummySurface->setParent(qGuiApp); // parent to something suitably long-living
m_dummySurface->setFormat(rw->format()); m_dummySurface->setFormat(rw->format());
m_dummySurface->setScreen(rw->screen());
m_dummySurface->create(); m_dummySurface->create();
surfaceSelector->setSurface(m_dummySurface); surfaceSelector->setSurface(m_dummySurface);
} else { } else {
@ -616,6 +617,9 @@ QSGNode *Scene3DItem::updatePaintNode(QSGNode *node, QQuickItem::UpdatePaintNode
// If the render aspect wasn't created yet, do so now // If the render aspect wasn't created yet, do so now
if (m_renderAspect == nullptr) { if (m_renderAspect == nullptr) {
m_renderAspect = new QRenderAspect(QRenderAspect::Synchronous); m_renderAspect = new QRenderAspect(QRenderAspect::Synchronous);
auto *rw = QQuickRenderControl::renderWindowFor(window());
static_cast<Qt3DRender::QRenderAspectPrivate *>(Qt3DRender::QRenderAspectPrivate::get(m_renderAspect))->m_screen =
(rw ? rw->screen() : window()->screen());
m_aspectEngine->registerAspect(m_renderAspect); m_aspectEngine->registerAspect(m_renderAspect);
// Before Synchronizing is in the SG Thread, we want beforeSync to be triggered // Before Synchronizing is in the SG Thread, we want beforeSync to be triggered

View File

@ -66,6 +66,7 @@
#include <Qt3DQuickExtras/private/qt3dquickwindowlogging_p.h> #include <Qt3DQuickExtras/private/qt3dquickwindowlogging_p.h>
#include <Qt3DRender/private/qrendersurfaceselector_p.h> #include <Qt3DRender/private/qrendersurfaceselector_p.h>
#include <Qt3DRender/private/qrenderaspect_p.h>
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
@ -132,6 +133,8 @@ Qt3DQuickWindow::Qt3DQuickWindow(QWindow *parent)
QSurfaceFormat::setDefaultFormat(format); QSurfaceFormat::setDefaultFormat(format);
d->m_renderAspect = new Qt3DRender::QRenderAspect; d->m_renderAspect = new Qt3DRender::QRenderAspect;
if (parent && parent->screen())
static_cast<Qt3DRender::QRenderAspectPrivate*>(Qt3DRender::QRenderAspectPrivate::get(d->m_renderAspect))->m_screen = parent->screen();
d->m_inputAspect = new Qt3DInput::QInputAspect; d->m_inputAspect = new Qt3DInput::QInputAspect;
d->m_logicAspect = new Qt3DLogic::QLogicAspect; d->m_logicAspect = new Qt3DLogic::QLogicAspect;
d->m_engine = new Qt3DCore::Quick::QQmlAspectEngine; d->m_engine = new Qt3DCore::Quick::QQmlAspectEngine;

View File

@ -68,6 +68,8 @@ namespace Quick {
with the item; if an entity has a QObjectPicker component, the pick events from that picker with the item; if an entity has a QObjectPicker component, the pick events from that picker
are sent to the QScene2D and converted to mouse events and finally sent to the item. are sent to the QScene2D and converted to mouse events and finally sent to the item.
\note Only mouse events are supported. The item does not support keyboard input.
\since 5.9 \since 5.9
*/ */
@ -89,6 +91,8 @@ namespace Quick {
with the item; if an entity has an ObjectPicker component, the pick events from that picker with the item; if an entity has an ObjectPicker component, the pick events from that picker
are sent to the Scene2D and converted to mouse events and finally sent to the item. are sent to the Scene2D and converted to mouse events and finally sent to the item.
\note Only mouse events are supported. The item does not support keyboard input.
Usage: Usage:
\qml \qml
Entity { Entity {

View File

@ -64,6 +64,7 @@ QT_BEGIN_NAMESPACE
class QSurface; class QSurface;
class QSize; class QSize;
class QScreen;
namespace Qt3DCore { namespace Qt3DCore {
class QAbstractFrameAdvanceService; class QAbstractFrameAdvanceService;
@ -175,6 +176,8 @@ public:
// For QtQuick rendering // For QtQuick rendering
virtual void setOpenGLContext(QOpenGLContext *ctx) = 0; virtual void setOpenGLContext(QOpenGLContext *ctx) = 0;
virtual void setScreen(QScreen *) {}
virtual QScreen *screen() const { return nullptr; }
virtual void setOffscreenSurfaceHelper(OffscreenSurfaceHelper *helper) = 0; virtual void setOffscreenSurfaceHelper(OffscreenSurfaceHelper *helper) = 0;
virtual QSurfaceFormat format() = 0; virtual QSurfaceFormat format() = 0;

View File

@ -72,6 +72,7 @@ void OffscreenSurfaceHelper::createOffscreenSurface()
m_offscreenSurface = new QOffscreenSurface; m_offscreenSurface = new QOffscreenSurface;
m_offscreenSurface->setParent(this); m_offscreenSurface->setParent(this);
m_offscreenSurface->setFormat(m_renderer->format()); m_offscreenSurface->setFormat(m_renderer->format());
m_offscreenSurface->setScreen(m_renderer->screen());
m_offscreenSurface->create(); m_offscreenSurface->create();
} }

View File

@ -107,10 +107,6 @@ bool PlatformSurfaceFilter::eventFilter(QObject *obj, QEvent *e)
// If we remove it, the call to isSurfaceValid will // If we remove it, the call to isSurfaceValid will
// implicitely return false // implicitely return false
PlatformSurfaceFilter::m_surfacesValidity.remove(m_surface); PlatformSurfaceFilter::m_surfacesValidity.remove(m_surface);
if (m_obj) {
m_obj->removeEventFilter(this);
m_obj = nullptr;
}
break; break;
} }

View File

@ -66,7 +66,7 @@ namespace Qt3DRender {
/*! /*!
\qmltype ComputeCommand \qmltype ComputeCommand
\since 5.7 \since 5.7
\inmodule Qt3DRender \inqmlmodule Qt3D.Render
\inherits Component3D \inherits Component3D
\instantiates Qt3DRender::QComputeCommand \instantiates Qt3DRender::QComputeCommand
\brief Component to issue work for the compute shader on GPU. \brief Component to issue work for the compute shader on GPU.

View File

@ -562,6 +562,7 @@ void QRenderAspect::onRegistered()
// TO DO: Load proper Renderer class based on Qt configuration preferences // TO DO: Load proper Renderer class based on Qt configuration preferences
d->m_renderer = new Render::Renderer(d->m_renderType); d->m_renderer = new Render::Renderer(d->m_renderType);
d->m_renderer->setScreen(d->m_screen);
d->m_renderer->setNodeManagers(d->m_nodeManagers); d->m_renderer->setNodeManagers(d->m_nodeManagers);
// Create a helper for deferring creation of an offscreen surface used during cleanup // Create a helper for deferring creation of an offscreen surface used during cleanup

View File

@ -60,6 +60,7 @@
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
class QSurface; class QSurface;
class QScreen;
namespace Qt3DRender { namespace Qt3DRender {
@ -106,6 +107,7 @@ public:
QVector<Render::QRenderPlugin *> m_renderPlugins; QVector<Render::QRenderPlugin *> m_renderPlugins;
QRenderAspect::RenderType m_renderType; QRenderAspect::RenderType m_renderType;
Render::OffscreenSurfaceHelper *m_offscreenHelper; Render::OffscreenSurfaceHelper *m_offscreenHelper;
QScreen *m_screen = nullptr;
static QMutex m_pluginLock; static QMutex m_pluginLock;
static QVector<QString> m_pluginConfig; static QVector<QString> m_pluginConfig;

View File

@ -44,6 +44,7 @@
#include <QPair> #include <QPair>
#include <math.h> #include <math.h>
#include <algorithm>
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
@ -55,6 +56,9 @@ namespace {
// returns true and intersection point q; false otherwise // returns true and intersection point q; false otherwise
bool intersectRaySphere(const Qt3DRender::RayCasting::QRay3D &ray, const Qt3DRender::Render::Sphere &s, Vector3D *q = nullptr) bool intersectRaySphere(const Qt3DRender::RayCasting::QRay3D &ray, const Qt3DRender::Render::Sphere &s, Vector3D *q = nullptr)
{ {
if (s.isNull())
return false;
const Vector3D p = ray.origin(); const Vector3D p = ray.origin();
const Vector3D d = ray.direction(); const Vector3D d = ray.direction();
const Vector3D m = p - s.center(); const Vector3D m = p - s.center();
@ -139,11 +143,31 @@ inline void sphereFromExtremePoints(Qt3DRender::Render::Sphere &s, const QVector
inline void constructRitterSphere(Qt3DRender::Render::Sphere &s, const QVector<Vector3D> &points) inline void constructRitterSphere(Qt3DRender::Render::Sphere &s, const QVector<Vector3D> &points)
{ {
// Calculate the sphere encompassing two axially extreme points //def bounding_sphere(points):
sphereFromExtremePoints(s, points); // dist = lambda a,b: ((a[0] - b[0])**2 + (a[1] - b[1])**2 + (a[2] - b[2])**2)**0.5
// x = points[0]
// y = max(points,key= lambda p: dist(p,x) )
// z = max(points,key= lambda p: dist(p,y) )
// bounding_sphere = (((y[0]+z[0])/2,(y[1]+z[1])/2,(y[2]+z[2])/2), dist(y,z)/2)
//
// exterior_points = [p for p in points if dist(p,bounding_sphere[0]) > bounding_sphere[1] ]
// while ( len(exterior_points) > 0 ):
// pt = exterior_points.pop()
// if (dist(pt, bounding_sphere[0]) > bounding_sphere[1]):
// bounding_sphere = (bounding_sphere[0],dist(pt,bounding_sphere[0]))
//
// return bounding_sphere
// Now make sure the sphere bounds all points by growing if needed const Vector3D x = points[0];
s.expandToContain(points); const Vector3D y = *std::max_element(points.begin(), points.end(), [&x](const Vector3D& lhs, const Vector3D& rhs){ return (lhs - x).lengthSquared() < (rhs - x).lengthSquared(); });
const Vector3D z = *std::max_element(points.begin(), points.end(), [&y](const Vector3D& lhs, const Vector3D& rhs){ return (lhs - y).lengthSquared() < (rhs - y).lengthSquared(); });
const Vector3D center = (y + z) * 0.5f;
const Vector3D maxDistPt = *std::max_element(points.begin(), points.end(), [&center](const Vector3D& lhs, const Vector3D& rhs){ return (lhs - center).lengthSquared() < (rhs - center).lengthSquared(); });
const float radius = (maxDistPt - center).length();
s.setCenter(center);
s.setRadius(radius);
} }
} // anonymous namespace } // anonymous namespace
@ -169,6 +193,12 @@ void Sphere::initializeFromPoints(const QVector<Vector3D> &points)
void Sphere::expandToContain(const Vector3D &p) void Sphere::expandToContain(const Vector3D &p)
{ {
if (isNull()) {
m_center = p;
m_radius = 0.0f;
return;
}
const Vector3D d = p - m_center; const Vector3D d = p - m_center;
const float dist2 = d.lengthSquared(); const float dist2 = d.lengthSquared();
@ -184,6 +214,13 @@ void Sphere::expandToContain(const Vector3D &p)
void Sphere::expandToContain(const Sphere &sphere) void Sphere::expandToContain(const Sphere &sphere)
{ {
if (isNull()) {
*this = sphere;
return;
} else if (sphere.isNull()) {
return;
}
const Vector3D d(sphere.m_center - m_center); const Vector3D d(sphere.m_center - m_center);
const float dist2 = d.lengthSquared(); const float dist2 = d.lengthSquared();
@ -206,6 +243,9 @@ void Sphere::expandToContain(const Sphere &sphere)
Sphere Sphere::transformed(const Matrix4x4 &mat) const Sphere Sphere::transformed(const Matrix4x4 &mat) const
{ {
if (isNull())
return *this;
// Transform extremities in x, y, and z directions to find extremities // Transform extremities in x, y, and z directions to find extremities
// of the resulting ellipsoid // of the resulting ellipsoid
Vector3D x = mat.map(m_center + Vector3D(m_radius, 0.0f, 0.0f)); Vector3D x = mat.map(m_center + Vector3D(m_radius, 0.0f, 0.0f));

View File

@ -69,7 +69,7 @@ class Q_3DRENDERSHARED_PRIVATE_EXPORT Sphere : public RayCasting::BoundingSphere
public: public:
inline Sphere(Qt3DCore::QNodeId i = Qt3DCore::QNodeId()) inline Sphere(Qt3DCore::QNodeId i = Qt3DCore::QNodeId())
: m_center() : m_center()
, m_radius(0.0f) , m_radius(-1.0f)
, m_id(i) , m_id(i)
{} {}
@ -82,7 +82,7 @@ public:
void setCenter(const Vector3D &c); void setCenter(const Vector3D &c);
Vector3D center() const override; Vector3D center() const override;
inline bool isNull() { return m_center == Vector3D() && m_radius == 0.0f; } bool isNull() const { return m_center == Vector3D() && m_radius == -1.0f; }
void setRadius(float r); void setRadius(float r);
float radius() const override; float radius() const override;
@ -131,7 +131,9 @@ inline Vector3D Sphere::center() const
inline void Sphere::setRadius(float r) inline void Sphere::setRadius(float r)
{ {
m_radius = r; Q_ASSERT(r >= 0.0f);
if (r >= 0.0f)
m_radius = r;
} }
inline float Sphere::radius() const inline float Sphere::radius() const
@ -142,11 +144,14 @@ inline float Sphere::radius() const
inline void Sphere::clear() inline void Sphere::clear()
{ {
m_center = Vector3D(); m_center = Vector3D();
m_radius = 0.0f; m_radius = -1.0f;
} }
inline bool intersects(const Sphere &a, const Sphere &b) inline bool intersects(const Sphere &a, const Sphere &b)
{ {
if (a.isNull() || b.isNull())
return false;
// Calculate squared distance between sphere centers // Calculate squared distance between sphere centers
const Vector3D d = a.center() - b.center(); const Vector3D d = a.center() - b.center();
const float distSq = Vector3D::dotProduct(d, d); const float distSq = Vector3D::dotProduct(d, d);

View File

@ -90,30 +90,42 @@ public:
m_min = QVector3D(findExtremePoints.xMin, findExtremePoints.yMin, findExtremePoints.zMin); m_min = QVector3D(findExtremePoints.xMin, findExtremePoints.yMin, findExtremePoints.zMin);
m_max = QVector3D(findExtremePoints.xMax, findExtremePoints.yMax, findExtremePoints.zMax); m_max = QVector3D(findExtremePoints.xMax, findExtremePoints.yMax, findExtremePoints.zMax);
// Calculate squared distance for the pairs of points FindMaxDistantPoint maxDistantPointY(m_manager);
const float xDist2 = (findExtremePoints.xMaxPt - findExtremePoints.xMinPt).lengthSquared(); maxDistantPointY.setReferencePoint = true;
const float yDist2 = (findExtremePoints.yMaxPt - findExtremePoints.yMinPt).lengthSquared(); if (!maxDistantPointY.apply(positionAttribute, indexAttribute, drawVertexCount,
const float zDist2 = (findExtremePoints.zMaxPt - findExtremePoints.zMinPt).lengthSquared(); primitiveRestartEnabled, primitiveRestartIndex)) {
return false;
// Select most distant pair
Vector3D p = findExtremePoints.xMinPt;
Vector3D q = findExtremePoints.xMaxPt;
if (yDist2 > xDist2 && yDist2 > zDist2) {
p = findExtremePoints.yMinPt;
q = findExtremePoints.yMaxPt;
} }
if (zDist2 > xDist2 && zDist2 > yDist2) { if (maxDistantPointY.hasNoPoints)
p = findExtremePoints.zMinPt; return false;
q = findExtremePoints.zMaxPt;
//const Vector3D x = maxDistantPointY.referencePt;
const Vector3D y = maxDistantPointY.maxDistPt;
FindMaxDistantPoint maxDistantPointZ(m_manager);
maxDistantPointZ.setReferencePoint = false;
maxDistantPointZ.referencePt = y;
if (!maxDistantPointZ.apply(positionAttribute, indexAttribute, drawVertexCount,
primitiveRestartEnabled, primitiveRestartIndex)) {
return false;
}
const Vector3D z = maxDistantPointZ.maxDistPt;
const Vector3D center = (y + z) * 0.5f;
FindMaxDistantPoint maxDistantPointCenter(m_manager);
maxDistantPointCenter.setReferencePoint = false;
maxDistantPointCenter.referencePt = center;
if (!maxDistantPointCenter.apply(positionAttribute, indexAttribute, drawVertexCount,
primitiveRestartEnabled, primitiveRestartIndex)) {
return false;
} }
const Vector3D c = 0.5f * (p + q); const float radius = (center - maxDistantPointCenter.maxDistPt).length();
m_volume.setCenter(c);
m_volume.setRadius((q - c).length());
ExpandSphere expandSphere(m_manager, m_volume); m_volume = Qt3DRender::Render::Sphere(center, radius);
if (!expandSphere.apply(positionAttribute, indexAttribute, drawVertexCount,
primitiveRestartEnabled, primitiveRestartIndex)) if (m_volume.isNull())
return false; return false;
return true; return true;
@ -172,18 +184,34 @@ private:
} }
}; };
class ExpandSphere : public Buffer3fVisitor class FindMaxDistantPoint : public Buffer3fVisitor
{ {
public: public:
ExpandSphere(NodeManagers *manager, Sphere& volume) FindMaxDistantPoint(NodeManagers *manager)
: Buffer3fVisitor(manager), m_volume(volume) : Buffer3fVisitor(manager)
{ } { }
Sphere& m_volume; float maxLengthSquared = 0.0f;
Vector3D maxDistPt;
Vector3D referencePt;
bool setReferencePoint = false;
bool hasNoPoints = true;
void visit(uint ndx, float x, float y, float z) override void visit(uint ndx, float x, float y, float z) override
{ {
Q_UNUSED(ndx); Q_UNUSED(ndx);
m_volume.expandToContain(Vector3D(x, y, z)); const Vector3D p = Vector3D(x, y, z);
if (hasNoPoints && setReferencePoint) {
maxLengthSquared = 0.0f;
referencePt = p;
}
const float lengthSquared = (p - referencePt).lengthSquared();
if ( lengthSquared >= maxLengthSquared ) {
maxDistPt = p;
maxLengthSquared = lengthSquared;
}
hasNoPoints = false;
} }
}; };
}; };

View File

@ -202,12 +202,12 @@ void PickBoundingVolumeJob::setRoot(Entity *root)
void PickBoundingVolumeJob::setMouseEvents(const QList<QPair<QObject*, QMouseEvent>> &pendingEvents) void PickBoundingVolumeJob::setMouseEvents(const QList<QPair<QObject*, QMouseEvent>> &pendingEvents)
{ {
m_pendingMouseEvents = pendingEvents; m_pendingMouseEvents.append(pendingEvents);
} }
void PickBoundingVolumeJob::setKeyEvents(const QList<QKeyEvent> &pendingEvents) void PickBoundingVolumeJob::setKeyEvents(const QList<QKeyEvent> &pendingEvents)
{ {
m_pendingKeyEvents = pendingEvents; m_pendingKeyEvents.append(pendingEvents);
} }
void PickBoundingVolumeJob::markPickersDirty() void PickBoundingVolumeJob::markPickersDirty()

View File

@ -65,6 +65,8 @@ QEffectPrivate::QEffectPrivate()
An QEffect instance should be shared among several QMaterial instances when possible. An QEffect instance should be shared among several QMaterial instances when possible.
\note QEffect node can not be disabled.
\code \code
QEffect *effect = new QEffect(); QEffect *effect = new QEffect();
@ -111,6 +113,8 @@ QEffectPrivate::QEffectPrivate()
A Parameter defined on an Effect is overridden by a QParameter (of the same A Parameter defined on an Effect is overridden by a QParameter (of the same
name) defined in a Material, TechniqueFilter, RenderPassFilter. name) defined in a Material, TechniqueFilter, RenderPassFilter.
\note Effect node can not be disabled.
\code \code
Effect { Effect {
id: effect id: effect

View File

@ -60,6 +60,8 @@ QFilterKeyPrivate::QFilterKeyPrivate()
Filter keys are used by QTechnique and QRenderPass to specify at which stage of rendering the Filter keys are used by QTechnique and QRenderPass to specify at which stage of rendering the
technique or the render pass is used. technique or the render pass is used.
\note QFilterKey node can not be disabled.
*/ */
/*! /*!
@ -73,6 +75,8 @@ QFilterKeyPrivate::QFilterKeyPrivate()
A FilterKey is a storage type for filter key and value pair. A FilterKey is a storage type for filter key and value pair.
Filter keys are used by Technique and RenderPass to specify at which stage of rendering the Filter keys are used by Technique and RenderPass to specify at which stage of rendering the
technique or the render pass is used. technique or the render pass is used.
\note FilterKey node can not be disabled.
*/ */
QFilterKey::QFilterKey(QNode *parent) QFilterKey::QFilterKey(QNode *parent)

View File

@ -76,6 +76,8 @@
\note when the targeted uniform is an array, the name should be the name \note when the targeted uniform is an array, the name should be the name
of the uniform with [0] appended to it. of the uniform with [0] appended to it.
\note Parameter node can not be disabled.
\code \code
Parameter { Parameter {
name: "diffuseValues[0]" name: "diffuseValues[0]"
@ -138,6 +140,8 @@
\note when the targeted uniform is an array, the name should be the name \note when the targeted uniform is an array, the name should be the name
of the uniform with [0] appended to it. of the uniform with [0] appended to it.
\note QParameter node can not be disabled.
\code \code
QParameter *param = new QParameter(); QParameter *param = new QParameter();
QVariantList values = QVariantList() << 0.0f << 1.0f << 2.0f << 3.0f << 4.0f << 883.0f << 1340.0f << 1584.0f; QVariantList values = QVariantList() << 0.0f << 1.0f << 2.0f << 3.0f << 4.0f << 883.0f << 1340.0f << 1584.0f;

View File

@ -87,6 +87,8 @@ QTechniquePrivate::~QTechniquePrivate()
QSurfaceFormat::setDefaultFormat(). Setting the QSurfaceFormat on the view QSurfaceFormat::setDefaultFormat(). Setting the QSurfaceFormat on the view
will likely have no effect on Qt3D related rendering. will likely have no effect on Qt3D related rendering.
\note Technique node can not be disabled.
\qml \qml
Technique { Technique {
id: gl3Technique id: gl3Technique
@ -152,6 +154,8 @@ QTechniquePrivate::~QTechniquePrivate()
QSurfaceFormat::setDefaultFormat(). Setting the QSurfaceFormat on the view QSurfaceFormat::setDefaultFormat(). Setting the QSurfaceFormat on the view
will likely have no effect on Qt3D related rendering. will likely have no effect on Qt3D related rendering.
\note QTechnique node can not be disabled.
\code \code
QTechnique *gl3Technique = new QTechnique(); QTechnique *gl3Technique = new QTechnique();

View File

@ -82,6 +82,9 @@ namespace Qt3DRender {
\note Instances of this component shouldn't be shared, not respecting that \note Instances of this component shouldn't be shared, not respecting that
condition will most likely result in undefined behavior. condition will most likely result in undefined behavior.
\note The camera far plane value affects picking and produces incorrect results due to
floating-point precision if it is greater than ~100 000.
\since 5.6 \since 5.6
*/ */
@ -115,6 +118,9 @@ namespace Qt3DRender {
\note Instances of this component shouldn't be shared, not respecting that \note Instances of this component shouldn't be shared, not respecting that
condition will most likely result in undefined behavior. condition will most likely result in undefined behavior.
\note The camera far plane value affects picking and produces incorrect results due to
floating-point precision if it is greater than ~100 000.
*/ */
/*! /*!

View File

@ -347,6 +347,16 @@ void Renderer::setOpenGLContext(QOpenGLContext *context)
m_glContext = context; m_glContext = context;
} }
void Renderer::setScreen(QScreen *scr)
{
m_screen = scr;
}
QScreen *Renderer::screen() const
{
return m_screen;
}
// Called in RenderThread context by the run method of RenderThread // Called in RenderThread context by the run method of RenderThread
// RenderThread has locked the mutex already and unlocks it when this // RenderThread has locked the mutex already and unlocks it when this
// method termintates // method termintates
@ -364,6 +374,8 @@ void Renderer::initialize()
// we need to create it // we need to create it
if (!m_glContext) { if (!m_glContext) {
ctx = new QOpenGLContext; ctx = new QOpenGLContext;
if (m_screen)
ctx->setScreen(m_screen);
ctx->setShareContext(qt_gl_global_share_context()); ctx->setShareContext(qt_gl_global_share_context());
// TO DO: Shouldn't we use the highest context available and trust // TO DO: Shouldn't we use the highest context available and trust
@ -393,6 +405,8 @@ void Renderer::initialize()
if (!ctx->shareContext()) { if (!ctx->shareContext()) {
m_shareContext = new QOpenGLContext; m_shareContext = new QOpenGLContext;
if (ctx->screen())
m_shareContext->setScreen(ctx->screen());
m_shareContext->setFormat(ctx->format()); m_shareContext->setFormat(ctx->format());
m_shareContext->setShareContext(ctx); m_shareContext->setShareContext(ctx);
m_shareContext->create(); m_shareContext->create();

View File

@ -106,6 +106,7 @@ QT_BEGIN_NAMESPACE
class QSurface; class QSurface;
class QMouseEvent; class QMouseEvent;
class QScreen;
namespace Qt3DCore { namespace Qt3DCore {
class QEntity; class QEntity;
@ -293,6 +294,8 @@ public:
ViewSubmissionResultData submitRenderViews(const QVector<Render::RenderView *> &renderViews); ViewSubmissionResultData submitRenderViews(const QVector<Render::RenderView *> &renderViews);
RendererCache *cache() { return &m_cache; } RendererCache *cache() { return &m_cache; }
void setScreen(QScreen *scr) override;
QScreen *screen() const override;
#ifdef QT3D_RENDER_UNIT_TESTS #ifdef QT3D_RENDER_UNIT_TESTS
public: public:
@ -426,6 +429,7 @@ private:
bool m_shouldSwapBuffers; bool m_shouldSwapBuffers;
QVector<FrameGraphNode *> m_frameGraphLeaves; QVector<FrameGraphNode *> m_frameGraphLeaves;
QScreen *m_screen = nullptr;
}; };
} // namespace Render } // namespace Render

View File

@ -59,6 +59,7 @@ namespace Qt3DRender {
/*! /*!
\qmltype RenderState \qmltype RenderState
\inqmlmodule Qt3D.Render
\brief An abstract base type for all render states. \brief An abstract base type for all render states.
\since 5.7 \since 5.7
\inherits Node \inherits Node

View File

@ -204,13 +204,150 @@ class tst_BoundingSphere : public Qt3DCore::QBackendNodeTester
private: private:
private Q_SLOTS: private Q_SLOTS:
void checkIsNull() {
auto defaultSphere = Qt3DRender::Render::Sphere();
QVERIFY(defaultSphere.isNull());
}
void remainsNotNullAfterTransform() {
QMatrix4x4 mat;
mat.translate(-5,-5,-5);
auto mMat = Matrix4x4(mat);
auto pointSphere = Qt3DRender::Render::Sphere(Vector3D(5.f,5.f,5.f),0.f);
pointSphere.transform(mMat);
QVERIFY(!pointSphere.isNull());
QVERIFY(pointSphere.center() == Vector3D(0.,0.,0));
QVERIFY(pointSphere.radius() == 0.f);
}
void remainsNullAfterTransform() {
QMatrix4x4 mat;
mat.translate(-5,-5,-5);
auto mMat = Matrix4x4(mat);
auto defaultSphere = Qt3DRender::Render::Sphere();
defaultSphere.transform(mMat);
QVERIFY(defaultSphere.isNull());
}
void expandToContainSphere() {
auto firstValidSphere = Qt3DRender::Render::Sphere(Vector3D(-10.f,-10.f,-10.f),1.f);
auto secondValidSphere = Qt3DRender::Render::Sphere(Vector3D(10.f,10.f,10.f),1.f);
firstValidSphere.expandToContain(secondValidSphere);
QVERIFY(firstValidSphere.center()==Vector3D(0.f,0.f,0.f));
float dist = static_cast<float>((2 + sqrt(3.*(20)*(20)))/2.);
QVERIFY(qFuzzyCompare(firstValidSphere.radius(), dist));
}
void expandToContainSphereOneInvalid() {
auto firstValidSphere = Qt3DRender::Render::Sphere(Vector3D(-10.f,-10.f,-10.f),1.f);
auto defaultSphere = Qt3DRender::Render::Sphere();
auto copiedSphere = firstValidSphere;
firstValidSphere.expandToContain(defaultSphere);
QVERIFY(firstValidSphere.center() == copiedSphere.center());
QVERIFY(firstValidSphere.radius() == copiedSphere.radius());
QVERIFY(!firstValidSphere.isNull());
}
void expandToContainOtherSphereInvalid() {
auto firstValidSphere = Qt3DRender::Render::Sphere(Vector3D(-10.f,-10.f,-10.f),1.f);
auto defaultSphere = Qt3DRender::Render::Sphere();
defaultSphere.expandToContain(firstValidSphere);
QVERIFY(defaultSphere.center() == firstValidSphere.center());
QVERIFY(defaultSphere.radius() == firstValidSphere.radius());
QVERIFY(!defaultSphere.isNull());
}
void expandNullSphereWithNullSphere() {
auto defaultSphere = Qt3DRender::Render::Sphere();
auto otherDefaultSphere = Qt3DRender::Render::Sphere();
defaultSphere.expandToContain(otherDefaultSphere);
QVERIFY(defaultSphere.isNull());
}
void expandToContainPoint() {
auto firstValidSphere = Qt3DRender::Render::Sphere(Vector3D(-10.f,-10.f,-10.f),1.f);
firstValidSphere.expandToContain(Vector3D(0,0,0));
QVERIFY(!firstValidSphere.isNull());
float expectedRadius = static_cast<float>((1 + qSqrt(3.*(10)*(10)))/2.);
QVERIFY(qFuzzyCompare(firstValidSphere.radius(), expectedRadius));
}
void nullSphereExpandToContainPoint() {
auto defaultSphere = Qt3DRender::Render::Sphere();
defaultSphere.expandToContain(Vector3D(5,5,5));
QVERIFY(!defaultSphere.isNull());
QVERIFY(defaultSphere.center() == Vector3D(5,5,5));
QVERIFY(qFuzzyIsNull(defaultSphere.radius()));
}
void nullSphereExpandToOrigin() {
auto defaultSphere = Qt3DRender::Render::Sphere();
defaultSphere.expandToContain(Vector3D(0,0,0));
QVERIFY(!defaultSphere.isNull());
QVERIFY(defaultSphere.center() == Vector3D(0,0,0));
QVERIFY(qFuzzyIsNull(defaultSphere.radius()));
}
void ritterSphereCubePoints() {
QVector<Vector3D> cubePts={
Vector3D(-0.5, -0.5, 0.5),
Vector3D( 0.5, -0.5, -0.5),
Vector3D(-0.5, 0.5, -0.5),
Vector3D( 0.5, 0.5, -0.5),
Vector3D(-0.5, -0.5, -0.5),
Vector3D( 0.5, -0.5, 0.5),
Vector3D(-0.5, 0.5, 0.5),
Vector3D( 0.5, 0.5, 0.5)
};
auto ritterSphere=Qt3DRender::Render::Sphere::fromPoints(cubePts);
QVERIFY(!ritterSphere.isNull());
QVERIFY(qFuzzyIsNull(ritterSphere.center().x()));
QVERIFY(qFuzzyIsNull(ritterSphere.center().y()));
QVERIFY(qFuzzyIsNull(ritterSphere.center().z()));
QVERIFY(qFuzzyCompare(ritterSphere.radius(), static_cast<float>(qSqrt(3)/2)));
}
void ritterSphereRandomPoints() {
QVector<Vector3D> randomPts={
Vector3D(-81, 55, 46),
Vector3D(-91, -73, -42),
Vector3D(-50, -76, -77),
Vector3D(-40, 63, 58),
Vector3D(-28, -2, -57),
Vector3D(84, 17, 33),
Vector3D(53, 11, -49),
Vector3D(-7, -24, -86),
Vector3D(-89, 6, 76),
Vector3D(46, -18, -27)
};
auto ritterSphere = Qt3DRender::Render::Sphere::fromPoints(randomPts);
QVERIFY(!ritterSphere.isNull());
QVERIFY(qFuzzyCompare(ritterSphere.center().x(), 17.f));
QVERIFY(qFuzzyCompare(ritterSphere.center().y(), -29.5f));
QVERIFY(qFuzzyCompare(ritterSphere.center().z(), -22.0f));
QVERIFY(qFuzzyCompare(ritterSphere.radius(), 148.66152831179963f));
}
void ritterSphereOnePoint() {
QVector<Vector3D> singlePt={
Vector3D(-0.5, -0.5, -0.5),
};
auto ritterSphere = Qt3DRender::Render::Sphere::fromPoints(singlePt);
QVERIFY(!ritterSphere.isNull());
QVERIFY(qFuzzyCompare(ritterSphere.center().x(), -0.5f));
QVERIFY(qFuzzyCompare(ritterSphere.center().y(), -0.5f));
QVERIFY(qFuzzyCompare(ritterSphere.center().z(), -0.5f));
QVERIFY(qFuzzyIsNull(ritterSphere.radius()));
}
void checkExtraGeometries_data() void checkExtraGeometries_data()
{ {
QTest::addColumn<QString>("qmlFile"); QTest::addColumn<QString>("qmlFile");
QTest::addColumn<QVector3D>("sphereCenter"); QTest::addColumn<QVector3D>("sphereCenter");
QTest::addColumn<float>("sphereRadius"); QTest::addColumn<float>("sphereRadius");
QTest::newRow("SphereMesh") << "qrc:/sphere.qml" << QVector3D(0.f, 0.f, 0.f) << 1.f; QTest::newRow("SphereMesh") << "qrc:/sphere.qml" << QVector3D(0.f, 0.f, 0.f) << 1.f;
QTest::newRow("CubeMesh") << "qrc:/cube.qml" << QVector3D(0.0928356f, -0.212021f, -0.0467958f) << 1.07583f; // weird! QTest::newRow("CubeMesh") << "qrc:/cube.qml" << QVector3D(0.f, 0.f, 0.f) << static_cast<float>(qSqrt(3.)/2.); // not weird at all
} }
void checkExtraGeometries() void checkExtraGeometries()
@ -235,9 +372,10 @@ private Q_SLOTS:
const auto boundingSphere = test->sceneRoot()->worldBoundingVolumeWithChildren(); const auto boundingSphere = test->sceneRoot()->worldBoundingVolumeWithChildren();
qDebug() << qmlFile << boundingSphere->radius() << boundingSphere->center(); qDebug() << qmlFile << boundingSphere->radius() << boundingSphere->center();
QCOMPARE(boundingSphere->radius(), sphereRadius); QCOMPARE(boundingSphere->radius(), sphereRadius);
QVERIFY(qAbs(boundingSphere->center().x() - sphereCenter.x()) < 0.000001f); // qFuzzyCompare hates 0s
QVERIFY(qAbs(boundingSphere->center().y() - sphereCenter.y()) < 0.000001f); QVERIFY(qFuzzyIsNull(boundingSphere->center().x() - sphereCenter.x()));
QVERIFY(qAbs(boundingSphere->center().z() - sphereCenter.z()) < 0.000001f); QVERIFY(qFuzzyIsNull(boundingSphere->center().y() - sphereCenter.y()));
QVERIFY(qFuzzyIsNull(boundingSphere->center().z() - sphereCenter.z()));
} }
void checkCustomGeometry_data() void checkCustomGeometry_data()
@ -247,10 +385,10 @@ private Q_SLOTS:
QTest::addColumn<QVector3D>("expectedCenter"); QTest::addColumn<QVector3D>("expectedCenter");
QTest::addColumn<float>("expectedRadius"); QTest::addColumn<float>("expectedRadius");
QTest::addColumn<bool>("withPrimitiveRestart"); QTest::addColumn<bool>("withPrimitiveRestart");
QTest::newRow("all") << 0 << 0 << QVector3D(-0.488892f, 0.0192147f, -75.4804f) << 25.5442f << false; QTest::newRow("all") << 0 << 0 << QVector3D(0.0f, 0.0f, -75.0f) << 25.03997f << false;
QTest::newRow("first only") << 3 << 0 << QVector3D(0, 1, -100) << 1.0f << false; QTest::newRow("first only") << 3 << 0 << QVector3D(0, 1, -100) << 1.0f << false;
QTest::newRow("second only") << 3 << int(3 * sizeof(ushort)) << QVector3D(0, -1, -50) << 1.0f << false; QTest::newRow("second only") << 3 << int(3 * sizeof(ushort)) << QVector3D(0, -1, -50) << 1.0f << false;
QTest::newRow("all with primitive restart") << 0 << 0 << QVector3D(-0.488892f, 0.0192147f, -75.4804f) << 25.5442f << true; QTest::newRow("all with primitive restart") << 0 << 0 << QVector3D(0.0f, 0.0f, -75.0f) << 25.03997f << true;
QTest::newRow("first only with primitive restart") << 4 << 0 << QVector3D(0, 1, -100) << 1.0f << true; QTest::newRow("first only with primitive restart") << 4 << 0 << QVector3D(0, 1, -100) << 1.0f << true;
QTest::newRow("second only with primitive restart") << 4 << int(3 * sizeof(ushort)) << QVector3D(0, -1, -50) << 1.0f << true; QTest::newRow("second only with primitive restart") << 4 << int(3 * sizeof(ushort)) << QVector3D(0, -1, -50) << 1.0f << true;
} }
@ -376,18 +514,17 @@ private Q_SLOTS:
float radius = entityBackend->localBoundingVolume()->radius(); float radius = entityBackend->localBoundingVolume()->radius();
qDebug() << radius << center; qDebug() << radius << center;
// truncate and compare integers only QCOMPARE(radius, expectedRadius);
QCOMPARE(int(radius), int(expectedRadius)); QCOMPARE(center.x(), expectedCenter.x());
QCOMPARE(int(center.x()), int(expectedCenter.x())); QCOMPARE(center.y(), expectedCenter.y());
QCOMPARE(int(center.y()), int(expectedCenter.y())); QCOMPARE(center.z(), expectedCenter.z());
QCOMPARE(int(center.z()), int(expectedCenter.z()));
} }
void checkCustomPackedGeometry() void checkCustomPackedGeometry()
{ {
int drawVertexCount = 6; int drawVertexCount = 6;
QVector3D expectedCenter(-0.488892f, 0.0192147f, -75.4804f); QVector3D expectedCenter(0.0f, 0.0f, -75.0f);
float expectedRadius = 25.5442f; float expectedRadius = 25.03997f;
// two triangles with different Z // two triangles with different Z
QByteArray vdata; QByteArray vdata;
@ -467,11 +604,10 @@ private Q_SLOTS:
float radius = entityBackend->localBoundingVolume()->radius(); float radius = entityBackend->localBoundingVolume()->radius();
qDebug() << radius << center; qDebug() << radius << center;
// truncate and compare integers only QCOMPARE(radius, expectedRadius);
QVERIFY(int(radius) == int(expectedRadius)); QCOMPARE(center.x(), expectedCenter.x());
QVERIFY(int(center.x()) == int(expectedCenter.x())); QCOMPARE(center.y(), expectedCenter.y());
QVERIFY(int(center.y()) == int(expectedCenter.y())); QCOMPARE(center.z(), expectedCenter.z());
QVERIFY(int(center.z()) == int(expectedCenter.z()));
} }
}; };

View File

@ -29,6 +29,10 @@
#include <QtTest/QTest> #include <QtTest/QTest>
#include <Qt3DCore/qentity.h> #include <Qt3DCore/qentity.h>
#include <Qt3DCore/qtransform.h> #include <Qt3DCore/qtransform.h>
#include <Qt3DRender/qgeometry.h>
#include <Qt3DRender/qgeometryrenderer.h>
#include <Qt3DRender/qattribute.h>
#include <Qt3DRender/qbuffer.h>
#include <Qt3DRender/private/nodemanagers_p.h> #include <Qt3DRender/private/nodemanagers_p.h>
#include <Qt3DRender/private/managers_p.h> #include <Qt3DRender/private/managers_p.h>
#include <Qt3DRender/private/entity_p.h> #include <Qt3DRender/private/entity_p.h>
@ -43,6 +47,40 @@ namespace {
Qt3DCore::QEntity *buildEntityAtDistance(float distance, Qt3DCore::QEntity *parent) Qt3DCore::QEntity *buildEntityAtDistance(float distance, Qt3DCore::QEntity *parent)
{ {
Qt3DCore::QEntity *entity = new Qt3DCore::QEntity(parent); Qt3DCore::QEntity *entity = new Qt3DCore::QEntity(parent);
// create geometry with a valid bounding volume - a single point is sufficient
auto geometry = new Qt3DRender::QGeometry;
auto vertexBuffer = new Qt3DRender::QBuffer(Qt3DRender::QBuffer::VertexBuffer, geometry);
auto positionAttribute = new Qt3DRender::QAttribute;
positionAttribute->setName(Qt3DRender::QAttribute::defaultPositionAttributeName());
positionAttribute->setAttributeType(Qt3DRender::QAttribute::VertexAttribute);
positionAttribute->setVertexBaseType(Qt3DRender::QAttribute::Float);
positionAttribute->setVertexSize(3);
positionAttribute->setByteStride(3 * sizeof(float));
positionAttribute->setBuffer(vertexBuffer);
QByteArray vertexBufferData;
vertexBufferData.resize(static_cast<int>(3 * sizeof(float)));
auto vertexArray = reinterpret_cast<float*>(vertexBufferData.data());
int i = 0;
vertexArray[i++] = 0.0f;
vertexArray[i++] = 0.0f;
vertexArray[i++] = 0.0f;
vertexBuffer->setData(vertexBufferData);
positionAttribute->setCount(1);
geometry->addAttribute(positionAttribute);
auto geometryRenderer = new Qt3DRender::QGeometryRenderer;
geometryRenderer->setPrimitiveType(Qt3DRender::QGeometryRenderer::Points);
geometryRenderer->setGeometry(geometry);
entity->addComponent(geometryRenderer);
Qt3DCore::QTransform *transform = new Qt3DCore::QTransform(parent); Qt3DCore::QTransform *transform = new Qt3DCore::QTransform(parent);
const QVector3D t = QVector3D(1.0f, 0.0f, 0.0f) * distance; const QVector3D t = QVector3D(1.0f, 0.0f, 0.0f) * distance;