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

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