1// Copyright (C) 2008-2012 NVIDIA Corporation.
2// Copyright (C) 2019 The Qt Company Ltd.
3// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
4
5#ifndef QSSG_RENDER_IMPL_RENDERABLE_OBJECTS_H
6#define QSSG_RENDER_IMPL_RENDERABLE_OBJECTS_H
7
8//
9// W A R N I N G
10// -------------
11//
12// This file is not part of the Qt API. It exists purely as an
13// implementation detail. This header file may change from version to
14// version without notice, or even be removed.
15//
16// We mean it.
17//
18
19#include <QtQuick3DRuntimeRender/private/qssgrendermodel_p.h>
20#include <QtQuick3DRuntimeRender/private/qssgrenderdefaultmaterial_p.h>
21#include <QtQuick3DRuntimeRender/private/qssgrendercustommaterial_p.h>
22#include <QtQuick3DRuntimeRender/private/qssgrenderparticles_p.h>
23#include <QtQuick3DRuntimeRender/private/qssgrendermesh_p.h>
24#include <QtQuick3DRuntimeRender/private/qssgrendershaderkeys_p.h>
25#include <QtQuick3DRuntimeRender/private/qssgrendershadercache_p.h>
26#include <QtQuick3DRuntimeRender/private/qssgrenderableimage_p.h>
27#include <QtQuick3DRuntimeRender/private/qssgrenderlight_p.h>
28#include <QtQuick3DRuntimeRender/private/qssgrenderreflectionprobe_p.h>
29#include <QtQuick3DRuntimeRender/private/qssgrenderclippingfrustum_p.h>
30
31#include <QtQuick3DUtils/private/qssginvasivelinkedlist_p.h>
32
33QT_BEGIN_NAMESPACE
34
35class QSSGRenderer;
36class QSSGRenderableObject;
37struct QSSGRenderItem2D;
38
39enum class QSSGRenderableObjectFlag : quint32
40{
41 HasTransparency = 1 << 0,
42 CompletelyTransparent = 1 << 1,
43 Dirty = 1 << 2,
44 CastsShadows = 1 << 3,
45 ReceivesShadows = 1 << 4,
46 HasAttributePosition = 1 << 5,
47 HasAttributeNormal = 1 << 6,
48 HasAttributeTexCoord0 = 1 << 7,
49 HasAttributeTexCoord1 = 1 << 8,
50 HasAttributeTangent = 1 << 9,
51 HasAttributeBinormal = 1 << 10,
52 HasAttributeColor = 1 << 11,
53 HasAttributeJointAndWeight = 1 << 12,
54 IsPointsTopology = 1 << 13,
55 // The number of target models' attributes are too many
56 // to store in a renderable flag.
57 // They will be recorded in shaderKey.
58 HasAttributeMorphTarget = 1 << 14,
59 RequiresScreenTexture = 1 << 15,
60 ReceivesReflections = 1 << 16,
61 UsedInBakedLighting = 1 << 17,
62 RendersWithLightmap = 1 << 18,
63 HasAttributeTexCoordLightmap = 1 << 19,
64 CastsReflections = 1 << 20
65};
66
67struct QSSGRenderableObjectFlags : public QFlags<QSSGRenderableObjectFlag>
68{
69 void setHasTransparency(bool inHasTransparency)
70 {
71 setFlag(flag: QSSGRenderableObjectFlag::HasTransparency, on: inHasTransparency);
72 }
73 bool hasTransparency() const { return this->operator&(other: QSSGRenderableObjectFlag::HasTransparency); }
74 void setCompletelyTransparent(bool inTransparent)
75 {
76 setFlag(flag: QSSGRenderableObjectFlag::CompletelyTransparent, on: inTransparent);
77 }
78 bool isCompletelyTransparent() const
79 {
80 return this->operator&(other: QSSGRenderableObjectFlag::CompletelyTransparent);
81 }
82 void setDirty(bool inDirty) { setFlag(flag: QSSGRenderableObjectFlag::Dirty, on: inDirty); }
83 bool isDirty() const { return this->operator&(other: QSSGRenderableObjectFlag::Dirty); }
84
85 void setCastsShadows(bool inCastsShadows) { setFlag(flag: QSSGRenderableObjectFlag::CastsShadows, on: inCastsShadows); }
86 bool castsShadows() const { return this->operator&(other: QSSGRenderableObjectFlag::CastsShadows); }
87
88 void setReceivesShadows(bool inReceivesShadows) { setFlag(flag: QSSGRenderableObjectFlag::ReceivesShadows, on: inReceivesShadows); }
89 bool receivesShadows() const { return this->operator&(other: QSSGRenderableObjectFlag::ReceivesShadows); }
90
91 void setReceivesReflections(bool inReceivesReflections) { setFlag(flag: QSSGRenderableObjectFlag::ReceivesReflections, on: inReceivesReflections); }
92 bool receivesReflections() const { return this->operator&(other: QSSGRenderableObjectFlag::ReceivesReflections); }
93
94 void setCastsReflections(bool inCastsReflections) { setFlag(flag: QSSGRenderableObjectFlag::CastsReflections, on: inCastsReflections); }
95 bool castsReflections() const { return this->operator&(other: QSSGRenderableObjectFlag::CastsReflections); }
96
97 void setUsedInBakedLighting(bool inUsedInBakedLighting) { setFlag(flag: QSSGRenderableObjectFlag::UsedInBakedLighting, on: inUsedInBakedLighting); }
98 bool usedInBakedLighting() const { return this->operator&(other: QSSGRenderableObjectFlag::UsedInBakedLighting); }
99
100 void setRendersWithLightmap(bool inRendersWithLightmap) { setFlag(flag: QSSGRenderableObjectFlag::RendersWithLightmap, on: inRendersWithLightmap); }
101 bool rendersWithLightmap() const { return this->operator&(other: QSSGRenderableObjectFlag::RendersWithLightmap); }
102
103 void setHasAttributePosition(bool b) { setFlag(flag: QSSGRenderableObjectFlag::HasAttributePosition, on: b); }
104 bool hasAttributePosition() const { return this->operator&(other: QSSGRenderableObjectFlag::HasAttributePosition); }
105
106 void setHasAttributeNormal(bool b) { setFlag(flag: QSSGRenderableObjectFlag::HasAttributeNormal, on: b); }
107 bool hasAttributeNormal() const { return this->operator&(other: QSSGRenderableObjectFlag::HasAttributeNormal); }
108
109 void setHasAttributeTexCoord0(bool b) { setFlag(flag: QSSGRenderableObjectFlag::HasAttributeTexCoord0, on: b); }
110 bool hasAttributeTexCoord0() const { return this->operator&(other: QSSGRenderableObjectFlag::HasAttributeTexCoord0); }
111
112 void setHasAttributeTexCoord1(bool b) { setFlag(flag: QSSGRenderableObjectFlag::HasAttributeTexCoord1, on: b); }
113 bool hasAttributeTexCoord1() const { return this->operator&(other: QSSGRenderableObjectFlag::HasAttributeTexCoord1); }
114
115 void setHasAttributeTexCoordLightmap(bool b) { setFlag(flag: QSSGRenderableObjectFlag::HasAttributeTexCoordLightmap, on: b); }
116 bool hasAttributeTexCoordLightmap() const { return this->operator&(other: QSSGRenderableObjectFlag::HasAttributeTexCoordLightmap); }
117
118 void setHasAttributeTangent(bool b) { setFlag(flag: QSSGRenderableObjectFlag::HasAttributeTangent, on: b); }
119 bool hasAttributeTangent() const { return this->operator&(other: QSSGRenderableObjectFlag::HasAttributeTangent); }
120
121 void setHasAttributeBinormal(bool b) { setFlag(flag: QSSGRenderableObjectFlag::HasAttributeBinormal, on: b); }
122 bool hasAttributeBinormal() const { return this->operator&(other: QSSGRenderableObjectFlag::HasAttributeBinormal); }
123
124 void setHasAttributeColor(bool b) { setFlag(flag: QSSGRenderableObjectFlag::HasAttributeColor, on: b); }
125 bool hasAttributeColor() const { return this->operator&(other: QSSGRenderableObjectFlag::HasAttributeColor); }
126
127 void setHasAttributeJointAndWeight(bool b) { setFlag(flag: QSSGRenderableObjectFlag::HasAttributeJointAndWeight, on: b);
128 }
129 bool hasAttributeJointAndWeight() const { return this->operator&(other: QSSGRenderableObjectFlag::HasAttributeJointAndWeight); }
130
131 void setHasAttributeMorphTarget(bool b) { setFlag(flag: QSSGRenderableObjectFlag::HasAttributeMorphTarget, on: b);
132 }
133 bool hasAttributeMorphTarget() const { return this->operator&(other: QSSGRenderableObjectFlag::HasAttributeMorphTarget); }
134
135 void setPointsTopology(bool v)
136 {
137 setFlag(flag: QSSGRenderableObjectFlag::IsPointsTopology, on: v);
138 }
139 bool isPointsTopology() const
140 {
141 return this->operator&(other: QSSGRenderableObjectFlag::IsPointsTopology);
142 }
143 void setRequiresScreenTexture(bool v)
144 {
145 setFlag(flag: QSSGRenderableObjectFlag::RequiresScreenTexture, on: v);
146 }
147 bool requiresScreenTexture() const {
148 return this->operator&(other: QSSGRenderableObjectFlag::RequiresScreenTexture);
149 }
150};
151
152struct QSSGShaderLight
153{
154 QSSGRenderLight *light = nullptr;
155 bool shadows = false;
156 QVector3D direction;
157
158 inline bool operator < (const QSSGShaderLight &o) const
159 {
160 // sort by light type
161 if (light->type < o.light->type)
162 return true;
163 // then shadow lights first
164 if (shadows > o.shadows)
165 return true;
166 return false;
167 }
168};
169
170struct QSSGShaderReflectionProbe
171{
172 QVector3D probeCubeMapCenter;
173 QVector3D probeBoxMax;
174 QVector3D probeBoxMin;
175 bool enabled = false;
176 int parallaxCorrection = 0;
177};
178
179// Having this as a QVLA is beneficial mainly because QVector would need to
180// detach somewhere in QSSGLayerRenderPreparationData::prepareForRender so the
181// implicit sharing's benefits do not outweigh the cost of allocations in this case.
182typedef QVarLengthArray<QSSGShaderLight, 16> QSSGShaderLightList;
183using QSSGShaderLightListView = QSSGDataView<QSSGShaderLight>;
184
185struct QSSGRenderableNodeEntry
186{
187 enum Overridden : quint16
188 {
189 Original = 0,
190 Disabled = 0x1,
191 GlobalTransform = 0x2,
192 Materials = 0x4,
193 GlobalOpacity = 0x8,
194 };
195
196 QSSGRenderNode *node = nullptr;
197 mutable QSSGShaderLightListView lights;
198 mutable quint16 overridden { Original };
199
200 // FIXME: This is just for the extension API and
201 // should be removed in the future.
202 struct ExtensionOverrides
203 {
204 QMatrix4x4 globalTransform;
205 QVector<QSSGRenderGraphObject *> materials;
206 float globalOpacity { 1.0f };
207 } mutable extOverrides;
208
209 bool isNull() const { return (node == nullptr); }
210 QSSGRenderableNodeEntry() = default;
211 QSSGRenderableNodeEntry(QSSGRenderNode &inNode) : node(&inNode) {}
212 QSSGRenderableNodeEntry(QSSGRenderNode *inNode) : node(inNode) {}
213};
214
215// Used for sorting
216struct QSSGRenderableObjectHandle
217{
218 QSSGRenderableObjectHandle() = default;
219 QSSGRenderableObjectHandle(QSSGRenderableObject *o, float camDistSq)
220 : obj(o)
221 , cameraDistanceSq(camDistSq)
222 {}
223 QSSGRenderableObject *obj = nullptr;
224 float cameraDistanceSq = 0.0f;
225};
226Q_DECLARE_TYPEINFO(QSSGRenderableObjectHandle, Q_PRIMITIVE_TYPE);
227
228using QSSGRenderableObjectList = QVector<QSSGRenderableObjectHandle>;
229
230class QSSGRenderableObject
231{
232 Q_DISABLE_COPY_MOVE(QSSGRenderableObject)
233public:
234 enum class Type : quint8
235 {
236 DefaultMaterialMeshSubset,
237 CustomMaterialMeshSubset,
238 Particles
239 };
240
241 // Variables used for picking
242 const QSSGBounds3 &bounds;
243 QSSGBounds3 globalBounds;
244
245 // Used for shadow map bounds when model has instancing
246 QSSGBounds3 globalBoundsInstancing;
247
248 QSSGRenderableObjectFlags renderableFlags;
249 // For rough sorting for transparency and for depth
250 QVector3D worldCenterPoint;
251 float depthBiasSq; // Squared as our sorting is based on the square distance!
252 float camdistSq = 0.0f;
253 QSSGDepthDrawMode depthWriteMode = QSSGDepthDrawMode::OpaqueOnly;
254 const Type type;
255 float instancingLodMin = -1;
256 float instancingLodMax = -1;
257
258 QSSGRenderableObject(Type ty,
259 QSSGRenderableObjectFlags inFlags,
260 const QVector3D &inWorldCenterPt,
261 const QSSGBounds3 &inBounds,
262 float inDepthBias,
263 float inMinThreshold = -1,
264 float inMaxThreshold = -1)
265
266 : bounds(inBounds)
267 , globalBounds(inBounds)
268 , renderableFlags(inFlags)
269 , worldCenterPoint(inWorldCenterPt)
270 , depthBiasSq(inDepthBias)
271 , type(ty)
272 , instancingLodMin(inMinThreshold)
273 , instancingLodMax(inMaxThreshold)
274 {
275 }
276};
277
278Q_STATIC_ASSERT(std::is_trivially_destructible<QSSGRenderableObject>::value);
279
280struct QSSGRenderCameraData
281{
282 QMatrix4x4 viewProjection;
283 std::optional<QSSGClippingFrustum> clippingFrustum;
284 QVector3D direction { 0.0f, 0.0f, -1.0f };
285 QVector3D position;
286};
287
288using QSSGRenderCameraList = QVarLengthArray<QSSGRenderCamera *, 2>;
289using QSSGRenderCameraDataList = QVarLengthArray<QSSGRenderCameraData, 2>;
290using QSSGRenderMvpArray = std::array<QMatrix4x4, 2>; // cannot be dynamic due to QSSGModelContext, must stick with 2 for now
291
292class QSSGSubsetRenderable;
293
294// Different subsets from the same model will get the same
295// model context so we can generate the MVP and normal matrix once
296// and only once per subset.
297class Q_AUTOTEST_EXPORT QSSGModelContext
298{
299 Q_DISABLE_COPY_MOVE(QSSGModelContext)
300public:
301 QSSGModelContext(const QSSGRenderModel &inModel,
302 const QMatrix4x4 &globalTransform,
303 const QMatrix3x3 &inNormalMatrix,
304 const QSSGRenderMvpArray &inModelViewProjections);
305
306 const QSSGRenderModel &model;
307 const QMatrix4x4 globalTransform;
308 const QMatrix3x3 normalMatrix;
309 QSSGRenderMvpArray modelViewProjections;
310 QSSGDataRef<QSSGSubsetRenderable> subsets;
311};
312
313Q_STATIC_ASSERT(std::is_trivially_destructible<QSSGModelContext>::value);
314
315class QSSGRenderer;
316class QSSGLayerRenderData;
317struct QSSGShadowMapEntry;
318
319class Q_AUTOTEST_EXPORT QSSGSubsetRenderable : public QSSGRenderableObject
320{
321 Q_DISABLE_COPY_MOVE(QSSGSubsetRenderable)
322public:
323 int reflectionProbeIndex = -1;
324 float distanceFromReflectionProbe;
325 quint32 subsetLevelOfDetail = 0;
326 QSSGShaderReflectionProbe reflectionProbe;
327 QSSGRenderer *renderer = nullptr;
328 const QSSGModelContext &modelContext;
329 const QSSGRenderSubset &subset;
330 QRhiBuffer *instanceBuffer = nullptr;
331 float opacity;
332 const QSSGRenderGraphObject &material;
333 QSSGRenderableImage *firstImage;
334 QSSGShaderDefaultMaterialKey shaderDescription;
335 const QSSGShaderLightListView &lights;
336
337 struct {
338 // Transient (due to the subsetRenderable being allocated using a
339 // per-frame allocator on every frame), not owned refs from the
340 // rhi-prepare step, used by the rhi-render step.
341 struct {
342 QRhiGraphicsPipeline *pipeline = nullptr;
343 QRhiShaderResourceBindings *srb = nullptr;
344 } mainPass;
345 struct {
346 QRhiGraphicsPipeline *pipeline = nullptr;
347 QRhiShaderResourceBindings *srb = nullptr;
348 } depthPrePass;
349 struct {
350 QRhiGraphicsPipeline *pipeline = nullptr;
351 QRhiShaderResourceBindings *srb[6] = {};
352 } shadowPass;
353 struct {
354 QRhiGraphicsPipeline *pipeline = nullptr;
355 QRhiShaderResourceBindings *srb[6] = {};
356 } reflectionPass;
357 } rhiRenderData;
358
359 QSSGSubsetRenderable(Type type,
360 QSSGRenderableObjectFlags inFlags,
361 const QVector3D &inWorldCenterPt,
362 QSSGRenderer *rendr,
363 const QSSGRenderSubset &inSubset,
364 const QSSGModelContext &inModelContext,
365 float inOpacity,
366 quint32 inSubsetLevelOfDetail,
367 const QSSGRenderGraphObject &mat,
368 QSSGRenderableImage *inFirstImage,
369 QSSGShaderDefaultMaterialKey inShaderKey,
370 const QSSGShaderLightListView &inLights,
371 bool anyLightHasShadows);
372
373 [[nodiscard]] const QSSGRenderGraphObject &getMaterial() const { return material; }
374};
375
376Q_STATIC_ASSERT(std::is_trivially_destructible<QSSGSubsetRenderable>::value);
377
378/**
379 * A renderable that corresponds to a particles.
380 */
381class Q_AUTOTEST_EXPORT QSSGParticlesRenderable : public QSSGRenderableObject
382{
383 Q_DISABLE_COPY_MOVE(QSSGParticlesRenderable)
384public:
385 QSSGRenderer *renderer = nullptr;
386 const QSSGRenderParticles &particles;
387 QSSGRenderableImage *firstImage;
388 QSSGRenderableImage *colorTable;
389 const QSSGShaderLightListView &lights;
390 QMatrix4x4 globalTransform;
391 float opacity;
392
393 struct {
394 // Transient (due to the subsetRenderable being allocated using a
395 // per-frame allocator on every frame), not owned refs from the
396 // rhi-prepare step, used by the rhi-render step.
397 struct {
398 QRhiGraphicsPipeline *pipeline = nullptr;
399 QRhiShaderResourceBindings *srb = nullptr;
400 } mainPass;
401 struct {
402 QRhiGraphicsPipeline *pipeline = nullptr;
403 QRhiShaderResourceBindings *srb = nullptr;
404 } depthPrePass;
405 struct {
406 QRhiGraphicsPipeline *pipeline = nullptr;
407 QRhiShaderResourceBindings *srb[6] = {};
408 } shadowPass;
409 struct {
410 QRhiGraphicsPipeline *pipeline = nullptr;
411 QRhiShaderResourceBindings *srb[6] = {};
412 } reflectionPass;
413 } rhiRenderData;
414
415 QSSGParticlesRenderable(QSSGRenderableObjectFlags inFlags,
416 const QVector3D &inWorldCenterPt,
417 QSSGRenderer *rendr,
418 const QMatrix4x4 &inGlobalTransform,
419 const QSSGRenderParticles &inParticles,
420 QSSGRenderableImage *inFirstImage,
421 QSSGRenderableImage *inColorTable,
422 const QSSGShaderLightListView &inLights,
423 float inOpacity);
424};
425
426Q_STATIC_ASSERT(std::is_trivially_destructible<QSSGParticlesRenderable>::value);
427
428
429using QSSGModelsView = QSSGDataView<QSSGRenderModel *>;
430using QSSGParticlesView = QSSGDataView<QSSGRenderParticles *>;
431using QSSGItem2DsView = QSSGDataView<QSSGRenderItem2D *>;
432using QSSGCamerasView = QSSGDataView<QSSGRenderCamera *>;
433using QSSGLightsView = QSSGDataView<QSSGRenderLight *>;
434using QSSGReflectionProbesView = QSSGDataView<QSSGRenderReflectionProbe *>;
435
436QT_END_NAMESPACE
437
438#endif
439

source code of qtquick3d/src/runtimerender/rendererimpl/qssgrenderableobjects_p.h