1// Copyright (C) 2019 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
3
4#include "qquick3ddirectionallight_p.h"
5#include "qquick3dobject_p.h"
6
7#include <QtQuick3DRuntimeRender/private/qssgrenderlight_p.h>
8
9#include "qquick3dnode_p_p.h"
10
11QT_BEGIN_NAMESPACE
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 float 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}
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 float 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 float 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 float 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
157QQuick3DDirectionalLight::QQuick3DDirectionalLight(QQuick3DNode *parent)
158 : QQuick3DAbstractLight(*(new QQuick3DNodePrivate(QQuick3DNodePrivate::Type::DirectionalLight)), parent) {}
159
160float QQuick3DDirectionalLight::csmSplit1() const
161{
162 return m_csmSplit1;
163}
164
165float QQuick3DDirectionalLight::csmSplit2() const
166{
167 return m_csmSplit2;
168}
169
170float QQuick3DDirectionalLight::csmSplit3() const
171{
172 return m_csmSplit3;
173}
174
175int QQuick3DDirectionalLight::csmNumSplits() const
176{
177 return m_csmNumSplits;
178}
179
180float QQuick3DDirectionalLight::csmBlendRatio() const
181{
182 return m_csmBlendRatio;
183}
184
185void QQuick3DDirectionalLight::setCsmSplit1(float newcsmSplit1)
186{
187 newcsmSplit1 = qBound(min: 0.0f, val: newcsmSplit1, max: 1.0f);
188 if (qFuzzyCompare(p1: m_csmSplit1, p2: newcsmSplit1))
189 return;
190
191 m_csmSplit1 = newcsmSplit1;
192 emit csmSplit1Changed();
193 m_dirtyFlags.setFlag(flag: QQuick3DAbstractLight::DirtyFlag::ShadowDirty);
194 update();
195}
196
197void QQuick3DDirectionalLight::setCsmSplit2(float newcsmSplit2)
198{
199 newcsmSplit2 = qBound(min: 0.0f, val: newcsmSplit2, max: 1.0f);
200 if (qFuzzyCompare(p1: m_csmSplit2, p2: newcsmSplit2))
201 return;
202
203 m_csmSplit2 = newcsmSplit2;
204 emit csmSplit2Changed();
205 m_dirtyFlags.setFlag(flag: QQuick3DAbstractLight::DirtyFlag::ShadowDirty);
206 update();
207}
208
209void QQuick3DDirectionalLight::setCsmSplit3(float newcsmSplit3)
210{
211 newcsmSplit3 = qBound(min: 0.0f, val: newcsmSplit3, max: 1.0f);
212 if (qFuzzyCompare(p1: m_csmSplit3, p2: newcsmSplit3))
213 return;
214
215 m_csmSplit3 = newcsmSplit3;
216 emit csmSplit3Changed();
217 m_dirtyFlags.setFlag(flag: QQuick3DAbstractLight::DirtyFlag::ShadowDirty);
218 update();
219}
220
221void QQuick3DDirectionalLight::setCsmNumSplits(int newcsmNumSplits)
222{
223 newcsmNumSplits = qBound(min: 0, val: newcsmNumSplits, max: 3);
224 if (m_csmNumSplits == newcsmNumSplits)
225 return;
226
227 m_csmNumSplits = newcsmNumSplits;
228 emit csmNumSplitsChanged();
229 m_dirtyFlags.setFlag(flag: QQuick3DAbstractLight::DirtyFlag::ShadowDirty);
230 update();
231}
232
233void QQuick3DDirectionalLight::setCsmBlendRatio(float newcsmBlendRatio)
234{
235 newcsmBlendRatio = qBound(min: 0.0, val: newcsmBlendRatio, max: 1.0);
236 if (m_csmBlendRatio == newcsmBlendRatio)
237 return;
238
239 m_csmBlendRatio = newcsmBlendRatio;
240 emit csmBlendRatioChanged();
241 m_dirtyFlags.setFlag(flag: QQuick3DAbstractLight::DirtyFlag::ShadowDirty);
242 update();
243}
244
245QSSGRenderGraphObject *QQuick3DDirectionalLight::updateSpatialNode(QSSGRenderGraphObject *node)
246{
247 if (!node) {
248 markAllDirty();
249 node = new QSSGRenderLight(/* defaults to directional */);
250 }
251
252 if (m_dirtyFlags.testFlag(flag: DirtyFlag::ShadowDirty)) {
253 QSSGRenderLight *light = static_cast<QSSGRenderLight *>(node);
254 light->m_csmSplit1 = m_csmSplit1;
255 light->m_csmSplit2 = m_csmSplit2;
256 light->m_csmSplit3 = m_csmSplit3;
257 light->m_csmNumSplits = m_csmNumSplits;
258 light->m_csmBlendRatio = m_csmBlendRatio;
259 }
260
261 QQuick3DAbstractLight::updateSpatialNode(node); // Marks the light node dirty if m_dirtyFlags != 0
262
263 return node;
264}
265
266QT_END_NAMESPACE
267

Provided by KDAB

Privacy Policy
Learn Advanced QML with KDAB
Find out more

source code of qtquick3d/src/quick3d/qquick3ddirectionallight.cpp