| 1 | // Copyright (C) 2019 The Qt Company Ltd. |
| 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only |
| 3 | |
| 4 | #include "qquick3dfrustumcamera_p.h" |
| 5 | |
| 6 | #include <QtQuick3DRuntimeRender/private/qssgrendercamera_p.h> |
| 7 | |
| 8 | #include <QtMath> |
| 9 | #include <QtQuick3DUtils/private/qssgutils_p.h> |
| 10 | |
| 11 | #include "qquick3dutils_p.h" |
| 12 | |
| 13 | #include "qquick3dnode_p_p.h" |
| 14 | |
| 15 | QT_BEGIN_NAMESPACE |
| 16 | |
| 17 | /*! |
| 18 | \qmltype FrustumCamera |
| 19 | \inherits PerspectiveCamera |
| 20 | \inqmlmodule QtQuick3D |
| 21 | \brief Defines a PerspectiveCamera with a custom frustum. |
| 22 | |
| 23 | A \l Camera defines how the content of the 3D scene is projected onto a 2D surface, |
| 24 | such as a View3D. A scene needs at least one \l Camera in order to visualize its |
| 25 | contents. |
| 26 | |
| 27 | It is possible to position and rotate the \l Camera like any other spatial \l{QtQuick3D::Node}{Node} in |
| 28 | the scene. The \l{QtQuick3D::Node}{Node}'s location and orientation determines where the \l Camera is in |
| 29 | the scene, and what direction it is facing. The default orientation of the \l Camera |
| 30 | has its forward vector pointing along the negative Z axis and its up vector along |
| 31 | the positive Y axis. |
| 32 | |
| 33 | The FrustumCamera type provides a PerspectiveCamera where the frustum bounds can be |
| 34 | customized. This can be useful for creating asymmetrical frustums. |
| 35 | |
| 36 | The following example creates a FrustumCamera at [0, 0, 100] in the scene. |
| 37 | The \l {PerspectiveCamera::clipNear}{near plane} is placed 100 units in front of the camera at the origin. |
| 38 | The intersection of the frustum and the near plane is then given by the rectangle that has a bottom left corner at [-5, -5], |
| 39 | and a top right corner at [5, 5], and continues until it intersect the |
| 40 | \l {PerspectiveCamera::clipFar}{far plane}, which is located 1000 units from the camera at [0, 0, -900]. |
| 41 | |
| 42 | \note The \l{PerspectiveCamera::fieldOfViewOrientation}{vertical field of view} angle is |
| 43 | a product of the distance between the camera, the \l {PerspectiveCamera::clipNear}{near plane} |
| 44 | and the length between the \c top and \c bottom of the near plane. |
| 45 | |
| 46 | \note If the top and bottom, or left right, values are asymmetric, |
| 47 | the apex of the frustum will be shifted, effectively offsetting the camera from its location. |
| 48 | |
| 49 | \code |
| 50 | FrustumCamera { |
| 51 | position: Qt.vector3d(0, 0, 100) |
| 52 | clipNear: 100 |
| 53 | clipFar: 1000 |
| 54 | top: 5 |
| 55 | bottom: -5 |
| 56 | left: -5 |
| 57 | right: 5 |
| 58 | } |
| 59 | \endcode |
| 60 | |
| 61 | \sa PerspectiveCamera, OrthographicCamera, CustomCamera |
| 62 | */ |
| 63 | |
| 64 | /*! |
| 65 | * \internal |
| 66 | */ |
| 67 | QQuick3DFrustumCamera::QQuick3DFrustumCamera(QQuick3DNode *parent) |
| 68 | : QQuick3DPerspectiveCamera(*(new QQuick3DNodePrivate(QQuick3DNodePrivate::Type::CustomFrustumCamera)), parent) |
| 69 | {} |
| 70 | |
| 71 | /*! |
| 72 | \qmlproperty real FrustumCamera::top |
| 73 | |
| 74 | The \c top value specifies the top of the \l{PerspectiveCamera::clipNear}{near clip plane}, |
| 75 | relative to the camera's position in local coordinates. |
| 76 | */ |
| 77 | float QQuick3DFrustumCamera::top() const |
| 78 | { |
| 79 | return m_top; |
| 80 | } |
| 81 | |
| 82 | /*! |
| 83 | \qmlproperty real FrustumCamera::bottom |
| 84 | |
| 85 | The \c bottom value specifies the bottom of the \l{PerspectiveCamera::clipNear}{near clip plane}, |
| 86 | relative to the camera's position in local coordinates. |
| 87 | */ |
| 88 | float QQuick3DFrustumCamera::bottom() const |
| 89 | { |
| 90 | return m_bottom; |
| 91 | } |
| 92 | |
| 93 | /*! |
| 94 | \qmlproperty real FrustumCamera::right |
| 95 | |
| 96 | The \c right value specifies the right of the \l{PerspectiveCamera::clipNear}{near clip plane}, |
| 97 | relative to the camera's position in local coordinates. |
| 98 | */ |
| 99 | float QQuick3DFrustumCamera::right() const |
| 100 | { |
| 101 | return m_right; |
| 102 | } |
| 103 | |
| 104 | /*! |
| 105 | \qmlproperty real FrustumCamera::left |
| 106 | |
| 107 | The \c left value specifies the left of the \l{PerspectiveCamera::clipNear}{near clip plane}, |
| 108 | relative to the camera's position in local coordinates. |
| 109 | */ |
| 110 | float QQuick3DFrustumCamera::left() const |
| 111 | { |
| 112 | return m_left; |
| 113 | } |
| 114 | |
| 115 | void QQuick3DFrustumCamera::setTop(float top) |
| 116 | { |
| 117 | if (qFuzzyCompare(p1: m_top, p2: top)) |
| 118 | return; |
| 119 | |
| 120 | m_top = top; |
| 121 | emit topChanged(); |
| 122 | update(); |
| 123 | } |
| 124 | |
| 125 | void QQuick3DFrustumCamera::setBottom(float bottom) |
| 126 | { |
| 127 | if (qFuzzyCompare(p1: m_bottom, p2: bottom)) |
| 128 | return; |
| 129 | |
| 130 | m_bottom = bottom; |
| 131 | emit bottomChanged(); |
| 132 | update(); |
| 133 | } |
| 134 | |
| 135 | void QQuick3DFrustumCamera::setRight(float right) |
| 136 | { |
| 137 | if (qFuzzyCompare(p1: m_right, p2: right)) |
| 138 | return; |
| 139 | |
| 140 | m_right = right; |
| 141 | emit rightChanged(); |
| 142 | update(); |
| 143 | } |
| 144 | |
| 145 | void QQuick3DFrustumCamera::setLeft(float left) |
| 146 | { |
| 147 | if (qFuzzyCompare(p1: m_left, p2: left)) |
| 148 | return; |
| 149 | |
| 150 | m_left = left; |
| 151 | emit leftChanged(); |
| 152 | update(); |
| 153 | } |
| 154 | |
| 155 | QSSGRenderGraphObject *QQuick3DFrustumCamera::updateSpatialNode(QSSGRenderGraphObject *node) |
| 156 | { |
| 157 | // NOTE: The frustum camera extends the perspective camera! |
| 158 | QSSGRenderCamera *camera = static_cast<QSSGRenderCamera *>(QQuick3DPerspectiveCamera::updateSpatialNode(node)); |
| 159 | if (camera) { |
| 160 | const bool changed = ((int(qUpdateIfNeeded(orig&: camera->top, updated: m_top)) |
| 161 | | int(qUpdateIfNeeded(orig&: camera->bottom, updated: m_bottom)) |
| 162 | | int(qUpdateIfNeeded(orig&: camera->right, updated: m_right)) |
| 163 | | int(qUpdateIfNeeded(orig&: camera->left, updated: m_left))) != 0); |
| 164 | if (changed) |
| 165 | camera->markDirty(dirtyFlag: QSSGRenderCamera::DirtyFlag::CameraDirty); |
| 166 | } |
| 167 | |
| 168 | return camera; |
| 169 | } |
| 170 | |
| 171 | QT_END_NAMESPACE |
| 172 | |