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