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
qssgshadermaterialadapter.cpp
Go to the documentation of this file.
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// Qt-Security score:significant reason:default
5
6
7/* clang-format off */
8
9#include <QtQuick3DRuntimeRender/private/qssgshadermaterialadapter_p.h>
11#include <QtQuick3DRuntimeRender/private/qssgrhicustommaterialsystem_p.h>
12
14
15QSSGShaderMaterialAdapter::~QSSGShaderMaterialAdapter() = default;
16
17QSSGShaderMaterialAdapter *QSSGShaderMaterialAdapter::create(const QSSGRenderGraphObject &materialNode)
18{
19 switch (materialNode.type) {
20 case QSSGRenderGraphObject::Type::DefaultMaterial:
21 case QSSGRenderGraphObject::Type::PrincipledMaterial:
22 case QSSGRenderGraphObject::Type::SpecularGlossyMaterial:
23 return new QSSGShaderDefaultMaterialAdapter(static_cast<const QSSGRenderDefaultMaterial &>(materialNode));
24
25 case QSSGRenderGraphObject::Type::CustomMaterial:
26 return new QSSGShaderCustomMaterialAdapter(static_cast<const QSSGRenderCustomMaterial &>(materialNode));
27
28 default:
29 break;
30 }
31
32 return nullptr;
33}
34
35bool QSSGShaderMaterialAdapter::isUnshaded()
36{
37 return false;
38}
39
40bool QSSGShaderMaterialAdapter::hasCustomShaderSnippet(QSSGShaderCache::ShaderType)
41{
42 return false;
43}
44
45QByteArray QSSGShaderMaterialAdapter::customShaderSnippet(QSSGShaderCache::ShaderType,
46 QSSGShaderLibraryManager &,
47 bool)
48{
49 return QByteArray();
50}
51
52bool QSSGShaderMaterialAdapter::hasCustomShaderFunction(QSSGShaderCache::ShaderType,
53 const QByteArray &,
54 QSSGShaderLibraryManager &)
55{
56 return false;
57}
58
59void QSSGShaderMaterialAdapter::setCustomPropertyUniforms(char *,
60 QSSGRhiShaderPipeline &,
61 const QSSGRenderContextInterface &)
62{
63}
64
65bool QSSGShaderMaterialAdapter::usesSharedVariables()
66{
67 return false;
68}
69
70
71
72QSSGShaderDefaultMaterialAdapter::QSSGShaderDefaultMaterialAdapter(const QSSGRenderDefaultMaterial &material)
73 : m_material(material)
74{
75}
76
77bool QSSGShaderDefaultMaterialAdapter::isPrincipled()
78{
79 return m_material.type == QSSGRenderGraphObject::Type::PrincipledMaterial;
80}
81
82bool QSSGShaderDefaultMaterialAdapter::isSpecularGlossy()
83{
84 return m_material.type == QSSGRenderGraphObject::Type::SpecularGlossyMaterial;
85}
86
87bool QSSGShaderDefaultMaterialAdapter::isMetalnessEnabled()
88{
89 return m_material.isMetalnessEnabled();
90}
91
92bool QSSGShaderDefaultMaterialAdapter::isSpecularEnabled()
93{
94 return m_material.isSpecularEnabled();
95}
96
97bool QSSGShaderDefaultMaterialAdapter::isVertexColorsEnabled()
98{
99 return m_material.isVertexColorsEnabled();
100}
101
102bool QSSGShaderDefaultMaterialAdapter::isVertexColorsMaskEnabled()
103{
104 return m_material.isVertexColorsMaskEnabled();
105}
106
107bool QSSGShaderDefaultMaterialAdapter::isInvertOpacityMapValue()
108{
109 return m_material.isInvertOpacityMapValue();
110}
111
112bool QSSGShaderDefaultMaterialAdapter::isBaseColorSingleChannelEnabled()
113{
114 return m_material.isBaseColorSingleChannelEnabled();
115}
116
117bool QSSGShaderDefaultMaterialAdapter::isSpecularAmountSingleChannelEnabled()
118{
119 return m_material.isSpecularAmountSingleChannelEnabled();
120}
121
122bool QSSGShaderDefaultMaterialAdapter::isEmissiveSingleChannelEnabled()
123{
124 return m_material.isEmissiveSingleChannelEnabled();
125}
126
127bool QSSGShaderDefaultMaterialAdapter::isClearcoatEnabled()
128{
129 return m_material.isClearcoatEnabled();
130}
131
132bool QSSGShaderDefaultMaterialAdapter::isSheenEnabled()
133{
134 return m_material.isSheenEnabled();
135}
136
137bool QSSGShaderDefaultMaterialAdapter::isAnisotropyEnabled()
138{
139 return m_material.isAnisotropyEnabled();
140}
141
142bool QSSGShaderDefaultMaterialAdapter::isIridescenceEnabled()
143{
144 return m_material.isIridescenceEnabled();
145}
146
147bool QSSGShaderDefaultMaterialAdapter::isDispersionEnabled()
148{
149 return m_material.isDispersionEnabled();
150}
151
152bool QSSGShaderDefaultMaterialAdapter::isTransmissionEnabled()
153{
154 return m_material.isTransmissionEnabled();
155}
156
157bool QSSGShaderDefaultMaterialAdapter::hasLighting()
158{
159 return m_material.hasLighting();
160}
161
162bool QSSGShaderDefaultMaterialAdapter::usesCustomSkinning()
163{
164 return false;
165}
166
167bool QSSGShaderDefaultMaterialAdapter::usesCustomMorphing()
168{
169 return false;
170}
171
172QSSGRenderDefaultMaterial::MaterialSpecularModel QSSGShaderDefaultMaterialAdapter::specularModel()
173{
174 return m_material.specularModel;
175}
176
177QSSGRenderDefaultMaterial::MaterialAlphaMode QSSGShaderDefaultMaterialAdapter::alphaMode()
178{
179 return m_material.alphaMode;
180}
181
182QSSGRenderDefaultMaterial::VertexColorMaskFlags QSSGShaderDefaultMaterialAdapter::vertexColorRedMask()
183{
184 return m_material.vertexColorRedMask;
185}
186
187QSSGRenderDefaultMaterial::VertexColorMaskFlags QSSGShaderDefaultMaterialAdapter::vertexColorGreenMask()
188{
189 return m_material.vertexColorGreenMask;
190}
191
192QSSGRenderDefaultMaterial::VertexColorMaskFlags QSSGShaderDefaultMaterialAdapter::vertexColorBlueMask()
193{
194 return m_material.vertexColorBlueMask;
195}
196
197QSSGRenderDefaultMaterial::VertexColorMaskFlags QSSGShaderDefaultMaterialAdapter::vertexColorAlphaMask()
198{
199 return m_material.vertexColorAlphaMask;
200}
201
202QSSGRenderImage *QSSGShaderDefaultMaterialAdapter::iblProbe()
203{
204 return m_material.iblProbe;
205}
206
207QVector3D QSSGShaderDefaultMaterialAdapter::emissiveColor()
208{
209 return m_material.emissiveColor;
210}
211
212QVector4D QSSGShaderDefaultMaterialAdapter::color()
213{
214 return m_material.color;
215}
216
217QVector3D QSSGShaderDefaultMaterialAdapter::specularTint()
218{
219 return m_material.specularTint;
220}
221
222float QSSGShaderDefaultMaterialAdapter::ior()
223{
224 return m_material.ior;
225}
226
227bool QSSGShaderDefaultMaterialAdapter::isFresnelScaleBiasEnabled()
228{
229 return m_material.fresnelScaleBiasEnabled;
230}
231
232float QSSGShaderDefaultMaterialAdapter::fresnelScale()
233{
234 return m_material.fresnelScale;
235}
236
237float QSSGShaderDefaultMaterialAdapter::fresnelBias()
238{
239 return m_material.fresnelBias;
240}
241
242float QSSGShaderDefaultMaterialAdapter::fresnelPower()
243{
244 return m_material.fresnelPower;
245}
246
247bool QSSGShaderDefaultMaterialAdapter::isClearcoatFresnelScaleBiasEnabled()
248{
249 return m_material.clearcoatFresnelScaleBiasEnabled;
250}
251
252float QSSGShaderDefaultMaterialAdapter::clearcoatFresnelScale()
253{
254 return m_material.clearcoatFresnelScale;
255}
256
257float QSSGShaderDefaultMaterialAdapter::clearcoatFresnelBias()
258{
259 return m_material.clearcoatFresnelBias;
260}
261
262float QSSGShaderDefaultMaterialAdapter::clearcoatFresnelPower()
263{
264 return m_material.clearcoatFresnelPower;
265}
266
267float QSSGShaderDefaultMaterialAdapter::metalnessAmount()
268{
269 return m_material.metalnessAmount;
270}
271
272float QSSGShaderDefaultMaterialAdapter::specularAmount()
273{
274 return m_material.specularAmount;
275}
276
277float QSSGShaderDefaultMaterialAdapter::specularRoughness()
278{
279 return m_material.specularRoughness;
280}
281
282float QSSGShaderDefaultMaterialAdapter::bumpAmount()
283{
284 return m_material.bumpAmount;
285}
286
287float QSSGShaderDefaultMaterialAdapter::translucentFallOff()
288{
289 return m_material.translucentFalloff;
290}
291
292float QSSGShaderDefaultMaterialAdapter::diffuseLightWrap()
293{
294 return m_material.diffuseLightWrap;
295}
296
297float QSSGShaderDefaultMaterialAdapter::occlusionAmount()
298{
299 return m_material.occlusionAmount;
300}
301
302float QSSGShaderDefaultMaterialAdapter::alphaCutOff()
303{
304 return m_material.alphaCutoff;
305}
306
307float QSSGShaderDefaultMaterialAdapter::pointSize()
308{
309 return m_material.pointSize;
310}
311
312float QSSGShaderDefaultMaterialAdapter::lineWidth()
313{
314 return m_material.lineWidth;
315}
316
317float QSSGShaderDefaultMaterialAdapter::heightAmount()
318{
319 return m_material.heightAmount;
320}
321
322float QSSGShaderDefaultMaterialAdapter::minHeightSamples()
323{
324 return m_material.minHeightSamples;
325}
326
327float QSSGShaderDefaultMaterialAdapter::maxHeightSamples()
328{
329 return m_material.maxHeightSamples;
330}
331
332float QSSGShaderDefaultMaterialAdapter::clearcoatAmount()
333{
334 return m_material.clearcoatAmount;
335}
336
337float QSSGShaderDefaultMaterialAdapter::clearcoatRoughnessAmount()
338{
339 return m_material.clearcoatRoughnessAmount;
340}
341
342float QSSGShaderDefaultMaterialAdapter::clearcoatNormalStrength()
343{
344 return m_material.clearcoatNormalStrength;
345}
346
347QVector3D QSSGShaderDefaultMaterialAdapter::sheenColor()
348{
349 return m_material.sheenColor;
350}
351
352float QSSGShaderDefaultMaterialAdapter::sheenRoughness()
353{
354 return m_material.sheenRoughness;
355}
356
357float QSSGShaderDefaultMaterialAdapter::anisotropyStrength()
358{
359 return m_material.anisotropyStrength;
360}
361
362float QSSGShaderDefaultMaterialAdapter::anisotropyRotation()
363{
364 return m_material.anisotropyRotation;
365}
366
367float QSSGShaderDefaultMaterialAdapter::iridescenceFactor()
368{
369 return m_material.iridescenceFactor;
370}
371
372float QSSGShaderDefaultMaterialAdapter::iridescenceIndexOfRefraction()
373{
374 return m_material.iridescenceIndexOfRefraction;
375}
376
377float QSSGShaderDefaultMaterialAdapter::iridescenceThicknessMinimum()
378{
379 return m_material.iridescenceThicknessMinimum;
380}
381
382float QSSGShaderDefaultMaterialAdapter::iridescenceThicknessMaximum()
383{
384 return m_material.iridescenceThicknessMaximum;
385}
386
387float QSSGShaderDefaultMaterialAdapter::dispersion()
388{
389 return m_material.dispersion;
390}
391
392float QSSGShaderDefaultMaterialAdapter::transmissionFactor()
393{
394 return m_material.transmissionFactor;
395}
396
397float QSSGShaderDefaultMaterialAdapter::thicknessFactor()
398{
399 return m_material.thicknessFactor;
400}
401
402float QSSGShaderDefaultMaterialAdapter::attenuationDistance()
403{
404 return m_material.attenuationDistance;
405}
406
407QVector3D QSSGShaderDefaultMaterialAdapter::attenuationColor()
408{
409 return m_material.attenuationColor;
410}
411
412QSSGShaderCustomMaterialAdapter::QSSGShaderCustomMaterialAdapter(const QSSGRenderCustomMaterial &material)
413 : m_material(material)
414{
415}
416
417// Act like Principled. Lighting is always on, specular, metalness, etc. support should all be enabled.
418// Unlike Principled, the *enabled values do not depend on the metalness or specularAmount values
419// (we cannot tell what those are if they are written in the shader).
420
421bool QSSGShaderCustomMaterialAdapter::isPrincipled()
422{
423 return true;
424}
425
426bool QSSGShaderCustomMaterialAdapter::isSpecularGlossy()
427{
428 return false;
429}
430
431bool QSSGShaderCustomMaterialAdapter::isMetalnessEnabled()
432{
433 return true;
434}
435
436bool QSSGShaderCustomMaterialAdapter::isSpecularEnabled()
437{
438 return true;
439}
440
441bool QSSGShaderCustomMaterialAdapter::isVertexColorsEnabled()
442{
443 return m_material.m_renderFlags.testFlag(QSSGRenderCustomMaterial::RenderFlag::VarColor);
444}
445
446bool QSSGShaderCustomMaterialAdapter::isVertexColorsMaskEnabled()
447{
448 return false;
449}
450
451bool QSSGShaderCustomMaterialAdapter::isInvertOpacityMapValue()
452{
453 return false;
454}
455
456bool QSSGShaderCustomMaterialAdapter::isBaseColorSingleChannelEnabled()
457{
458 return false;
459}
460
461bool QSSGShaderCustomMaterialAdapter::isSpecularAmountSingleChannelEnabled()
462{
463 return false;
464}
465
466bool QSSGShaderCustomMaterialAdapter::isEmissiveSingleChannelEnabled()
467{
468 return false;
469}
470
471bool QSSGShaderCustomMaterialAdapter::isClearcoatEnabled()
472{
473 return m_material.m_renderFlags.testFlag(QSSGRenderCustomMaterial::RenderFlag::Clearcoat);
474}
475
476bool QSSGShaderCustomMaterialAdapter::isSheenEnabled()
477{
478 return m_material.m_renderFlags.testFlag(QSSGRenderCustomMaterial::RenderFlag::Sheen);
479}
480
481bool QSSGShaderCustomMaterialAdapter::isAnisotropyEnabled()
482{
483 return m_material.m_renderFlags.testFlag(QSSGRenderCustomMaterial::RenderFlag::Anisotropy);
484}
485
486bool QSSGShaderCustomMaterialAdapter::isIridescenceEnabled()
487{
488 return m_material.m_renderFlags.testFlag(QSSGRenderCustomMaterial::RenderFlag::Iridescence);
489}
490
491bool QSSGShaderCustomMaterialAdapter::isDispersionEnabled()
492{
493 // Only declares the keyword; it is applied when transmission is used too
494 return m_material.m_renderFlags.testFlag(QSSGRenderCustomMaterial::RenderFlag::Dispersion);
495}
496
497bool QSSGShaderCustomMaterialAdapter::isTransmissionEnabled()
498{
499 return m_material.m_renderFlags.testFlag(QSSGRenderCustomMaterial::RenderFlag::Transmission);
500}
501
502bool QSSGShaderCustomMaterialAdapter::hasLighting()
503{
504 return true;
505}
506
507bool QSSGShaderCustomMaterialAdapter::usesCustomSkinning()
508{
509 return m_material.m_renderFlags.testFlag(QSSGRenderCustomMaterial::RenderFlag::Skinning);
510}
511
512bool QSSGShaderCustomMaterialAdapter::usesCustomMorphing()
513{
514 return m_material.m_renderFlags.testFlag(QSSGRenderCustomMaterial::RenderFlag::Morphing);
515}
516
517QSSGRenderDefaultMaterial::MaterialSpecularModel QSSGShaderCustomMaterialAdapter::specularModel()
518{
519 return QSSGRenderDefaultMaterial::MaterialSpecularModel::SchlickGGX;
520}
521
522QSSGRenderDefaultMaterial::MaterialAlphaMode QSSGShaderCustomMaterialAdapter::alphaMode()
523{
524 return QSSGRenderDefaultMaterial::MaterialAlphaMode::Default;
525}
526
527QSSGRenderDefaultMaterial::VertexColorMaskFlags QSSGShaderCustomMaterialAdapter::vertexColorRedMask()
528{
529 return QSSGRenderDefaultMaterial::NoMask;
530}
531
532QSSGRenderDefaultMaterial::VertexColorMaskFlags QSSGShaderCustomMaterialAdapter::vertexColorGreenMask()
533{
534 return QSSGRenderDefaultMaterial::NoMask;
535}
536
537QSSGRenderDefaultMaterial::VertexColorMaskFlags QSSGShaderCustomMaterialAdapter::vertexColorBlueMask()
538{
539 return QSSGRenderDefaultMaterial::NoMask;
540}
541
542QSSGRenderDefaultMaterial::VertexColorMaskFlags QSSGShaderCustomMaterialAdapter::vertexColorAlphaMask()
543{
544 return QSSGRenderDefaultMaterial::NoMask;
545}
546
547QSSGRenderImage *QSSGShaderCustomMaterialAdapter::iblProbe()
548{
549 return m_material.m_iblProbe;
550}
551
552// The following are the values that get set into uniforms such as
553// qt_material_properties etc. When a custom shader is present, these values
554// are not used at all. However, a CustomMaterial is also valid without a
555// vertex/fragment shader, or with no custom shaders at all. Therefore the
556// values here must match the defaults of PrincipledMaterial, in order to make
557// PrincipledMaterial { } and CustomMaterial { } identical.
558
559QVector3D QSSGShaderCustomMaterialAdapter::emissiveColor()
560{
561 return QVector3D(0, 0, 0);
562}
563
564QVector4D QSSGShaderCustomMaterialAdapter::color()
565{
566 return QVector4D(1, 1, 1, 1);
567}
568
569QVector3D QSSGShaderCustomMaterialAdapter::specularTint()
570{
571 return QVector3D(1, 1, 1);
572}
573
574float QSSGShaderCustomMaterialAdapter::ior()
575{
576 return 1.45f;
577}
578
579bool QSSGShaderCustomMaterialAdapter::isFresnelScaleBiasEnabled()
580{
581 return m_material.m_renderFlags.testFlag(QSSGRenderCustomMaterial::RenderFlag::FresnelScaleBias);
582}
583
584float QSSGShaderCustomMaterialAdapter::fresnelScale()
585{
586 return 1.0f;
587}
588
589float QSSGShaderCustomMaterialAdapter::fresnelBias()
590{
591 return 0.0f;
592}
593
594float QSSGShaderCustomMaterialAdapter::fresnelPower()
595{
596 return 0.0f;
597}
598
599bool QSSGShaderCustomMaterialAdapter::isClearcoatFresnelScaleBiasEnabled()
600{
601 return m_material.m_renderFlags.testFlag(QSSGRenderCustomMaterial::RenderFlag::ClearcoatFresnelScaleBias);
602}
603
604float QSSGShaderCustomMaterialAdapter::clearcoatFresnelScale()
605{
606 return 1.0f;
607}
608
609float QSSGShaderCustomMaterialAdapter::clearcoatFresnelBias()
610{
611 return 0.0f;
612}
613
614float QSSGShaderCustomMaterialAdapter::clearcoatFresnelPower()
615{
616 return 0.0f;
617}
618
619float QSSGShaderCustomMaterialAdapter::metalnessAmount()
620{
621 return 0.0f;
622}
623
624float QSSGShaderCustomMaterialAdapter::specularAmount()
625{
626 return 0.5f;
627}
628
629float QSSGShaderCustomMaterialAdapter::specularRoughness()
630{
631 return 0.0f;
632}
633
634float QSSGShaderCustomMaterialAdapter::bumpAmount()
635{
636 return 0.0f;
637}
638
639float QSSGShaderCustomMaterialAdapter::translucentFallOff()
640{
641 return 0.0f;
642}
643
644float QSSGShaderCustomMaterialAdapter::diffuseLightWrap()
645{
646 return 0.0f;
647}
648
649float QSSGShaderCustomMaterialAdapter::occlusionAmount()
650{
651 return 1.0f;
652}
653
654float QSSGShaderCustomMaterialAdapter::alphaCutOff()
655{
656 return 0.5f;
657}
658
659float QSSGShaderCustomMaterialAdapter::pointSize()
660{
661 return 1.0f;
662}
663
664float QSSGShaderCustomMaterialAdapter::lineWidth()
665{
666 return m_material.m_lineWidth;
667}
668
669float QSSGShaderCustomMaterialAdapter::heightAmount()
670{
671 return 0.0f;
672}
673
674float QSSGShaderCustomMaterialAdapter::minHeightSamples()
675{
676 return 0.0f;
677}
678
679float QSSGShaderCustomMaterialAdapter::maxHeightSamples()
680{
681 return 0.0f;
682}
683
684float QSSGShaderCustomMaterialAdapter::clearcoatAmount()
685{
686 return 0.0f;
687}
688
689float QSSGShaderCustomMaterialAdapter::clearcoatRoughnessAmount()
690{
691 return 0.0f;
692}
693
694float QSSGShaderCustomMaterialAdapter::clearcoatNormalStrength()
695{
696 return 1.0f;
697}
698
699QVector3D QSSGShaderCustomMaterialAdapter::sheenColor()
700{
701 // Custom materials provide the value through the SHEEN_COLOR keyword
702 return { 0.0f, 0.0f, 0.0f };
703}
704
705float QSSGShaderCustomMaterialAdapter::sheenRoughness()
706{
707 return 0.0f;
708}
709
710float QSSGShaderCustomMaterialAdapter::anisotropyStrength()
711{
712 // Custom materials provide the value through the ANISOTROPY_STRENGTH keyword
713 return 0.0f;
714}
715
716float QSSGShaderCustomMaterialAdapter::anisotropyRotation()
717{
718 return 0.0f;
719}
720
721float QSSGShaderCustomMaterialAdapter::iridescenceFactor()
722{
723 // Custom materials provide the value through the IRIDESCENCE_FACTOR keyword
724 return 0.0f;
725}
726
727float QSSGShaderCustomMaterialAdapter::iridescenceIndexOfRefraction()
728{
729 return 1.3f;
730}
731
732float QSSGShaderCustomMaterialAdapter::iridescenceThicknessMinimum()
733{
734 return 100.0f;
735}
736
737float QSSGShaderCustomMaterialAdapter::iridescenceThicknessMaximum()
738{
739 return 400.0f;
740}
741
742float QSSGShaderCustomMaterialAdapter::dispersion()
743{
744 // Custom materials provide the value through the DISPERSION keyword
745 return 0.0f;
746}
747
748float QSSGShaderCustomMaterialAdapter::transmissionFactor()
749{
750 return 0.0f;
751}
752
753float QSSGShaderCustomMaterialAdapter::thicknessFactor()
754{
755 return 0.0f;
756}
757
758float QSSGShaderCustomMaterialAdapter::attenuationDistance()
759{
760 return std::numeric_limits<float>::infinity();
761}
762
763QVector3D QSSGShaderCustomMaterialAdapter::attenuationColor()
764{
765 return { 1.0f, 1.0f, 1.0f };
766}
767
768bool QSSGShaderCustomMaterialAdapter::isUnshaded()
769{
770 return m_material.m_shadingMode == QSSGRenderCustomMaterial::ShadingMode::Unshaded;
771}
772
773bool QSSGShaderCustomMaterialAdapter::hasCustomShaderSnippet(QSSGShaderCache::ShaderType type)
774{
775 if (type == QSSGShaderCache::ShaderType::Vertex)
776 return m_material.m_customShaderPresence.testFlag(QSSGRenderCustomMaterial::CustomShaderPresenceFlag::Vertex);
777
778 return m_material.m_customShaderPresence.testFlag(QSSGRenderCustomMaterial::CustomShaderPresenceFlag::Fragment);
779}
780
781QByteArray QSSGShaderCustomMaterialAdapter::customShaderSnippet(QSSGShaderCache::ShaderType type,
782 QSSGShaderLibraryManager &shaderLibraryManager,
783 bool multiViewCompatible)
784{
785 if (hasCustomShaderSnippet(type)) {
786 const QByteArray shaderPathKey = m_material.m_shaderPathKey[multiViewCompatible ? QSSGRenderCustomMaterial::MultiViewShaderPathKeyIndex
787 : QSSGRenderCustomMaterial::RegularShaderPathKeyIndex];
788 return shaderLibraryManager.getShaderSource(shaderPathKey, type);
789 }
790
791 return QByteArray();
792}
793
794bool QSSGShaderCustomMaterialAdapter::hasCustomShaderFunction(QSSGShaderCache::ShaderType shaderType,
795 const QByteArray &funcName,
796 QSSGShaderLibraryManager &shaderLibraryManager)
797{
798 if (hasCustomShaderSnippet(shaderType))
799 return shaderLibraryManager.getShaderMetaData(m_material.m_shaderPathKey[QSSGRenderCustomMaterial::RegularShaderPathKeyIndex],
800 shaderType).customFunctions.contains(funcName);
801
802 return false;
803}
804
805void QSSGShaderCustomMaterialAdapter::setCustomPropertyUniforms(char *ubufData,
806 QSSGRhiShaderPipeline &shaderPipeline,
807 const QSSGRenderContextInterface &context)
808{
809 context.customMaterialSystem()->applyRhiShaderPropertyValues(ubufData, m_material, shaderPipeline);
810}
811
812bool QSSGShaderCustomMaterialAdapter::usesSharedVariables()
813{
814 return m_material.m_usesSharedVariables;
815}
816
817namespace {
818
819// Custom material shader substitution table.
820// Must be in sync with the shader generator.
821static const QSSGCustomMaterialVariableSubstitution qssg_var_subst_tab[] = {
822 // uniform (block members)
823 { "MODELVIEWPROJECTION_MATRIX", "qt_modelViewProjection", true },
824 { "VIEWPROJECTION_MATRIX", "qt_viewProjectionMatrix", true },
825 { "MODEL_MATRIX", "qt_modelMatrix", false },
826 { "VIEW_MATRIX", "qt_viewMatrix", true },
827 { "NORMAL_MATRIX", "qt_normalMatrix", false },
828 { "BONE_TRANSFORMS", "qt_getTexMatrix", false },
829 { "BONE_NORMAL_TRANSFORMS", "qt_getTexMatrix", false },
830 { "PROJECTION_MATRIX", "qt_projectionMatrix", true },
831 { "INVERSE_PROJECTION_MATRIX", "qt_inverseProjectionMatrix", true },
832 { "CAMERA_POSITION", "qt_cameraPosition", true },
833 { "CAMERA_DIRECTION", "qt_cameraDirection", true },
834 { "CAMERA_PROPERTIES", "qt_cameraProperties", false },
835 { "FRAMEBUFFER_Y_UP", "qt_rhi_properties.x", false },
836 { "NDC_Y_UP", "qt_rhi_properties.y", false },
837 { "NEAR_CLIP_VALUE", "qt_rhi_properties.z", false },
838 { "IBL_MAXMIPMAP", "qt_lightProbeProperties.y", false },
839 { "IBL_HORIZON", "qt_lightProbeProperties.z", false },
840 { "IBL_EXPOSE", "qt_lightProbeProperties.w", false },
841
842 // outputs
843 { "POSITION", "gl_Position", false },
844 { "FRAGCOLOR", "fragOutput", false },
845 { "POINT_SIZE", "gl_PointSize", false },
846
847 // fragment inputs
848 { "FRAGCOORD", "gl_FragCoord", false },
849
850 // functions
851 { "DIRECTIONAL_LIGHT", "qt_directionalLightProcessor", false },
852 { "POINT_LIGHT", "qt_pointLightProcessor", false },
853 { "SPOT_LIGHT", "qt_spotLightProcessor", false },
854 { "AMBIENT_LIGHT", "qt_ambientLightProcessor", false },
855 { "SPECULAR_LIGHT", "qt_specularLightProcessor", false },
856 { "MAIN", "qt_customMain", false },
857 { "POST_PROCESS", "qt_customPostProcessor", false },
858 { "IBL_PROBE", "qt_iblProbeProcessor", false },
859
860 // textures
861 { "SCREEN_TEXTURE", "qt_screenTexture", true },
862 { "SCREEN_MIP_TEXTURE", "qt_screenTexture", true }, // same resource as SCREEN_TEXTURE under the hood
863 { "DEPTH_TEXTURE", "qt_depthTexture", true },
864 { "AO_TEXTURE", "qt_aoTexture", true },
865 { "IBL_TEXTURE", "qt_lightProbe", false },
866 { "LIGHTMAP", "qt_lightmap", false },
867 { "NORMAL_ROUGHNESS_TEXTURE", "qt_normalTexture", false },
868 { "MOTION_VECTOR_TEXTURE", "qt_motionVectorTexture", false },
869
870 // For shaded only: vertex outputs, for convenience and perf. (only those
871 // that are always present when lighting is enabled) The custom vertex main
872 // can also calculate on its own and pass them on with VARYING but that's a
873 // bit wasteful since we calculate these anyways.
874 { "VAR_WORLD_NORMAL", "qt_varNormal", false },
875 { "VAR_WORLD_TANGENT", "qt_varTangent", false },
876 { "VAR_WORLD_BINORMAL", "qt_varBinormal", false },
877 { "VAR_WORLD_POSITION", "qt_varWorldPos", false },
878 // vertex color is always enabled for custom materials (shaded)
879 { "VAR_COLOR", "qt_varColor", false },
880
881 // effects
882 { "INPUT", "qt_inputTexture", true },
883 { "INPUT_UV", "qt_inputUV", false },
884 { "TEXTURE_UV", "qt_textureUV", false },
885 { "INPUT_SIZE", "qt_inputSize", false },
886 { "OUTPUT_SIZE", "qt_outputSize", false },
887 { "FRAME", "qt_frame_num", false },
888
889 // instancing
890 { "INSTANCE_COLOR", "qt_instanceColor", false },
891 { "INSTANCE_DATA", "qt_instanceData", false },
892 { "INSTANCE_INDEX", "gl_InstanceIndex", false },
893
894 // morphing
895 { "MORPH_POSITION", "qt_getTargetPositionFromTargetId", false },
896 { "MORPH_NORMAL", "qt_getTargetNormalFromTargetId", false },
897 { "MORPH_TANGENT", "qt_getTargetTangentFromTargetId", false },
898 { "MORPH_BINORMAL", "qt_getTargetBinormalFromTargetId", false },
899 { "MORPH_WEIGHTS", "qt_morphWeights", false },
900
901 // custom variables
902 { "SHARED_VARS", "struct QT_SHARED_VARS", false },
903
904 // multiview
905 { "VIEW_INDEX", "qt_viewIndex", false }
906};
907
908// Functions that, if present, get an argument list injected.
909static const QByteArrayView qssg_func_injectarg_tab[] = {
910 "DIRECTIONAL_LIGHT",
911 "POINT_LIGHT",
912 "SPOT_LIGHT",
913 "AMBIENT_LIGHT",
914 "SPECULAR_LIGHT",
915 "MAIN",
916 "POST_PROCESS",
917 "IBL_PROBE"
918};
919
920// This is based on the Qt Quick shader rewriter (with fixes)
921struct Tokenizer {
922 enum Token {
923 Token_Comment,
924 Token_OpenBrace,
925 Token_CloseBrace,
926 Token_OpenParen,
927 Token_CloseParen,
928 Token_SemiColon,
929 Token_Identifier,
930 Token_OpenBraket,
931 Token_CloseBraket,
932 Token_Unspecified,
933
934 Token_EOF
935 };
936
937 void initialize(const QByteArray &input);
938 Token next();
939
940 const char *stream;
941 const char *pos;
942 const char *identifier;
943};
944
945void Tokenizer::initialize(const QByteArray &input)
946{
947 stream = input.constData();
948 pos = input;
949 identifier = input;
950}
951
952Tokenizer::Token Tokenizer::next()
953{
954 while (*pos) {
955 char c = *pos++;
956 switch (c) {
957 case '/':
958 if (*pos == '/') {
959 // '//' comment
960 ++pos;
961 while (*pos && *pos != '\n') ++pos;
962 return Token_Comment;
963 } else if (*pos == '*') {
964 // /* */ comment
965 ++pos;
966 while (*pos && (*pos != '*' || pos[1] != '/')) ++pos;
967 if (*pos) pos += 2;
968 return Token_Comment;
969 }
970 return Token_Unspecified;
971
972 case ';': return Token_SemiColon;
973 case '\0': return Token_EOF;
974 case '{': return Token_OpenBrace;
975 case '}': return Token_CloseBrace;
976 case '(': return Token_OpenParen;
977 case ')': return Token_CloseParen;
978 case '[': return Token_OpenBraket;
979 case ']': return Token_CloseBraket;
980
981 case ' ':
982 case '\n':
983 case '\r': break;
984 default:
985 // Identifier...
986 if ((c >= 'a' && c <= 'z' ) || (c >= 'A' && c <= 'Z' ) || c == '_') {
987 identifier = pos - 1;
988 while (*pos && ((*pos >= 'a' && *pos <= 'z')
989 || (*pos >= 'A' && *pos <= 'Z')
990 || *pos == '_'
991 || (*pos >= '0' && *pos <= '9'))) {
992 ++pos;
993 }
994 return Token_Identifier;
995 } else {
996 return Token_Unspecified;
997 }
998 }
999 }
1000
1001 return Token_EOF;
1002}
1003} // namespace
1004
1005void QSSGShaderCustomMaterialAdapter::beginPrepareCustomShader(
1006 CustomShaderPrepWorkData *workData,
1007 ShaderCodeAndMetaData *codeAndMetaData,
1008 const QByteArray &shaderCode,
1009 QSSGShaderCache::ShaderType type,
1010 bool multiViewCompatible)
1011{
1012 QByteArrayList inputs;
1013 QByteArrayList outputs;
1014
1015 Tokenizer tok;
1016 tok.initialize(shaderCode);
1017
1018 QSSGCustomShaderMetaData md = {};
1019 QByteArray result;
1020 result.reserve(1024);
1021 // If shader debugging is not enabled we reset the line count to make error message
1022 // when a shader fails more useful. When shader debugging is enabled the whole shader
1023 // will be printed and not just the user written part, so in that case we do not want
1024 // to adjust the line numbers.
1025 //
1026 // NOTE: This is not perfect, we do expend the custom material and effect shaders, so
1027 // there cane still be cases where the reported line numbers are slightly off.
1028 if (!QSSGRhiContextPrivate::shaderDebuggingEnabled())
1029 result.prepend("#line 1\n");
1030 const char *lastPos = shaderCode.constData();
1031
1032 int funcFinderState = 0;
1033 int useJointTexState = -1;
1034 int useJointNormalTexState = -1;
1035 QByteArray currentShadedFunc;
1036 Tokenizer::Token t = tok.next();
1037 while (t != Tokenizer::Token_EOF) {
1038 switch (t) {
1039 case Tokenizer::Token_Comment:
1040 break;
1041 case Tokenizer::Token_Identifier:
1042 {
1043 QByteArray id = QByteArray::fromRawData(lastPos, tok.pos - lastPos);
1044 if (id.trimmed() == QByteArrayLiteral("VARYING")) {
1045 QByteArray vtype;
1046 QByteArray vname;
1047 bool vflat = false;
1048 lastPos = tok.pos;
1049 t = tok.next();
1050 while (t != Tokenizer::Token_EOF) {
1051 QByteArray data = QByteArray::fromRawData(lastPos, tok.pos - lastPos);
1052 if (t == Tokenizer::Token_Identifier) {
1053 if (vtype.isEmpty()) {
1054 vtype = data.trimmed();
1055 if (vtype == QByteArrayLiteral("flat")) {
1056 vflat = true;
1057 vtype.clear();
1058 }
1059 } else if (vname.isEmpty()) {
1060 vname = data.trimmed();
1061 }
1062 }
1063 if (t == Tokenizer::Token_SemiColon)
1064 break;
1065 lastPos = tok.pos;
1066 t = tok.next();
1067 }
1068 if (type == QSSGShaderCache::ShaderType::Vertex)
1069 outputs.append((vflat ? "flat " : "") + vtype + " " + vname);
1070 else
1071 inputs.append((vflat ? "flat " : "") + vtype + " " + vname);
1072 } else {
1073 const QByteArray trimmedId = id.trimmed();
1074 if (funcFinderState == 0 && trimmedId == QByteArrayLiteral("void")) {
1075 funcFinderState += 1;
1076 } else if (funcFinderState == 1) {
1077 auto begin = qssg_func_injectarg_tab;
1078 const auto end = qssg_func_injectarg_tab + (sizeof(qssg_func_injectarg_tab) / sizeof(qssg_func_injectarg_tab[0]));
1079 const auto foundIt = std::find_if(begin, end, [trimmedId](const QByteArrayView &entry) { return entry == trimmedId; });
1080 if (foundIt != end) {
1081 currentShadedFunc = trimmedId;
1082 funcFinderState += 1;
1083 }
1084 } else {
1085 funcFinderState = 0;
1086 }
1087
1088 if (trimmedId == QByteArrayLiteral("SCREEN_TEXTURE"))
1089 md.flags |= QSSGCustomShaderMetaData::UsesScreenTexture;
1090 else if (trimmedId == QByteArrayLiteral("SCREEN_MIP_TEXTURE"))
1091 md.flags |= QSSGCustomShaderMetaData::UsesScreenMipTexture;
1092 else if (trimmedId == QByteArrayLiteral("DEPTH_TEXTURE"))
1093 md.flags |= QSSGCustomShaderMetaData::UsesDepthTexture;
1094 else if (trimmedId == QByteArrayLiteral("NORMAL_ROUGHNESS_TEXTURE"))
1095 md.flags |= QSSGCustomShaderMetaData::UsesNormalTexture;
1096 else if (trimmedId == QByteArrayLiteral("AO_TEXTURE"))
1097 md.flags |= QSSGCustomShaderMetaData::UsesAoTexture;
1098 else if (trimmedId == QByteArrayLiteral("POSITION"))
1099 md.flags |= QSSGCustomShaderMetaData::OverridesPosition;
1100 else if (trimmedId == QByteArrayLiteral("PROJECTION_MATRIX"))
1101 md.flags |= QSSGCustomShaderMetaData::UsesProjectionMatrix;
1102 else if (trimmedId == QByteArrayLiteral("INVERSE_PROJECTION_MATRIX"))
1103 md.flags |= QSSGCustomShaderMetaData::UsesInverseProjectionMatrix;
1104 else if (trimmedId == QByteArrayLiteral("VIEW_MATRIX"))
1105 md.flags |= QSSGCustomShaderMetaData::UsesViewMatrix;
1106 else if (trimmedId == QByteArrayLiteral("VAR_COLOR"))
1107 md.flags |= QSSGCustomShaderMetaData::UsesVarColor;
1108 else if (trimmedId == QByteArrayLiteral("SHARED_VARS"))
1109 md.flags |= QSSGCustomShaderMetaData::UsesSharedVars;
1110 else if (trimmedId == QByteArrayLiteral("IBL_ORIENTATION"))
1111 md.flags |= QSSGCustomShaderMetaData::UsesIblOrientation;
1112 else if (trimmedId == QByteArrayLiteral("LIGHTMAP"))
1113 md.flags |= QSSGCustomShaderMetaData::UsesLightmap;
1114 else if (trimmedId == QByteArrayLiteral("VIEW_INDEX"))
1115 md.flags |= QSSGCustomShaderMetaData::UsesViewIndex;
1116 else if (trimmedId == QByteArrayLiteral("INPUT"))
1117 md.flags |= QSSGCustomShaderMetaData::UsesInputTexture;
1118 else if (trimmedId == QByteArrayLiteral("CLEARCOAT_AMOUNT"))
1119 md.flags |= QSSGCustomShaderMetaData::UsesClearcoat;
1120 else if (trimmedId == QByteArrayLiteral("SHEEN_COLOR")
1121 || trimmedId == QByteArrayLiteral("SHEEN_ROUGHNESS"))
1122 md.flags |= QSSGCustomShaderMetaData::UsesSheen;
1123 else if (trimmedId == QByteArrayLiteral("ANISOTROPY_STRENGTH")
1124 || trimmedId == QByteArrayLiteral("ANISOTROPY_ROTATION"))
1125 md.flags |= QSSGCustomShaderMetaData::UsesAnisotropy;
1126 else if (trimmedId == QByteArrayLiteral("IRIDESCENCE_FACTOR")
1127 || trimmedId == QByteArrayLiteral("IRIDESCENCE_IOR")
1128 || trimmedId == QByteArrayLiteral("IRIDESCENCE_THICKNESS"))
1129 md.flags |= QSSGCustomShaderMetaData::UsesIridescence;
1130 else if (trimmedId == QByteArrayLiteral("DISPERSION"))
1131 md.flags |= QSSGCustomShaderMetaData::UsesDispersion;
1132 else if (trimmedId == QByteArrayLiteral("CLEARCOAT_FRESNEL_SCALE") ||
1133 trimmedId == QByteArrayLiteral("CLEARCOAT_FRESNEL_BIAS"))
1134 md.flags |= QSSGCustomShaderMetaData::UsesClearcoatFresnelScaleBias;
1135 else if (trimmedId == QByteArrayLiteral("FRESNEL_SCALE") ||
1136 trimmedId == QByteArrayLiteral("FRESNEL_BIAS"))
1137 md.flags |= QSSGCustomShaderMetaData::UsesFresnelScaleBias;
1138 else if (trimmedId == QByteArrayLiteral("MOTION_VECTOR_TEXTURE"))
1139 md.flags |= QSSGCustomShaderMetaData::UsesMotionVectorTexture;
1140 else if (trimmedId == QByteArrayLiteral("TRANSMISSION_FACTOR")) {
1141 md.flags |= QSSGCustomShaderMetaData::UsesTransmission;
1142 md.flags |= QSSGCustomShaderMetaData::UsesScreenTexture;
1143 md.flags |= QSSGCustomShaderMetaData::UsesScreenMipTexture;
1144 }
1145
1146 for (const QSSGCustomMaterialVariableSubstitution &subst : qssg_var_subst_tab) {
1147 if (trimmedId == subst.builtin) {
1148 QByteArray newExpr;
1149 newExpr.assign(subst.actualName);
1150 if (subst.multiViewDependent && multiViewCompatible) {
1151 if (subst.builtin.endsWith(QByteArrayLiteral("_TEXTURE"))
1152 || subst.builtin == QByteArrayLiteral("INPUT"))
1153 {
1154 newExpr += QByteArrayLiteral("Array"); // e.g. qt_depthTexture -> qt_depthTextureArray
1155 } else {
1156 newExpr += QByteArrayLiteral("[qt_viewIndex]"); // e.g. qt_viewProjectionMatrix -> qt_viewProjectionMatrix[qt_viewIndex]
1157 }
1158 }
1159 id.replace(subst.builtin, newExpr); // replace, not assignment, to keep whitespace etc.
1160 if (trimmedId == QByteArrayLiteral("BONE_TRANSFORMS")) {
1161 useJointTexState = 0;
1162 md.flags |= QSSGCustomShaderMetaData::UsesSkinning;
1163 } else if (trimmedId == QByteArrayLiteral("BONE_NORMAL_TRANSFORMS")) {
1164 useJointNormalTexState = 0;
1165 md.flags |= QSSGCustomShaderMetaData::UsesSkinning;
1166 }
1167 if (trimmedId == QByteArrayLiteral("MORPH_POSITION") ||
1168 trimmedId == QByteArrayLiteral("MORPH_NORMAL") ||
1169 trimmedId == QByteArrayLiteral("MORPH_TANGENT") ||
1170 trimmedId == QByteArrayLiteral("MORPH_BINORMAL"))
1171 md.flags |= QSSGCustomShaderMetaData::UsesMorphing;
1172 break;
1173 }
1174 }
1175 result += id;
1176 }
1177 }
1178 break;
1179 case Tokenizer::Token_OpenParen:
1180 result += QByteArray::fromRawData(lastPos, tok.pos - lastPos);
1181 if (funcFinderState == 2) {
1182 result += QByteArrayLiteral("/*%QT_ARGS_");
1183 result += currentShadedFunc;
1184 result += QByteArrayLiteral("%*/");
1185 for (const QSSGCustomMaterialVariableSubstitution &subst : qssg_var_subst_tab) {
1186 if (currentShadedFunc == subst.builtin) {
1187 currentShadedFunc = subst.actualName.toByteArray();
1188 break;
1189 }
1190 }
1191 md.customFunctions.insert(currentShadedFunc);
1192 currentShadedFunc.clear();
1193 }
1194 funcFinderState = 0;
1195 break;
1196 case Tokenizer::Token_OpenBraket:
1197 // copy everything as-is up to the [
1198 result += QByteArray::fromRawData(lastPos, tok.pos - lastPos - 1);
1199 if (useJointTexState == 0) {
1200 result += QByteArrayLiteral("(2 * (");
1201 ++useJointTexState;
1202 break;
1203 } else if (useJointNormalTexState == 0) {
1204 result += QByteArrayLiteral("(1 + 2 * (");
1205 ++useJointNormalTexState;
1206 break;
1207 }
1208
1209 if (useJointTexState >= 0)
1210 ++useJointTexState;
1211 else if (useJointNormalTexState >= 0)
1212 ++useJointNormalTexState;
1213 result += QByteArrayLiteral("[");
1214 break;
1215 case Tokenizer::Token_CloseBraket:
1216 // copy everything as-is up to the ]
1217 result += QByteArray::fromRawData(lastPos, tok.pos - lastPos - 1);
1218 // This implementation will not allow mixed usages of BONE_TRANSFORMS and
1219 // BONE_NORMAL_TRANSFORMS.
1220 // For example, BONE_TRANSFORM[int(BONE_NORMAL_TRANFORMS[i][0].x)]
1221 // cannot be compiled successfully.
1222 if (useJointTexState <= 0 && useJointNormalTexState <= 0) {
1223 result += QByteArrayLiteral("]");
1224 break;
1225 }
1226 if (useJointTexState > 1) {
1227 result += QByteArrayLiteral("]");
1228 --useJointTexState;
1229 break;
1230 } else if (useJointNormalTexState > 1) {
1231 result += QByteArrayLiteral("]");
1232 --useJointNormalTexState;
1233 break;
1234 }
1235 result += QByteArrayLiteral("))");
1236 useJointTexState = -1;
1237 useJointNormalTexState = -1;
1238 break;
1239 default:
1240 result += QByteArray::fromRawData(lastPos, tok.pos - lastPos);
1241 break;
1242 }
1243 lastPos = tok.pos;
1244 t = tok.next();
1245 }
1246
1247 result += '\n';
1248
1249 workData->inputs = inputs;
1250 workData->outputs = outputs;
1251
1252 if (md.flags.testFlag(QSSGCustomShaderMetaData::UsesDispersion)
1253 && !md.flags.testFlag(QSSGCustomShaderMetaData::UsesTransmission)) {
1254 qWarning("Custom material writes DISPERSION but never sets TRANSMISSION_FACTOR; "
1255 "dispersion requires transmission and will have no effect");
1256 }
1257
1258 *codeAndMetaData = { result, md };
1259}
1260
1261void QSSGShaderCustomMaterialAdapter::finishPrepareCustomShader(
1262 QByteArray *dst,
1263 const CustomShaderPrepWorkData &workData,
1264 const ShaderCodeAndMetaData &codeAndMetaData,
1265 QSSGShaderCache::ShaderType type,
1266 bool multiViewCompatible,
1267 const StringPairList &baseUniforms,
1268 const StringPairList &baseInputs,
1269 const StringPairList &baseOutputs,
1270 const StringPairList &multiViewDependentSamplers,
1271 const StringPairList &multiViewDependentUniforms)
1272{
1273 StringPairList allUniforms = baseUniforms;
1274
1275 for (const StringPair &samplerTypeAndName : multiViewDependentSamplers) {
1276 if (multiViewCompatible)
1277 allUniforms.append({ "sampler2DArray", samplerTypeAndName.second });
1278 else
1279 allUniforms.append(samplerTypeAndName);
1280 }
1281
1282 const QSSGCustomShaderMetaData &md(codeAndMetaData.second);
1283
1284 // We either have qt_depthTexture or qt_depthTextureArray (or none of them),
1285 // but never both. We do not generally support binding a 2D texture to a
1286 // sampler2DArray binding point and vice versa. Therefore it is up to the
1287 // shader snippet to ifdef with QSHADER_VIEW_COUNT if it wants to support
1288 // both multiview and non-multiview rendering.
1289 if (md.flags.testFlag(QSSGCustomShaderMetaData::UsesDepthTexture)) {
1290 if (multiViewCompatible)
1291 allUniforms.append({ "sampler2DArray", "qt_depthTextureArray" });
1292 else
1293 allUniforms.append({ "sampler2D", "qt_depthTexture" });
1294 }
1295
1296 // And the same pattern for qt_screenTexture(Array).
1297 if ((md.flags.testFlag(QSSGCustomShaderMetaData::UsesScreenTexture) || md.flags.testFlag(QSSGCustomShaderMetaData::UsesScreenMipTexture))) {
1298 if (multiViewCompatible)
1299 allUniforms.append({ "sampler2DArray", "qt_screenTextureArray" });
1300 else
1301 allUniforms.append({ "sampler2D", "qt_screenTexture" });
1302 }
1303
1304 // And for SSAO.
1305 if (md.flags.testFlag(QSSGCustomShaderMetaData::UsesAoTexture)) {
1306 if (multiViewCompatible)
1307 allUniforms.append({ "sampler2DArray", "qt_aoTextureArray" });
1308 else
1309 allUniforms.append({ "sampler2D", "qt_aoTexture" });
1310 }
1311
1312 if (md.flags.testFlag(QSSGCustomShaderMetaData::UsesNormalTexture))
1313 allUniforms.append({ "sampler2D", "qt_normalTexture" });
1314
1315 // Input texture for post-processing effects.
1316 if (md.flags.testFlag(QSSGCustomShaderMetaData::UsesInputTexture)) {
1317 if (multiViewCompatible)
1318 allUniforms.append({ "sampler2DArray", "qt_inputTextureArray" });
1319 else
1320 allUniforms.append({ "sampler2D", "qt_inputTexture" });
1321 }
1322
1323 if (md.flags.testFlag(QSSGCustomShaderMetaData::UsesLightmap))
1324 allUniforms.append({ "sampler2D", "qt_lightmap" });
1325
1326 if (md.flags.testFlag(QSSGCustomShaderMetaData::UsesMotionVectorTexture))
1327 allUniforms.append({ "sampler2D", "qt_motionVectorTexture" });
1328
1329 static const char *metaStart = "#ifdef QQ3D_SHADER_META\n/*{\n \"uniforms\": [\n";
1330 static const char *metaEnd = " ]\n}*/\n#endif\n";
1331 dst->append(metaStart);
1332
1333 for (int i = 0, count = allUniforms.size(); i < count; ++i) {
1334 const auto &typeAndName(allUniforms[i]);
1335 dst->append(" { \"type\": \"" + typeAndName.first + "\", \"name\": \"" + typeAndName.second + "\" }");
1336 if (i < count - 1 || !multiViewDependentUniforms.isEmpty())
1337 dst->append(",");
1338 dst->append("\n");
1339 }
1340
1341 // multiViewDependentUniforms are not in allUniforms. For these we leave it to the
1342 // metadata processor to add an array suffix (e.g., qt_projectionMatrix[2]) when needed.
1343 for (int i = 0, count = multiViewDependentUniforms.size(); i < count; ++i) {
1344 const auto &typeAndName(multiViewDependentUniforms[i]);
1345 dst->append(" { \"type\": \"" + typeAndName.first + "\", \"name\": \"" + typeAndName.second + "\", \"multiview_dependent\": true }");
1346 if (i < count - 1)
1347 dst->append(",");
1348 dst->append("\n");
1349 }
1350
1351 dst->append(metaEnd);
1352
1353 const char *stageStr = type == QSSGShaderCache::ShaderType::Vertex ? "vertex" : "fragment";
1354 StringPairList allInputs = baseInputs;
1355 QVarLengthArray<bool, 16> inputIsFlat(allInputs.count(), false);
1356 for (const QByteArray &inputTypeAndName : workData.inputs) {
1357 const QByteArrayList typeAndName = inputTypeAndName.split(' ');
1358 if (typeAndName.size() == 2) {
1359 allInputs.append({ typeAndName[0].trimmed(), typeAndName[1].trimmed() });
1360 inputIsFlat.append(false);
1361 } else if (typeAndName.size() == 3 && typeAndName[0].startsWith("flat")) {
1362 allInputs.append({ typeAndName[1].trimmed(), typeAndName[2].trimmed() });
1363 inputIsFlat.append(true);
1364 }
1365 }
1366 if (!allInputs.isEmpty()) {
1367 static const char *metaStart = "#ifdef QQ3D_SHADER_META\n/*{\n \"inputs\": [\n";
1368 static const char *metaEnd = " ]\n}*/\n#endif\n";
1369 dst->append(metaStart);
1370 for (int i = 0, count = allInputs.size(); i < count; ++i) {
1371 dst->append(" { \"type\": \"" + allInputs[i].first
1372 + "\", \"name\": \"" + allInputs[i].second
1373 + "\", \"stage\": \"" + stageStr
1374 + (inputIsFlat[i] ? "\", \"flat\": true" : "\"")
1375 + " }");
1376 if (i < count - 1)
1377 dst->append(",");
1378 dst->append("\n");
1379 }
1380 dst->append(metaEnd);
1381 }
1382
1383 StringPairList allOutputs = baseOutputs;
1384 QVarLengthArray<bool, 16> outputIsFlat(allOutputs.count(), false);
1385 for (const QByteArray &outputTypeAndName : workData.outputs) {
1386 const QByteArrayList typeAndName = outputTypeAndName.split(' ');
1387 if (typeAndName.size() == 2) {
1388 allOutputs.append({ typeAndName[0].trimmed(), typeAndName[1].trimmed() });
1389 outputIsFlat.append(false);
1390 } else if (typeAndName.size() == 3 && typeAndName[0].startsWith("flat")) {
1391 allOutputs.append({ typeAndName[1].trimmed(), typeAndName[2].trimmed() });
1392 outputIsFlat.append(true);
1393 }
1394 }
1395 if (!allOutputs.isEmpty()) {
1396 static const char *metaStart = "#ifdef QQ3D_SHADER_META\n/*{\n \"outputs\": [\n";
1397 static const char *metaEnd = " ]\n}*/\n#endif\n";
1398 dst->append(metaStart);
1399 for (int i = 0, count = allOutputs.size(); i < count; ++i) {
1400 dst->append(" { \"type\": \"" + allOutputs[i].first
1401 + "\", \"name\": \"" + allOutputs[i].second
1402 + "\", \"stage\": \"" + stageStr
1403 + (outputIsFlat[i] ? "\", \"flat\": true" : "\"")
1404 + " }");
1405 if (i < count - 1)
1406 dst->append(",");
1407 dst->append("\n");
1408 }
1409 dst->append(metaEnd);
1410 }
1411}
1412
1413QList<QByteArrayView> QtQuick3DEditorHelpers::CustomMaterial::preprocessorVars()
1414{
1415 QList<QByteArrayView> k;
1416 k.reserve(std::size(qssg_var_subst_tab));
1417 for (const auto &v : qssg_var_subst_tab)
1418 k.push_back(v.builtin);
1419 return k;
1420}
1421
1422QT_END_NAMESPACE
Combined button and popup list for selecting options.