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 {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 {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 {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 {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 | |