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
qssgrenderhelpers.cpp
Go to the documentation of this file.
1// Copyright (C) 2023 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
3
6
7#include <QtQuick3DRuntimeRender/private/qssgrenderer_p.h>
8#include <QtQuick3DRuntimeRender/private/qssgrenderhelpers_p.h>
9#include <QtQuick3DRuntimeRender/private/qssglayerrenderdata_p.h>
10
11#include "graphobjects/qssgrendermodel_p.h"
12#include <QtQuick3DRuntimeRender/private/qssgrendercamera_p.h>
13
14#include <QtQuick3DUtils/private/qssgassert_p.h>
15
17
18 /*!
19 \class QSSGRenderHelpers
20 \inmodule QtQuick3D
21 \since 6.7
22
23 \brief Class containing helper functions for setting up and render QtQuick3D renderables.
24*/
25
26/*!
27 \typedef QSSGPrepContextId
28 \relates QtQuick3D
29
30 Handle to a preparation context. Setting up a preparation context is the first
31 step needed before renderables can be created and rendered.
32
33 \sa QSSGRenderHelpers::prepareForRender()
34*/
35
36/*!
37 \typedef QSSGRenderablesId
38 \brief Handle to a set of renderables.
39 \relates QtQuick3D
40
41 Handle to a set of renderables created for one or more node(s). This \c id can be used
42 to for example modify the renderables created for a specific model.
43*/
44
45/*!
46 \typedef QSSGPrepResultId
47 \relates QtQuick3D
48
49 Handle to a preparation result.
50
51 Once the \l {QSSGRenderHelpers::createRenderables}{renderables} for a frame are updated and ready
52 to be translated into rendering code by the engine, the \l {QSSGRenderHelpers::createRenderables}{renderables}
53 and the \l {QSSGRenderHelpers::prepareForRender()}{preparation context} can be \l {QSSGRenderHelpers::commit()}{committed}.
54 If the commit succeeds, the returned preparation result can be used to \l {QSSGRenderHelpers::prepareRenderables()}{prepare}
55 and \l {QSSGRenderHelpers::renderRenderables}{record} the rendering for the frame.
56*/
57
58/*!
59 \enum QSSGRenderHelpers::CreateFlag
60
61 \value None The default value. Renderables are created only for the nodes specified.
62 \value Recurse Renderables are created for each node and their children.
63 \value Steal Renderables are taken from the engine and won't be rendered by QtQuick3D.
64
65 \note Calling \l QSSGRenderHelpers::createRenderables() without the {QSSGRenderHelpers::CreateFlag::Steal}{Steal}
66 flag set means nodes are duplicated and QtQuick3D will render its copy of the nodes as normal.
67*/
68
69/*!
70 Takes a list of node ids and create renderables that can be further processed by the renderer.
71 If there are no nodes, or no renderable nodes in the list, the returned id will be invalid.
72
73 By default the function does not recurse down and included children of the \a nodes in the list.
74 Enabling recursion can be achieved by passing in the \l{CreateFlag::}{Recurse} flag in
75 the \a flags argument.
76
77 \return an id to the created renderables.
78
79 \a frameData, \a prepId
80
81 \sa CreateFlags, prepareForRender()
82 */
83QSSGRenderablesId QSSGRenderHelpers::createRenderables(const QSSGFrameData &frameData,
84 QSSGPrepContextId prepId,
85 const QSSGNodeIdList &nodes,
86 CreateFlags flags)
87{
88 QSSGRenderablesId rid { QSSGRenderablesId::Invalid };
89 if (nodes.size() > 0) {
90 auto *ctx = frameData.contextInterface();
91 auto *layer = QSSGLayerRenderData::getCurrent(*ctx->renderer());
92 QSSG_ASSERT_X(layer, "No active layer for renderer!", return rid);
93 return layer->createRenderables(prepId, nodes, flags);
94 }
95
96 return rid;
97}
98
99/*!
100 prepareForRender() creates a context for collecting and storing information about the render-data
101 associated with this render extension.
102
103 If the same nodes are to be rendered more then once but with different properties, for example
104 a different material or camera, then a new context will be needed. To create several contexts for
105 one extension the \a slot argument can be used. The default context is created in slot \b 0.
106
107 \return an id to the prep context.
108
109 \a frameData, \a ext, \a cameraId
110
111 \sa commit()
112 */
113
114QSSGPrepContextId QSSGRenderHelpers::prepareForRender(const QSSGFrameData &frameData,
115 const QSSGRenderExtension &ext,
116 QSSGCameraId cameraId,
117 quint32 slot)
118{
119 auto *cn = QSSGRenderGraphObjectUtils::getCamera<QSSGRenderCamera>(cameraId);
120 QSSG_ASSERT_X(cn && QSSGRenderGraphObject::isCamera(cn->type), "CameraId is not a camera!", return QSSGPrepContextId::Invalid);
121 auto *ctx = frameData.contextInterface();
122 auto *layer = QSSGLayerRenderData::getCurrent(*ctx->renderer());
123 QSSG_ASSERT_X(layer, "No active layer for renderer!", return QSSGPrepContextId::Invalid);
124 return layer->getOrCreateExtensionContext(ext, cn, slot);
125}
126
127/*!
128 Once the required changes have been done to the renderables, the data can marked as ready for
129 the renderer.
130
131 \return an id to the preparation result.
132
133 \a frameData, \a prepId, \a renderablesId, \a lodThreshold
134
135 \sa prepareRenderables(), renderRenderables()
136 */
137QSSGPrepResultId QSSGRenderHelpers::commit(const QSSGFrameData &frameData,
138 QSSGPrepContextId prepId,
139 QSSGRenderablesId renderablesId,
140 float lodThreshold)
141{
142 auto *ctx = frameData.contextInterface();
143 auto *layer = QSSGLayerRenderData::getCurrent(*ctx->renderer());
144 QSSG_ASSERT_X(layer, "No active layer for renderer!", return QSSGPrepResultId::Invalid);
145 return layer->prepareModelsForRender(*ctx, prepId, renderablesId, lodThreshold);
146}
147
148/*!
149 Prepare the draw call data needed for the renderables before calling \l {renderRenderables}.
150
151 \return an id to the preparation result.
152
153 \a frameData, \a renderPassDescriptor, \a ps, \a prepId, \a filter
154
155 \sa renderRenderables()
156 */
157void QSSGRenderHelpers::prepareRenderables(const QSSGFrameData &frameData,
158 QSSGPrepResultId prepId,
159 QRhiRenderPassDescriptor *renderPassDescriptor,
160 QSSGRhiGraphicsPipelineState &ps,
161 QSSGRenderablesFilters filter)
162{
163 auto *ctx = frameData.contextInterface();
164 auto *layer = QSSGLayerRenderData::getCurrent(*ctx->renderer());
165 QSSG_ASSERT_X(layer, "No active layer for renderer!", return);
166 layer->prepareRenderables(*ctx, prepId, renderPassDescriptor, ps, filter);
167}
168
169/*!
170 Render the renderables.
171
172 \a frameData, \a prepId
173
174 \sa prepareRenderables()
175 */
176void QSSGRenderHelpers::renderRenderables(const QSSGFrameData &frameData,
177 QSSGPrepResultId prepId)
178{
179 QSSGRenderContextInterface *ctx = frameData.contextInterface();
180 auto *layer = QSSGLayerRenderData::getCurrent(*ctx->renderer());
181 QSSG_ASSERT_X(layer, "No active layer for renderer!", return);
182 layer->renderRenderables(*ctx, prepId);
183}
184
185QSSGRenderHelpers::QSSGRenderHelpers()
186{
187
188}
189
190 /*!
191 \class QSSGModelHelpers
192 \inmodule QtQuick3D
193 \since 6.7
194
195 \brief Class containing helper functions for modifying and setting data for model renderables.
196*/
197
198/*!
199 Sets the \a materials to be used on \a model.
200
201 \note As with the \l {QtQuick3D::Model::materials}{materials} on the \l {QtQuick3D::Model}{model} item,
202 materials are applied in the same manner.
203
204 The sub-mesh uses a material from the \l{materials} list, corresponding to its index. If the number
205 of materials is less than the sub-meshes, the last material in the list is used for subsequent
206 sub-meshes.
207
208 \a frameData \a renderablesId
209
210 \sa QSSGRenderHelpers::createRenderables()
211 */
212void QSSGModelHelpers::setModelMaterials(const QSSGFrameData &frameData,
213 QSSGRenderablesId renderablesId,
214 QSSGNodeId model,
215 MaterialList materials)
216{
217 auto *ctx = frameData.contextInterface();
218 auto *layer = QSSGLayerRenderData::getCurrent(*ctx->renderer());
219 QSSG_ASSERT_X(layer, "No active layer for renderer!", return);
220 auto *renderModel = QSSGRenderGraphObjectUtils::getNode<QSSGRenderModel>(model);
221 QSSG_ASSERT_X(renderModel && renderModel->type == QSSGRenderGraphObject::Type::Model, "Invalid model-id!", return);
222 layer->setModelMaterials(renderablesId, *renderModel, materials);
223}
224
225/*!
226 Convenience function to apply \a materials to all models in the renderablesId set.
227
228 \a frameData, \a renderablesId
229
230 \sa QSSGRenderHelpers::createRenderables()
231 */
232void QSSGModelHelpers::setModelMaterials(const QSSGFrameData &frameData,
233 QSSGRenderablesId renderablesId,
234 MaterialList materials)
235{
236 auto *ctx = frameData.contextInterface();
237 auto *layer = QSSGLayerRenderData::getCurrent(*ctx->renderer());
238 QSSG_ASSERT_X(layer, "No active layer for renderer!", return);
239 layer->setModelMaterials(renderablesId, materials);
240}
241
242/*!
243 \return Returns the global transform for the \a model in context of the \a prepId. By default the prep context argument is
244 QSSGPrepContextId::Uninitialized which returns the model's original global transform.
245
246 \a frameData
247
248 \sa QSSGRenderHelpers::createRenderables()
249*/
250QMatrix4x4 QSSGModelHelpers::getGlobalTransform(const QSSGFrameData &frameData,
251 QSSGNodeId model,
252 QSSGPrepContextId prepId)
253{
254 auto *ctx = frameData.contextInterface();
255 auto *layer = QSSGLayerRenderData::getCurrent(*ctx->renderer());
256 QSSG_ASSERT_X(layer, "No active layer for renderer!", return {});
257 auto *renderModel = QSSGRenderGraphObjectUtils::getNode<QSSGRenderModel>(model);
258 QSSG_ASSERT_X(renderModel && renderModel->type == QSSGRenderGraphObject::Type::Model, "Invalid model-id!", return {});
259 return (prepId != QSSGPrepContextId::Invalid) ? layer->getGlobalTransform(prepId, *renderModel)
260 : layer->getGlobalTransform(*renderModel);
261}
262
263/*!
264 \return Returns the local transform for the \a model.
265
266 \a frameData
267*/
268QMatrix4x4 QSSGModelHelpers::getLocalTransform(const QSSGFrameData &frameData, QSSGNodeId model)
269{
270 Q_UNUSED(frameData);
271 auto *renderModel = QSSGRenderGraphObjectUtils::getNode<QSSGRenderModel>(model);
272 QSSG_ASSERT_X(renderModel && renderModel->type == QSSGRenderGraphObject::Type::Model, "Invalid model-id!", return {});
273 return renderModel->localTransform;
274}
275
276/*!
277 \return Returns the global opacity for the \a model.
278
279 \a frameData
280*/
281float QSSGModelHelpers::getGlobalOpacity(const QSSGFrameData &frameData, QSSGNodeId model)
282{
283 auto *ctx = frameData.contextInterface();
284 auto *layer = QSSGLayerRenderData::getCurrent(*ctx->renderer());
285 QSSG_ASSERT_X(layer, "No active layer for renderer!", return {});
286 auto *renderModel = QSSGRenderGraphObjectUtils::getNode<QSSGRenderModel>(model);
287 QSSG_ASSERT_X(renderModel && renderModel->type == QSSGRenderGraphObject::Type::Model, "Invalid model-id!", return {});
288 return layer->getGlobalOpacity(*renderModel);
289}
290
291/*!
292 \return Returns the global opacity for the \a model in context of the \a prepId. By default the prep context argument is
293 QSSGPrepContextId::Uninitialized which returns the model's original global opacity.
294
295 \a frameData
296
297 \sa QSSGRenderHelpers::createRenderables()
298*/
299float QSSGModelHelpers::getGlobalOpacity(const QSSGFrameData &frameData, QSSGNodeId model, QSSGPrepContextId prepId = QSSGPrepContextId::Invalid)
300{
301 auto *ctx = frameData.contextInterface();
302 auto *layer = QSSGLayerRenderData::getCurrent(*ctx->renderer());
303 QSSG_ASSERT_X(layer, "No active layer for renderer!", return {});
304 auto *renderModel = QSSGRenderGraphObjectUtils::getNode<QSSGRenderModel>(model);
305 QSSG_ASSERT_X(renderModel && renderModel->type == QSSGRenderGraphObject::Type::Model, "Invalid model-id!", return {});
306 return (prepId != QSSGPrepContextId::Invalid) ? layer->getGlobalOpacity(prepId, *renderModel) : layer->getGlobalOpacity(*renderModel);
307}
308
309/*!
310 \return Returns the local opacity for the \a model.
311
312 \a frameData
313*/
314float QSSGModelHelpers::getLocalOpacity(const QSSGFrameData &frameData, QSSGNodeId model)
315{
316 Q_UNUSED(frameData);
317 auto *renderModel = QSSGRenderGraphObjectUtils::getNode<QSSGRenderModel>(model);
318 QSSG_ASSERT_X(renderModel && renderModel->type == QSSGRenderGraphObject::Type::Model, "Invalid model-id!", return {});
319 return renderModel->localOpacity;
320}
321
322/*!
323 Sets the global transform for \a model in the context of the \a renderablesId.
324
325 \a frameData, \a transform
326
327 \sa QSSGRenderHelpers::createRenderables()
328 */
329void QSSGModelHelpers::setGlobalTransform(const QSSGFrameData &frameData,
330 QSSGRenderablesId renderablesId,
331 QSSGNodeId model,
332 const QMatrix4x4 &transform)
333{
334 auto *ctx = frameData.contextInterface();
335 auto *layer = QSSGLayerRenderData::getCurrent(*ctx->renderer());
336 QSSG_ASSERT_X(layer, "No active layer for renderer!", return);
337 auto *node = QSSGRenderGraphObjectUtils::getNode(model);
338 QSSG_ASSERT_X(node && node->type == QSSGRenderGraphObject::Type::Model, "Invalid model-id!", return);
339 const auto &renderModel = static_cast<const QSSGRenderModel &>(*node);
340 layer->setGlobalTransform(renderablesId, renderModel, transform);
341}
342
343/*!
344 Sets the global opacity for \a model in the context of the \a renderablesId.
345
346 \a frameData, \a opacity
347
348 \sa QSSGRenderHelpers::createRenderables()
349 */
350void QSSGModelHelpers::setGlobalOpacity(const QSSGFrameData &frameData, QSSGRenderablesId renderablesId, QSSGNodeId model, float opacity)
351{
352 auto *ctx = frameData.contextInterface();
353 auto *layer = QSSGLayerRenderData::getCurrent(*ctx->renderer());
354 QSSG_ASSERT_X(layer, "No active layer for renderer!", return);
355 auto *node = QSSGRenderGraphObjectUtils::getNode(model);
356 QSSG_ASSERT_X(node && node->type == QSSGRenderGraphObject::Type::Model, "Invalid model-id!", return);
357 const auto &renderModel = static_cast<const QSSGRenderModel &>(*node);
358 layer->setGlobalOpacity(renderablesId, renderModel, opacity);
359}
360
361 /*!
362 \class QSSGCameraHelpers
363 \inmodule QtQuick3D
364 \since 6.7
365
366 \brief Class containing helper functions for getting camera data used for rendering.
367*/
368
369/*!
370 Get the projection matrix for \a cameraId. An optional transform argument can be given to be used
371 instead of the cameras global transform when calculating the projection matrix.
372
373 \return projection matrix for \a cameraId
374
375 \a globalTransform
376
377 \sa QSSGRenderHelpers::createRenderables()
378 */
379QMatrix4x4 QSSGCameraHelpers::getViewProjectionMatrix(const QSSGCameraId cameraId,
380 const QMatrix4x4 *globalTransform)
381{
382 auto *renderCamera = QSSGRenderGraphObjectUtils::getCamera<QSSGRenderCamera>(cameraId);
383 QSSG_ASSERT(renderCamera && QSSGRenderGraphObject::isCamera(renderCamera->type), return {});
384
385 QMatrix4x4 mat44{Qt::Uninitialized};
386 const auto &projection = renderCamera->projection;
387 const auto &transform = (globalTransform != 0) ? *globalTransform : renderCamera->localTransform;
388 QSSGRenderCamera::calculateViewProjectionMatrix(transform, projection, mat44);
389 return mat44;
390}
391
392 /*!
393 \class QSSGRenderExtensionHelpers
394 \inmodule QtQuick3D
395 \since 6.7
396
397 \brief Class containing helper functions for the extensions.
398*/
399
400/*!
401 Register a render result, in form of a texture, for this \a extension. Once a texture is registered,
402 the extension can be uses as a {QtQuick3D::Texture::textureProvider}{texture provider} in QML.
403
404 \note To ensure that the \a texture is available for renderables, for example to be used by a {QtQuick3D::Texture} item,
405 textures should be registered during the \l QSSGRenderExtension::prepareData call of the extension.
406
407 \note Calling this function with a new texture will any previously registered texture.
408 \note A texture can be unregistered by registering a nullptr for this extension.
409
410 \a frameData
411
412 \sa {QtQuick3D::Texture::textureProvider}{textureProvider}
413 */
414void QSSGRenderExtensionHelpers::registerRenderResult(const QSSGFrameData &frameData,
415 QSSGExtensionId extension,
416 QRhiTexture *texture)
417{
418 if (auto *ext = QSSGRenderGraphObjectUtils::getExtension<QSSGRenderExtension>(extension)) {
419 const QSSGRenderContextInterface *ctx = frameData.contextInterface();
420 ctx->bufferManager()->registerExtensionResult(*ext, texture);
421 }
422}
423
424QT_END_NAMESPACE