1// Copyright (C) 2023 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
3
4#include "qssgrendercontextcore.h"
5#include "qssgrenderhelpers.h"
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
16QT_BEGIN_NAMESPACE
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 NodeList &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(renderer: *ctx->renderer());
92 QSSG_ASSERT_X(layer, "No active layer for renderer!", return rid);
93 return layer->createRenderables(prepId, nodes, createFlags: 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(renderer: *ctx->renderer());
123 QSSG_ASSERT_X(layer, "No active layer for renderer!", return QSSGPrepContextId::Invalid);
124 return layer->getOrCreateExtensionContext(ext, camera: 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(renderer: *ctx->renderer());
144 QSSG_ASSERT_X(layer, "No active layer for renderer!", return QSSGPrepResultId::Invalid);
145 return layer->prepareModelsForRender(contextInterface&: *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(renderer: *ctx->renderer());
165 QSSG_ASSERT_X(layer, "No active layer for renderer!", return);
166 layer->prepareRenderables(ctx&: *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(renderer: *ctx->renderer());
181 QSSG_ASSERT_X(layer, "No active layer for renderer!", return);
182 layer->renderRenderables(ctx&: *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(renderer: *ctx->renderer());
219 QSSG_ASSERT_X(layer, "No active layer for renderer!", return);
220 auto *renderModel = QSSGRenderGraphObjectUtils::getNode<QSSGRenderModel>(nodeId: model);
221 QSSG_ASSERT_X(renderModel && renderModel->type == QSSGRenderGraphObject::Type::Model, "Invalid model-id!", return);
222 layer->setModelMaterials(renderablesId, model: *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(renderer: *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(renderer: *ctx->renderer());
256 QSSG_ASSERT_X(layer, "No active layer for renderer!", return {});
257 auto *renderModel = QSSGRenderGraphObjectUtils::getNode<QSSGRenderModel>(nodeId: model);
258 QSSG_ASSERT_X(renderModel && renderModel->type == QSSGRenderGraphObject::Type::Model, "Invalid model-id!", return {});
259 return (prepId != QSSGPrepContextId::Invalid) ? layer->getGlobalTransform(prepId, model: *renderModel)
260 : renderModel->globalTransform;
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>(nodeId: 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 Q_UNUSED(frameData);
284 auto *renderModel = QSSGRenderGraphObjectUtils::getNode<QSSGRenderModel>(nodeId: model);
285 QSSG_ASSERT_X(renderModel && renderModel->type == QSSGRenderGraphObject::Type::Model, "Invalid model-id!", return {});
286 return renderModel->globalOpacity;
287}
288
289/*!
290 \return Returns the global opacity for the \a model in context of the \a prepId. By default the prep context argument is
291 QSSGPrepContextId::Uninitialized which returns the model's original global opacity.
292
293 \a frameData
294
295 \sa QSSGRenderHelpers::createRenderables()
296*/
297float QSSGModelHelpers::getGlobalOpacity(const QSSGFrameData &frameData, QSSGNodeId model, QSSGPrepContextId prepId = QSSGPrepContextId::Invalid)
298{
299 auto *ctx = frameData.contextInterface();
300 auto *layer = QSSGLayerRenderData::getCurrent(renderer: *ctx->renderer());
301 QSSG_ASSERT_X(layer, "No active layer for renderer!", return {});
302 auto *renderModel = QSSGRenderGraphObjectUtils::getNode<QSSGRenderModel>(nodeId: model);
303 QSSG_ASSERT_X(renderModel && renderModel->type == QSSGRenderGraphObject::Type::Model, "Invalid model-id!", return {});
304 return (prepId != QSSGPrepContextId::Invalid) ? layer->getGlobalOpacity(prepId, model: *renderModel)
305 : renderModel->globalOpacity;
306}
307
308/*!
309 \return Returns the local opacity for the \a model.
310
311 \a frameData
312*/
313float QSSGModelHelpers::getLocalOpacity(const QSSGFrameData &frameData, QSSGNodeId model)
314{
315 Q_UNUSED(frameData);
316 auto *renderModel = QSSGRenderGraphObjectUtils::getNode<QSSGRenderModel>(nodeId: model);
317 QSSG_ASSERT_X(renderModel && renderModel->type == QSSGRenderGraphObject::Type::Model, "Invalid model-id!", return {});
318 return renderModel->localOpacity;
319}
320
321/*!
322 Sets the global transform for \a model in the context of the \a renderablesId.
323
324 \a frameData, \a transform
325
326 \sa QSSGRenderHelpers::createRenderables()
327 */
328void QSSGModelHelpers::setGlobalTransform(const QSSGFrameData &frameData,
329 QSSGRenderablesId renderablesId,
330 QSSGNodeId model,
331 const QMatrix4x4 &transform)
332{
333 auto *ctx = frameData.contextInterface();
334 auto *layer = QSSGLayerRenderData::getCurrent(renderer: *ctx->renderer());
335 QSSG_ASSERT_X(layer, "No active layer for renderer!", return);
336 auto *node = QSSGRenderGraphObjectUtils::getNode(nodeId: model);
337 QSSG_ASSERT_X(node && node->type == QSSGRenderGraphObject::Type::Model, "Invalid model-id!", return);
338 const auto &renderModel = static_cast<const QSSGRenderModel &>(*node);
339 layer->setGlobalTransform(renderablesId, model: renderModel, mvp: transform);
340}
341
342/*!
343 Sets the global opacity for \a model in the context of the \a renderablesId.
344
345 \a frameData, \a opacity
346
347 \sa QSSGRenderHelpers::createRenderables()
348 */
349void QSSGModelHelpers::setGlobalOpacity(const QSSGFrameData &frameData, QSSGRenderablesId renderablesId, QSSGNodeId model, float opacity)
350{
351 auto *ctx = frameData.contextInterface();
352 auto *layer = QSSGLayerRenderData::getCurrent(renderer: *ctx->renderer());
353 QSSG_ASSERT_X(layer, "No active layer for renderer!", return);
354 auto *node = QSSGRenderGraphObjectUtils::getNode(nodeId: model);
355 QSSG_ASSERT_X(node && node->type == QSSGRenderGraphObject::Type::Model, "Invalid model-id!", return);
356 const auto &renderModel = static_cast<const QSSGRenderModel &>(*node);
357 layer->setGlobalOpacity(renderablesId, model: renderModel, opacity);
358}
359
360 /*!
361 \class QSSGCameraHelpers
362 \inmodule QtQuick3D
363 \since 6.7
364
365 \brief Class containing helper functions for getting camera data used for rendering.
366*/
367
368/*!
369 Get the projection matrix for \a cameraId. An optional transform argument can be given to be used
370 instead of the cameras global transform when calculating the projection matrix.
371
372 \return projection matrix for \a cameraId
373
374 \a globalTransform
375
376 \sa QSSGRenderHelpers::createRenderables()
377 */
378QMatrix4x4 QSSGCameraHelpers::getViewProjectionMatrix(const QSSGCameraId cameraId,
379 const QMatrix4x4 *globalTransform)
380{
381 auto *renderCamera = QSSGRenderGraphObjectUtils::getCamera<QSSGRenderCamera>(cameraId);
382 QSSG_ASSERT(renderCamera && QSSGRenderGraphObject::isCamera(renderCamera->type), return {});
383
384 QMatrix4x4 mat44{Qt::Uninitialized};
385 const auto &projection = renderCamera->projection;
386 const auto &transform = (globalTransform != 0) ? *globalTransform : renderCamera->globalTransform;
387 QSSGRenderCamera::calculateViewProjectionMatrix(globalTransform: transform, projection, outMatrix&: mat44);
388 return mat44;
389}
390
391 /*!
392 \class QSSGRenderExtensionHelpers
393 \inmodule QtQuick3D
394 \since 6.7
395
396 \brief Class containing helper functions for the extensions.
397*/
398
399/*!
400 Register a render result, in form of a texture, for this \a extension. Once a texture is registered,
401 the extension can be uses as a {QtQuick3D::Texture::textureProvider}{texture provider} in QML.
402
403 \note To ensure that the \a texture is available for renderables, for example to be used by a {QtQuick3D::Texture} item,
404 textures should be registered during the \l QSSGRenderExtension::prepareData call of the extension.
405
406 \note Calling this function with a new texture will any previously registered texture.
407 \note A texture can be unregistered by registering a nullptr for this extension.
408
409 \a frameData
410
411 \sa {QtQuick3D::Texture::textureProvider}{textureProvider}
412 */
413void QSSGRenderExtensionHelpers::registerRenderResult(const QSSGFrameData &frameData,
414 QSSGExtensionId extension,
415 QRhiTexture *texture)
416{
417 if (auto *ext = QSSGRenderGraphObjectUtils::getExtension<QSSGRenderExtension>(extensionId: extension)) {
418 const QSSGRenderContextInterface *ctx = frameData.contextInterface();
419 ctx->bufferManager()->registerExtensionResult(extensions: *ext, texture);
420 }
421}
422
423QT_END_NAMESPACE
424

Provided by KDAB

Privacy Policy
Learn to use CMake with our Intro Training
Find out more

source code of qtquick3d/src/runtimerender/extensionapi/qssgrenderhelpers.cpp