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
qquick3ddirectionallight.cpp
Go to the documentation of this file.
1// Copyright (C) 2019 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
3
6
7#include <QtQuick3DRuntimeRender/private/qssgrenderlight_p.h>
8
10
12
13/*!
14 \qmltype DirectionalLight
15 \inherits Light
16 \inqmlmodule QtQuick3D
17 \brief Defines a directional light in the scene.
18
19 The directional light emits light in one direction from an unidentifiable source located
20 infinitely far away. This is similar to the way sunlight works in real life. A directional
21 light has infinite range and does not diminish.
22
23 If \l {Light::castsShadow}{castsShadow} is enabled, shadows will be parallel to the light
24 direction.
25
26 A directional light effectively have no position, so moving it does not
27 have any effect. The light will always be emitted in the direction of the
28 light's Z axis.
29
30 Rotating the light along its X or Y axis will change the direction of the light emission.
31
32 Scaling a directional light will only have an effect in the following cases:
33 \list
34 \li If Z scale is set to a negative number, the light will be emitted in the opposite direction.
35 \li If the scale of any axis is set to 0, the light will be emitted along the world's Z axis.
36 \note Rotating the light will then have no effect.
37 \endlist
38
39 Let's look at a simple example:
40
41 \qml
42 import QtQuick
43 import QtQuick3D
44 View3D {
45 anchors.fill: parent
46
47 PerspectiveCamera { z: 600 }
48
49 DirectionalLight {
50 }
51
52 Model {
53 source: "#Sphere"
54 scale: Qt.vector3d(4, 4, 4)
55 materials: PrincipledMaterial {
56 baseColor: "#40c060"
57 roughness: 0.1 // make specular highlight visible
58 }
59 }
60 }
61 \endqml
62
63 Here the DirectionalLight uses the default \c white color, emitting in the
64 direction of the DirectionalLight node's Z axis.
65
66 \image directionallight-1.png
67
68 Rotating 60 degrees around the X axis would lead to the following. Instead
69 of emitting straight in the direction of the Z axis, the light is now
70 pointing 60 degrees "down":
71
72 \qml
73 DirectionalLight {
74 eulerRotation.x: 60
75 }
76 \endqml
77
78 \image directionallight-2.png
79
80 For further usage examples, see \l{Qt Quick 3D - Lights Example}.
81
82 \sa PointLight, SpotLight, {Shadow Mapping}
83*/
84
85/*!
86 \qmlproperty real DirectionalLight::csmSplit1
87 \since 6.8
88
89 This property defines where the first cascade of the shadow map split will occur when
90 CSM is active.
91
92 Range: \c{[0.0, 1.0]}
93
94 Default value: \c{0.1}
95
96 \sa csmSplit2, csmSplit3
97 \note This property is only used when DirectionalLight::csmNumSplits is greater than \c{0}.
98*/
99
100/*!
101 \qmlproperty real DirectionalLight::csmSplit2
102 \since 6.8
103
104 This property defines where the second cascade of the shadow map split will occur when
105 CSM is active.
106
107 Range: \c{[0.0, 1.0]}
108
109 Default value: \c{0.25}
110
111 \sa csmSplit1, csmSplit3
112 \note This property is only used when DirectionalLight::csmNumSplits is greater than \c{1}.
113*/
114
115/*!
116 \qmlproperty real DirectionalLight::csmSplit3
117 \since 6.8
118
119 This property defines where the third cascade of the shadow map split will occur when
120 CSM is active.
121
122 Range: \c{[0.0, 1.0]}
123
124 Default value: \c{0.5}
125
126 \sa csmSplit1, csmSplit2
127 \note This property is only used when DirectionalLight::csmNumSplits is greater than \c{2}.
128*/
129
130/*!
131 \qmlproperty int DirectionalLight::csmNumSplits
132 \since 6.8
133
134 This property defines the number of splits the frustum should be split by when
135 rendering the shadowmap. No splits means that the shadowmap will be rendered
136 so that it covers the bounding box of all shadow casting and receiving objects.
137
138 Range: \c{[0, 3]}
139
140 Default value: \c{0}
141
142 \sa csmSplit1, csmSplit2, csmSplit3
143*/
144
145/*!
146 \qmlproperty real DirectionalLight::csmBlendRatio
147 \since 6.8
148
149 This property defines how much of the shadow of any cascade should be blended
150 together with the previous one.
151
152 Range: \c{[0.0, 1.0]}
153
154 Default value: \c{0.05}
155*/
156
157/*!
158 \qmlproperty bool DirectionalLight::lockShadowmapTexels
159 \since 6.9
160
161 When this property is enabled, the shadowmap texels are "locked" in position in the
162 world eliminating shadow edge shimmering at the cost of bigger shadowmap texels.
163 It works by using uniform sized, and texel aligned shadowmaps for each cascade.
164
165 Default value: \c{false}
166*/
167
168QQuick3DDirectionalLight::QQuick3DDirectionalLight(QQuick3DNode *parent)
169 : QQuick3DAbstractLight(*(new QQuick3DNodePrivate(QQuick3DNodePrivate::Type::DirectionalLight)), parent) {}
170
171float QQuick3DDirectionalLight::csmSplit1() const
172{
173 return m_csmSplit1;
174}
175
176float QQuick3DDirectionalLight::csmSplit2() const
177{
178 return m_csmSplit2;
179}
180
181float QQuick3DDirectionalLight::csmSplit3() const
182{
183 return m_csmSplit3;
184}
185
186int QQuick3DDirectionalLight::csmNumSplits() const
187{
188 return m_csmNumSplits;
189}
190
191float QQuick3DDirectionalLight::csmBlendRatio() const
192{
193 return m_csmBlendRatio;
194}
195
196bool QQuick3DDirectionalLight::lockShadowmapTexels() const
197{
198 return m_lockShadowmapTexels;
199}
200
201void QQuick3DDirectionalLight::setCsmSplit1(float newcsmSplit1)
202{
203 newcsmSplit1 = qBound(0.0f, newcsmSplit1, 1.0f);
204 if (qFuzzyCompare(m_csmSplit1, newcsmSplit1))
205 return;
206
207 m_csmSplit1 = newcsmSplit1;
208 emit csmSplit1Changed();
209 m_dirtyFlags.setFlag(QQuick3DAbstractLight::DirtyFlag::ShadowDirty);
210 update();
211}
212
213void QQuick3DDirectionalLight::setCsmSplit2(float newcsmSplit2)
214{
215 newcsmSplit2 = qBound(0.0f, newcsmSplit2, 1.0f);
216 if (qFuzzyCompare(m_csmSplit2, newcsmSplit2))
217 return;
218
219 m_csmSplit2 = newcsmSplit2;
220 emit csmSplit2Changed();
221 m_dirtyFlags.setFlag(QQuick3DAbstractLight::DirtyFlag::ShadowDirty);
222 update();
223}
224
225void QQuick3DDirectionalLight::setCsmSplit3(float newcsmSplit3)
226{
227 newcsmSplit3 = qBound(0.0f, newcsmSplit3, 1.0f);
228 if (qFuzzyCompare(m_csmSplit3, newcsmSplit3))
229 return;
230
231 m_csmSplit3 = newcsmSplit3;
232 emit csmSplit3Changed();
233 m_dirtyFlags.setFlag(QQuick3DAbstractLight::DirtyFlag::ShadowDirty);
234 update();
235}
236
237void QQuick3DDirectionalLight::setCsmNumSplits(int newcsmNumSplits)
238{
239 newcsmNumSplits = qBound(0, newcsmNumSplits, 3);
240 if (m_csmNumSplits == newcsmNumSplits)
241 return;
242
243 m_csmNumSplits = newcsmNumSplits;
244 emit csmNumSplitsChanged();
245 m_dirtyFlags.setFlag(QQuick3DAbstractLight::DirtyFlag::ShadowDirty);
246 update();
247}
248
249void QQuick3DDirectionalLight::setCsmBlendRatio(float newcsmBlendRatio)
250{
251 newcsmBlendRatio = qBound(0.0, newcsmBlendRatio, 1.0);
252 if (m_csmBlendRatio == newcsmBlendRatio)
253 return;
254
255 m_csmBlendRatio = newcsmBlendRatio;
256 emit csmBlendRatioChanged();
257 m_dirtyFlags.setFlag(QQuick3DAbstractLight::DirtyFlag::ShadowDirty);
258 update();
259}
260
261void QQuick3DDirectionalLight::setLockShadowmapTexels(bool newLockShadowmapTexels)
262{
263 if (m_lockShadowmapTexels == newLockShadowmapTexels)
264 return;
265
266 m_lockShadowmapTexels = newLockShadowmapTexels;
267 emit lockShadowmapTexelsChanged();
268 m_dirtyFlags.setFlag(QQuick3DAbstractLight::DirtyFlag::ShadowDirty);
269 update();
270}
271
272QSSGRenderGraphObject *QQuick3DDirectionalLight::updateSpatialNode(QSSGRenderGraphObject *node)
273{
274 if (!node) {
275 markAllDirty();
276 node = new QSSGRenderLight(/* defaults to directional */);
277 }
278
279 if (m_dirtyFlags.testFlag(DirtyFlag::ShadowDirty)) {
280 QSSGRenderLight *light = static_cast<QSSGRenderLight *>(node);
281 light->m_csmSplit1 = m_csmSplit1;
282 light->m_csmSplit2 = m_csmSplit2;
283 light->m_csmSplit3 = m_csmSplit3;
284 light->m_csmNumSplits = m_csmNumSplits;
285 light->m_csmBlendRatio = m_csmBlendRatio;
286 light->m_lockShadowmapTexels = m_lockShadowmapTexels;
287 }
288
289 QQuick3DAbstractLight::updateSpatialNode(node); // Marks the light node dirty if m_dirtyFlags != 0
290
291 return node;
292}
293
294QT_END_NAMESPACE