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

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