Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qquick3dspotlight.cpp
Go to the documentation of this file.
1// Copyright (C) 2020 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
3// Qt-Security score:significant reason:default
4
5
8
9#include <QtQuick3DRuntimeRender/private/qssgrenderlight_p.h>
10
12
14
15/*!
16 \qmltype SpotLight
17 \inherits Light
18 \inqmlmodule QtQuick3D
19 \brief Defines a spot light in the scene.
20 \since 5.15
21
22 The spot light emits light towards one direction in a cone shape, which is defined by the
23 \l {coneAngle} property. The light intensity diminishes when approaching the \l {coneAngle}.
24 The angle at which the light intensity starts to diminish is defined by \l {innerConeAngle}.
25 Both angles are defined in degrees.
26
27 Inside the \l {innerConeAngle}, the spot light behaves similarly to the point light.
28 There the light intensity diminishes according to inverse-square-law. However, the fade-off
29 (and range) can be controlled with the \l {constantFade}, \l {linearFade}, and
30 \l quadraticFade properties. Light attenuation is calculated using the formula:
31 \l {constantFade} + \c distance * (\l {linearFade} * 0.01) + \c distance * (\l {quadraticFade} * 0.0001)^2
32
33 Let's look at a simple example. Here a SpotLight is placed at 300 on the Z
34 axis, so halfway between the camera and the scene center. By default the
35 light is emitting in the direction of the Z axis. The \l {Light::}{brightness} is
36 increased to 10 to make it look more like a typical spot light.
37
38 \qml
39 import QtQuick
40 import QtQuick3D
41 View3D {
42 anchors.fill: parent
43
44 PerspectiveCamera { z: 600 }
45
46 SpotLight {
47 z: 300
48 brightness: 10
49 ambientColor: Qt.rgba(0.1, 0.1, 0.1, 1.0)
50 }
51
52 Model {
53 source: "#Rectangle"
54 scale: Qt.vector3d(10, 10, 10)
55 z: -100
56 materials: PrincipledMaterial { }
57 }
58
59 Model {
60 source: "#Sphere"
61 scale: Qt.vector3d(2, 2, 2)
62 materials: PrincipledMaterial {
63 baseColor: "#40c060"
64 roughness: 0.1
65 }
66 }
67 }
68 \endqml
69
70 \image spotlight-1.png {Green sphere with spotlight cone angle visualization}
71
72 Rotations happens similarly to \l DirectionalLight. Here we want to light to
73 emit more to the right, so we rotate around the Y axis by -20 degrees. The
74 cone is reduced by setting coneAngle to 30 instead of the default 40. We
75 also make the intensity start diminish earlier, by changing innerConeAngle
76 to 10.
77
78 \qml
79 SpotLight {
80 z: 300
81 brightness: 10
82 ambientColor: Qt.rgba(0.1, 0.1, 0.1, 1.0)
83 eulerRotation.y: -20
84 coneAngle: 30
85 innerConeAngle: 10
86 }
87 \endqml
88
89 \image spotlight-2.png {Green sphere with spotlight inner and outer cone angles}
90
91 For further usage examples, see \l{Qt Quick 3D - Lights Example}.
92
93 \sa DirectionalLight, PointLight, {Shadow Mapping}
94*/
95
96/*!
97 \qmlproperty real SpotLight::constantFade
98
99 This property is constant factor of the attenuation term of the light.
100 The default value is 1.0.
101 */
102
103/*!
104 \qmlproperty real SpotLight::linearFade
105
106 This property increases the rate at which the lighting effect dims the light
107 in proportion to the distance to the light. The default value is \c 0.0, which means the light
108 doesn't have linear fade. The value used here is multiplied by \c 0.01 before being used to
109 calculate light attenuation.
110*/
111
112/*!
113 \qmlproperty real SpotLight::quadraticFade
114
115 This property increases the rate at which the lighting effect dims the light
116 in proportion to the inverse square law. The default value is 1.0, which means the spot light
117 fade exactly follows the inverse square law, i.e. when distance to an object doubles the
118 light intensity decreases to 1/4th. The value used here is multiplied by \c 0.0001 before
119 being used to calculate light attenuation.
120*/
121
122/*!
123 \qmlproperty real SpotLight::coneAngle
124
125 This property defines the cut-off angle (from edge to edge) beyond which the light doesn't affect the scene.
126 Defined in degrees between \c{0} and \c{180}. The default value is \c{40}.
127
128 \note When the cone angle approaches \c{180} degrees the shadow quality will start to deteriorate. A value
129 under \c{170} is therefore recommended.
130*/
131
132/*!
133 \qmlproperty real SpotLight::innerConeAngle
134
135 This property defines the angle (from edge to edge) at which the light intensity starts to gradually diminish
136 as it approaches \l {coneAngle}. Defined in degrees between 0 and 180. If the value is set
137 larger than \l {coneAngle}, it'll behave as if it had the same value as \l {coneAngle}.
138 The default value is 30.
139*/
140
141QQuick3DSpotLight::QQuick3DSpotLight(QQuick3DNode *parent)
142 : QQuick3DAbstractLight(*(new QQuick3DNodePrivate(QQuick3DNodePrivate::Type::SpotLight)), parent) {}
143
144float QQuick3DSpotLight::constantFade() const
145{
146 return m_constantFade;
147}
148
149float QQuick3DSpotLight::linearFade() const
150{
151 return m_linearFade;
152}
153
154float QQuick3DSpotLight::quadraticFade() const
155{
156 return m_quadraticFade;
157}
158
159float QQuick3DSpotLight::coneAngle() const
160{
161 return m_coneAngle;
162}
163
164float QQuick3DSpotLight::innerConeAngle() const
165{
166 return m_innerConeAngle;
167}
168
169void QQuick3DSpotLight::setConstantFade(float constantFade)
170{
171 if (qFuzzyCompare(m_constantFade, constantFade))
172 return;
173
174 m_constantFade = constantFade;
175 m_dirtyFlags.setFlag(DirtyFlag::FadeDirty);
176 emit constantFadeChanged();
177 update();
178}
179
180void QQuick3DSpotLight::setLinearFade(float linearFade)
181{
182 if (qFuzzyCompare(m_linearFade, linearFade))
183 return;
184
185 m_linearFade = linearFade;
186 m_dirtyFlags.setFlag(DirtyFlag::FadeDirty);
187 emit linearFadeChanged();
188 update();
189}
190
191void QQuick3DSpotLight::setQuadraticFade(float quadraticFade)
192{
193 if (qFuzzyCompare(m_quadraticFade, quadraticFade))
194 return;
195
196 m_quadraticFade = quadraticFade;
197 m_dirtyFlags.setFlag(DirtyFlag::FadeDirty);
198 emit quadraticFadeChanged();
199 update();
200}
201
202void QQuick3DSpotLight::setConeAngle(float coneAngle)
203{
204 if (coneAngle < 0.f)
205 coneAngle = 0.f;
206 else if (coneAngle > 180.f)
207 coneAngle = 180.f;
208
209 if (qFuzzyCompare(m_coneAngle, coneAngle))
210 return;
211
212 m_coneAngle = coneAngle;
213 m_dirtyFlags.setFlag(DirtyFlag::AreaDirty);
214 emit coneAngleChanged();
215 update();
216}
217
218void QQuick3DSpotLight::setInnerConeAngle(float innerConeAngle)
219{
220 if (innerConeAngle < 0.f)
221 innerConeAngle = 0.f;
222 else if (innerConeAngle > 180.f)
223 innerConeAngle = 180.f;
224
225 if (qFuzzyCompare(m_innerConeAngle, innerConeAngle))
226 return;
227
228 m_innerConeAngle = innerConeAngle;
229 m_dirtyFlags.setFlag(DirtyFlag::AreaDirty);
230 emit innerConeAngleChanged();
231 update();
232}
233
234QSSGRenderGraphObject *QQuick3DSpotLight::updateSpatialNode(QSSGRenderGraphObject *node)
235{
236 if (!node) {
237 markAllDirty();
238 node = new QSSGRenderLight(QSSGRenderLight::Type::SpotLight);
239 }
240
241 QQuick3DAbstractLight::updateSpatialNode(node); // Marks the light node dirty if m_dirtyFlags != 0
242
243 QSSGRenderLight *light = static_cast<QSSGRenderLight *>(node);
244
245 if (m_dirtyFlags.testFlag(DirtyFlag::FadeDirty)) {
246 m_dirtyFlags.setFlag(DirtyFlag::FadeDirty, false);
247 light->m_constantFade = m_constantFade;
248 light->m_linearFade = m_linearFade;
249 light->m_quadraticFade = m_quadraticFade;
250 }
251
252 if (m_dirtyFlags.testFlag(DirtyFlag::AreaDirty)) {
253 m_dirtyFlags.setFlag(DirtyFlag::AreaDirty, false);
254 light->m_coneAngle = qBound(0.0f, m_coneAngle * 0.5, 90.0f);
255 light->m_innerConeAngle = qBound(0.0f, m_innerConeAngle * 0.5, 90.0f);
256 }
257
258 return node;
259}
260
261QT_END_NAMESPACE
Combined button and popup list for selecting options.