Revision control

Copy as Markdown

// Copyright (C) 2008-2012 NVIDIA Corporation.
// Copyright (C) 2019 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
// Qt-Security score:significant reason:default
#ifndef QSSG_RENDER_CAMERA_H
#define QSSG_RENDER_CAMERA_H
//
// W A R N I N G
// -------------
//
// This file is not part of the Qt API. It exists purely as an
// implementation detail. This header file may change from version to
// version without notice, or even be removed.
//
// We mean it.
//
#include <QtQuick3DRuntimeRender/private/qtquick3druntimerenderglobal_p.h>
#include <QtQuick3DRuntimeRender/private/qssgrendernode_p.h>
#include <QtQuick3DRuntimeRender/private/qssgrenderray_p.h>
#include <QtQuick3DUtils/private/qssgrenderbasetypes_p.h>
QT_BEGIN_NAMESPACE
struct QSSGCameraGlobalCalculationResult
{
bool m_wasDirty;
bool m_computeFrustumSucceeded /* = true */;
};
struct QSSGRenderCameraConfiguration
{
float dpr = 1.0f;
float ssaaMultiplier = 1.0f;
};
class QSSGRenderCameraFieldOfView
{
public:
enum class Orientation
{
Vertical,
Horizontal,
};
explicit constexpr QSSGRenderCameraFieldOfView(Orientation orientation = Orientation::Vertical) : fovOrientation(orientation) {}
QSSGRenderCameraFieldOfView(const QSSGRenderCameraFieldOfView &) = default;
QSSGRenderCameraFieldOfView(QSSGRenderCameraFieldOfView &&) = default;
QSSGRenderCameraFieldOfView &operator=(const QSSGRenderCameraFieldOfView &other) = default;
template <Orientation Type = Orientation::Vertical>
static QSSGRenderCameraFieldOfView fromDegrees(float fov)
{
return QSSGRenderCameraFieldOfView(fov, FovValue::Degrees, Type);
}
template <Orientation Type = Orientation::Vertical>
static QSSGRenderCameraFieldOfView fromRadians(float fov)
{
return QSSGRenderCameraFieldOfView(fov, FovValue::Radians, Type);
}
constexpr Orientation orientation() const { return fovOrientation; }
float degrees() const { return fovDegrees; }
float radians() const { return fovRadians; }
void setDegrees(float fov)
{
fovDegrees = fov;
fovRadians = qDegreesToRadians(fov);
}
QSSGRenderCameraFieldOfView asVerticalFov(float aspectRatio) const
{
if (fovOrientation == Orientation::Vertical)
return *this;
const float fovV = float(2.0 * qAtan(qTan(qreal(fovRadians) / 2.0) / qreal(aspectRatio)));
return fromRadians<Orientation::Vertical>(fovV);
}
void setRadians(float fov)
{
fovRadians = fov;
fovDegrees = qRadiansToDegrees(fov);
}
private:
enum class FovValue
{
Degrees,
Radians,
};
constexpr explicit QSSGRenderCameraFieldOfView(float fov, FovValue value, Orientation angleOfView)
: fovDegrees(value == FovValue::Degrees ? fov : qRadiansToDegrees(fov))
, fovRadians(value == FovValue::Radians ? fov : qDegreesToRadians(fov))
, fovOrientation(angleOfView)
{
}
float fovDegrees = 60.0f;
float fovRadians = qDegreesToRadians(fovDegrees);
Orientation fovOrientation;
};
class Q_QUICK3DRUNTIMERENDER_EXPORT QSSGRenderCamera : public QSSGRenderNode
{
public:
using Configuration = QSSGRenderCameraConfiguration;
using FieldOfView = QSSGRenderCameraFieldOfView;
explicit QSSGRenderCamera(QSSGRenderGraphObject::Type type);
enum class DirtyFlag : quint8
{
CameraDirty = 0x1,
LayerMaskDirty = 0x2,
};
using FlagT = std::underlying_type_t<DirtyFlag>;
static constexpr DirtyFlag DirtyMask { std::numeric_limits<FlagT>::max() };
static constexpr quint32 ReservedLayerMask = 0xFF000000; // The upper 8 bits are reserved for internal use.
static constexpr quint32 LayerMaskUserAll = 0x00FFFFFF; // The lower 24 bits are available for user layers.
// Default to all layers (user + reserved).
static constexpr quint32 LayerMaskAll = LayerMaskUserAll | ReservedLayerMask;
class ClipPlanes : public QVector2D
{
public:
constexpr inline ClipPlanes() : QVector2D(0.0f, 10000.0f) {}
constexpr inline ClipPlanes(float n, float f) : QVector2D(n, f) {}
constexpr float clipNear() const noexcept { return x(); }
constexpr float clipFar() const noexcept { return y(); }
constexpr inline void setClipNear(float n) noexcept { setX(n); }
constexpr inline void setClipFar(float f) noexcept { setY(f); }
};
class Magnification : public QVector2D
{
public:
constexpr inline Magnification() : QVector2D(1.0f, 1.0f) {}
constexpr inline Magnification(float h, float v) : QVector2D(h, v) {}
constexpr float horizontal() const noexcept { return x(); }
constexpr float vertical() const noexcept { return y(); }
constexpr inline void setHorizontal(float h) noexcept { setX(h); }
constexpr inline void setVertical(float v) noexcept { setY(v); }
};
// Used by the custom frustum camera
struct Frustum
{
float top = 0.0f;
float bottom = 0.0f;
float left = 0.0f;
float right = 0.0f;
};
// Set our position, rotation member variables based on the lookat target
// Marks this object as dirty.
// Need to test this when the camera's local transform is null.
// Assumes parent's local transform is the identity, meaning our local transform is
// our global transform.
void lookAt(const QVector3D &inCameraPos, const QVector3D &inUpDir, const QVector3D &inTargetPos, const QVector3D &pivot);
/*!
* Convenience function intended for use with internal cameras that's not part of the scene graph!
* This function will NOT ensure that the camera's global transform, projection matrix, or state
* is updated!.
*/
static bool calculateProjectionInternal(QSSGRenderCamera &camera,
const QRectF &inViewport,
Configuration config = {});
/*!
* \brief calculateProjection
* \param inViewport
* \param config
* \return true if the projection was successfully calculated, false otherwise.
*
* This function will calculate the projection matrix for the camera.
*
* NOTE: This function will not update the camera's global transform. It is the caller's
* responsibility to ensure that the camera's global transform has been calculated prior
* to calling this function.
*/
bool calculateProjection(const QRectF &inViewport, Configuration config = {});
void setCustomProjection(const QMatrix4x4 &proj);
static bool computeFrustumOrtho(QRectF inViewport,
QSSGRenderCamera::ClipPlanes clipPlanes,
QSSGRenderCamera::Magnification magnification,
Configuration config,
QMatrix4x4 &outProjection);
static bool computeFrustumPerspective(QRectF inViewport,
FieldOfView fov,
QSSGRenderCamera::ClipPlanes clipPlanes,
QMatrix4x4 &outProjection);
static bool computeCustomFrustum(QSSGRenderCamera::Frustum frustum,
QSSGRenderCamera::ClipPlanes clipPlanes,
QMatrix4x4 &outProjection);
static void calculateViewProjectionMatrix(const QMatrix4x4 &globalTransform,
const QMatrix4x4 &projection,
QMatrix4x4 &outMatrix);
void calculateViewProjectionMatrix(const QMatrix4x4 &globalTransform, QMatrix4x4 &outMatrix) const;
void calculateViewProjectionWithoutTranslation(const QMatrix4x4 &globalTransform, float near, float far, QMatrix4x4 &outMatrix) const;
// Unproject a point (x,y) in viewport relative coordinates meaning
// left, bottom is 0,0 and values are increasing right,up respectively.
QSSGRenderRay unproject(const QMatrix4x4 &globalTransform, const QVector2D &inLayerRelativeMouseCoords, const QRectF &inViewport) const;
[[nodiscard]] inline bool isDirty(DirtyFlag dirtyFlag = DirtyMask) const
{
return ((cameraDirtyFlags & FlagT(dirtyFlag)) != 0)
|| ((dirtyFlag == DirtyMask) && QSSGRenderNode::isDirty());
}
void markDirty(DirtyFlag dirtyFlag);
void clearDirty(DirtyFlag dirtyFlag);
float getLevelOfDetailMultiplier() const;
float getDpr() const { return dpr; }
// Setting these variables should be followed by marking the camera dirty!
ClipPlanes clipPlanes;
FieldOfView fov;
Frustum customFrustum;
Magnification magnification;
QMatrix4x4 projection;
float levelOfDetailPixelThreshold = 1.0;
quint32 layerMask = LayerMaskAll;
bool enableFrustumClipping = true;
private:
// Record some values from creating the projection matrix
// to use during mouse picking.
QVector2D frustumScale;
QRectF previousInViewport;
float dpr = 1.0f;
FlagT cameraDirtyFlags = 0;
};
[[nodiscard]] constexpr bool qFuzzyCompare(const QSSGRenderCamera::FieldOfView &fov1, const QSSGRenderCamera::FieldOfView &fov2) noexcept
{
return fov1.orientation() == fov2.orientation() && qFuzzyCompare(fov1.degrees(), fov2.degrees());
}
[[nodiscard]] constexpr bool qFuzzyCompare(QSSGRenderCamera::Frustum f1, QSSGRenderCamera::Frustum f2) noexcept
{
return qFuzzyCompare(f1.top, f2.top) && qFuzzyCompare(f1.bottom, f2.bottom) && qFuzzyCompare(f1.left, f2.left) && qFuzzyCompare(f1.right, f2.right);
}
QT_END_NAMESPACE
#endif