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
qssgrenderdefaultmaterialshadergenerator.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
5/* clang-format off */
6
7#include <QtQuick3DUtils/private/qssgutils_p.h>
8#include <QtQuick3DUtils/private/qssgassert_p.h>
9
10#include <QtQuick3DRuntimeRender/private/qssgrenderdefaultmaterialshadergenerator_p.h>
12#include <QtQuick3DRuntimeRender/private/qssgrendershadercodegenerator_p.h>
13#include <QtQuick3DRuntimeRender/private/qssgrenderimage_p.h>
14#include <QtQuick3DRuntimeRender/private/qssgrenderlight_p.h>
15#include <QtQuick3DRuntimeRender/private/qssgrendercamera_p.h>
16#include <QtQuick3DRuntimeRender/private/qssgrendershadowmap_p.h>
17#include <QtQuick3DRuntimeRender/private/qssgrendercustommaterial_p.h>
18#include <QtQuick3DRuntimeRender/private/qssgrendershaderlibrarymanager_p.h>
19#include <QtQuick3DRuntimeRender/private/qssgrendershaderkeys_p.h>
20#include <QtQuick3DRuntimeRender/private/qssgshadermaterialadapter_p.h>
21#include <QtQuick3DRuntimeRender/private/qssgvertexpipelineimpl_p.h>
22#include <QtQuick3DRuntimeRender/private/qssglayerrenderdata_p.h>
23
24#include <QtCore/QByteArray>
25
26#include <cstdio>
27
28QT_BEGIN_NAMESPACE
29
30namespace {
31using Type = QSSGRenderableImage::Type;
32template<Type> struct ImageStrings {};
33#define DefineImageStrings(V) template<> struct ImageStrings<Type::V> \
34{
35 static constexpr const char* sampler() { return "qt_"#V"Map_sampler"; }
36 static constexpr const char* offsets() { return "qt_"#V"Map_offsets"; }
37 static constexpr const char* rotations() { return "qt_"#V"Map_rotations"; }
38 static constexpr const char* fragCoords1() { return "qt_"#V"Map_uv_coords1"; }
39 static constexpr const char* fragCoords2() { return "qt_"#V"Map_uv_coords2"; }
40 static constexpr const char* samplerSize() { return "qt_"#V"Map_size"; }\
41}
42
49DefineImageStrings(SpecularAmountMap);
51DefineImageStrings(Translucency);
58DefineImageStrings(ClearcoatRoughness);
59DefineImageStrings(ClearcoatNormal);
60DefineImageStrings(Transmission);
62
64{
65 const char *imageSampler;
66 const char *imageFragCoords;
68 const char *imageOffsets;
69 const char *imageRotations;
70};
71
72#define DefineImageStringTableEntry(V)
73 { ImageStrings<Type::V>::sampler(), ImageStrings<Type::V>::fragCoords1(), ImageStrings<Type::V>::fragCoords2(),
74 ImageStrings<Type::V>::offsets(), ImageStrings<Type::V>::rotations() }
75
97
98const int TEXCOORD_VAR_LEN = 16;
99
100void textureCoordVaryingName(char (&outString)[TEXCOORD_VAR_LEN], quint8 uvSet)
101{
102 // For now, uvSet will be less than 2.
103 // But this value will be verified in the setProperty function.
104 Q_ASSERT(uvSet < 9);
105 qstrncpy(outString, "qt_varTexCoordX", TEXCOORD_VAR_LEN);
106 outString[14] = '0' + uvSet;
107}
108
109void textureCoordVariableName(char (&outString)[TEXCOORD_VAR_LEN], quint8 uvSet)
110{
111 // For now, uvSet will be less than 2.
112 // But this value will be verified in the setProperty function.
113 Q_ASSERT(uvSet < 9);
114 qstrncpy(outString, "qt_texCoordX", TEXCOORD_VAR_LEN);
115 outString[11] = '0' + uvSet;
116}
117
118}
119
120const char *QSSGMaterialShaderGenerator::getSamplerName(QSSGRenderableImage::Type type)
121{
122 return imageStringTable[int(type)].imageSampler;
123}
124
125static void addLocalVariable(QSSGStageGeneratorBase &inGenerator, const QByteArray &inName, const QByteArray &inType)
126{
127 inGenerator << " " << inType << " " << inName << ";\n";
128}
129
130static QByteArray uvTransform(const QByteArray& imageRotations, const QByteArray& imageOffsets)
131{
132 QByteArray transform;
133 transform = " qt_uTransform = vec3(" + imageRotations + ".x, " + imageRotations + ".y, " + imageOffsets + ".x);\n";
134 transform += " qt_vTransform = vec3(" + imageRotations + ".z, " + imageRotations + ".w, " + imageOffsets + ".y);\n";
135 return transform;
136}
137
138static void generateImageUVCoordinates(QSSGMaterialVertexPipeline &vertexShader,
139 QSSGStageGeneratorBase &fragmentShader,
140 const QSSGShaderDefaultMaterialKey &key,
141 const ImageStringSet &names,
142 bool forceFragmentShader = false,
143 quint32 uvSet = 0,
144 bool reuseImageCoords = false,
145 bool useEnvironmentMapping = false)
146{
147 char textureCoordName[TEXCOORD_VAR_LEN];
148 fragmentShader.addUniform(names.imageSampler, "sampler2D");
149 if (!forceFragmentShader) {
150 vertexShader.addUniform(names.imageOffsets, "vec3");
151 vertexShader.addUniform(names.imageRotations, "vec4");
152 } else {
153 fragmentShader.addUniform(names.imageOffsets, "vec3");
154 fragmentShader.addUniform(names.imageRotations, "vec4");
155 }
156 QByteArray uvTrans = uvTransform(names.imageRotations, names.imageOffsets);
157 if (!useEnvironmentMapping) { // default to UV mapping
158 if (!forceFragmentShader) {
159 vertexShader << uvTrans;
160 vertexShader.addOutgoing(names.imageFragCoords, "vec2");
161 vertexShader.addFunction("getTransformedUVCoords");
162 } else {
163 fragmentShader << uvTrans;
164 fragmentShader.addFunction("getTransformedUVCoords");
165 }
166 vertexShader.generateUVCoords(uvSet, key);
167 if (!forceFragmentShader) {
168 textureCoordVaryingName(textureCoordName, uvSet);
169 vertexShader << " vec2 " << names.imageFragCoordsTemp << " = qt_getTransformedUVCoords(vec3(" << textureCoordName << ", 1.0), qt_uTransform, qt_vTransform);\n";
170 vertexShader.assignOutput(names.imageFragCoords, names.imageFragCoordsTemp);
171 } else {
172 textureCoordVariableName(textureCoordName, uvSet);
173 if (reuseImageCoords)
174 fragmentShader << " ";
175 else
176 fragmentShader << " vec2 ";
177 fragmentShader << names.imageFragCoords << " = qt_getTransformedUVCoords(vec3(" << textureCoordName << ", 1.0), qt_uTransform, qt_vTransform);\n";
178 }
179 } else {
180 fragmentShader.addUniform(names.imageOffsets, "vec3");
181 fragmentShader.addUniform(names.imageRotations, "vec4");
182 fragmentShader << uvTrans;
183 vertexShader.generateEnvMapReflection(key);
184 fragmentShader.addFunction("getTransformedUVCoords");
185 if (reuseImageCoords)
186 fragmentShader << " ";
187 else
188 fragmentShader << " vec2 ";
189 fragmentShader << names.imageFragCoords << " = qt_getTransformedUVCoords(environment_map_reflection, qt_uTransform, qt_vTransform);\n";
190 }
191}
192
193static void generateImageUVSampler(QSSGMaterialVertexPipeline &vertexGenerator,
194 QSSGStageGeneratorBase &fragmentShader,
195 const QSSGShaderDefaultMaterialKey &key,
196 const ImageStringSet &names,
197 char (&outString)[TEXCOORD_VAR_LEN],
198 quint8 uvSet = 0)
199{
200 fragmentShader.addUniform(names.imageSampler, "sampler2D");
201 // NOTE: Actually update the uniform name here
202 textureCoordVariableName(outString, uvSet);
203 vertexGenerator.generateUVCoords(uvSet, key);
204}
205
206static inline QSSGShaderMaterialAdapter *getMaterialAdapter(const QSSGRenderGraphObject &inMaterial)
207{
208 switch (inMaterial.type) {
209 case QSSGRenderGraphObject::Type::DefaultMaterial:
210 case QSSGRenderGraphObject::Type::PrincipledMaterial:
211 case QSSGRenderGraphObject::Type::SpecularGlossyMaterial:
212 return static_cast<const QSSGRenderDefaultMaterial &>(inMaterial).adapter;
213 case QSSGRenderGraphObject::Type::CustomMaterial:
214 return static_cast<const QSSGRenderCustomMaterial &>(inMaterial).adapter;
215 default:
216 break;
217 }
218 return nullptr;
219}
220
221// NOTE!!!: PLEASE ADD NEW VARS HERE!
223 { "DIFFUSE" },
224 { "BASE_COLOR" },
225 { "METALNESS" },
226 { "ROUGHNESS" },
227 { "EMISSIVE" },
228 { "SPECULAR_AMOUNT" },
229 { "EMISSIVE_COLOR" },
230 { "LIGHT_COLOR" },
231 { "LIGHT_ATTENUATION" },
232 { "SPOT_FACTOR" },
233 { "SHADOW_CONTRIB" },
234 { "FRESNEL_CONTRIB" },
235 { "TO_LIGHT_DIR" },
236 { "NORMAL" },
237 { "VIEW_VECTOR" },
238 { "TOTAL_AMBIENT_COLOR" },
239 { "COLOR_SUM" },
240 { "BINORMAL" },
241 { "TANGENT" },
242 { "FRESNEL_POWER" },
243 { "INSTANCE_MODEL_MATRIX" },
244 { "INSTANCE_MODELVIEWPROJECTION_MATRIX" },
245 { "UV0" },
246 { "UV1" },
247 { "VERTEX" },
248 { "FRESNEL_SCALE" },
249 { "FRESNEL_BIAS" },
250 { "CLEARCOAT_FRESNEL_POWER" },
251 { "CLEARCOAT_FRESNEL_SCALE" },
252 { "CLEARCOAT_FRESNEL_BIAS" },
253 { "CLEARCOAT_AMOUNT" },
254 { "CLEARCOAT_NORMAL" },
255 { "CLEARCOAT_ROUGHNESS" },
256 { "IOR" },
257 { "TRANSMISSION_FACTOR" },
258 { "THICKNESS_FACTOR" },
259 { "ATTENUATION_COLOR" },
260 { "ATTENUATION_DISTANCE" },
261 { "OCCLUSION_AMOUNT" },
262};
263
264const char *QSSGMaterialShaderGenerator::directionalLightProcessorArgumentList()
265{
266 return "inout vec3 DIFFUSE, in vec3 LIGHT_COLOR, in float SHADOW_CONTRIB, in vec3 TO_LIGHT_DIR, in vec3 NORMAL, in vec4 BASE_COLOR, in float METALNESS, in float ROUGHNESS, in vec3 VIEW_VECTOR";
267}
268
269const char *QSSGMaterialShaderGenerator::pointLightProcessorArgumentList()
270{
271 return "inout vec3 DIFFUSE, in vec3 LIGHT_COLOR, in float LIGHT_ATTENUATION, in float SHADOW_CONTRIB, in vec3 TO_LIGHT_DIR, in vec3 NORMAL, in vec4 BASE_COLOR, in float METALNESS, in float ROUGHNESS, in vec3 VIEW_VECTOR";
272}
273
274const char *QSSGMaterialShaderGenerator::spotLightProcessorArgumentList()
275{
276 return "inout vec3 DIFFUSE, in vec3 LIGHT_COLOR, in float LIGHT_ATTENUATION, float SPOT_FACTOR, in float SHADOW_CONTRIB, in vec3 TO_LIGHT_DIR, in vec3 NORMAL, in vec4 BASE_COLOR, in float METALNESS, in float ROUGHNESS, in vec3 VIEW_VECTOR";
277}
278
279const char *QSSGMaterialShaderGenerator::ambientLightProcessorArgumentList()
280{
281 return "inout vec3 DIFFUSE, in vec3 TOTAL_AMBIENT_COLOR, in vec3 NORMAL, in vec3 VIEW_VECTOR";
282}
283
284const char *QSSGMaterialShaderGenerator::specularLightProcessorArgumentList()
285{
286 return "inout vec3 SPECULAR, in vec3 LIGHT_COLOR, in float LIGHT_ATTENUATION, in float SHADOW_CONTRIB, in vec3 FRESNEL_CONTRIB, in vec3 TO_LIGHT_DIR, in vec3 NORMAL, in vec4 BASE_COLOR, in float METALNESS, in float ROUGHNESS, in float SPECULAR_AMOUNT, in vec3 VIEW_VECTOR";
287}
288
289const char *QSSGMaterialShaderGenerator::shadedFragmentMainArgumentList()
290{
291 return "inout vec4 BASE_COLOR, inout vec3 EMISSIVE_COLOR, inout float METALNESS, inout float ROUGHNESS, inout float SPECULAR_AMOUNT, inout float FRESNEL_POWER, inout vec3 NORMAL, inout vec3 TANGENT, inout vec3 BINORMAL, in vec2 UV0, in vec2 UV1, in vec3 VIEW_VECTOR, inout float IOR, inout float OCCLUSION_AMOUNT";
292}
293
294const char *QSSGMaterialShaderGenerator::postProcessorArgumentList()
295{
296 return "inout vec4 COLOR_SUM, in vec4 DIFFUSE, in vec3 SPECULAR, in vec3 EMISSIVE, in vec2 UV0, in vec2 UV1";
297}
298
299const char *QSSGMaterialShaderGenerator::iblProbeProcessorArgumentList()
300{
301 return "inout vec3 DIFFUSE, inout vec3 SPECULAR, in vec4 BASE_COLOR, in float AO_FACTOR, in float SPECULAR_AMOUNT, in float ROUGHNESS, in vec3 NORMAL, in vec3 VIEW_VECTOR, in mat3 IBL_ORIENTATION";
302}
303
304const char *QSSGMaterialShaderGenerator::vertexMainArgumentList()
305{
306 return "inout vec3 VERTEX, inout vec3 NORMAL, inout vec2 UV0, inout vec2 UV1, inout vec3 TANGENT, inout vec3 BINORMAL, inout ivec4 JOINTS, inout vec4 WEIGHTS, inout vec4 COLOR";
307}
308
309const char *QSSGMaterialShaderGenerator::vertexInstancedMainArgumentList()
310{
311 return "inout vec3 VERTEX, inout vec3 NORMAL, inout vec2 UV0, inout vec2 UV1, inout vec3 TANGENT, inout vec3 BINORMAL, inout ivec4 JOINTS, inout vec4 WEIGHTS, inout vec4 COLOR, inout mat4 INSTANCE_MODEL_MATRIX, inout mat4 INSTANCE_MODELVIEWPROJECTION_MATRIX";
312}
313
314#define MAX_MORPH_TARGET 8
315
316static void generateFragmentDefines(QSSGStageGeneratorBase &fragmentShader,
317 const QSSGShaderDefaultMaterialKey &inKey,
318 const QSSGShaderDefaultMaterialKeyProperties &keyProps,
319 QSSGShaderMaterialAdapter *materialAdapter,
320 QSSGShaderLibraryManager &shaderLibraryManager)
321{
322 if (materialAdapter->hasCustomShaderSnippet(QSSGShaderCache::ShaderType::Fragment)) {
323 auto hasCustomFunction = [&shaderLibraryManager, materialAdapter](const QByteArray &funcName) {
324 return materialAdapter->hasCustomShaderFunction(QSSGShaderCache::ShaderType::Fragment, funcName, shaderLibraryManager);
325 };
326
327 if (hasCustomFunction(QByteArrayLiteral("qt_directionalLightProcessor")))
328 fragmentShader.addDefinition("QSSG_CUSTOM_MATERIAL_DIRECTIONAL_LIGHT_PROCESSOR", "1");
329 if (hasCustomFunction(QByteArrayLiteral("qt_pointLightProcessor")))
330 fragmentShader.addDefinition("QSSG_CUSTOM_MATERIAL_POINT_LIGHT_PROCESSOR", "1");
331 if (hasCustomFunction(QByteArrayLiteral("qt_spotLightProcessor")))
332 fragmentShader.addDefinition("QSSG_CUSTOM_MATERIAL_SPOT_LIGHT_PROCESSOR", "1");
333 if (hasCustomFunction(QByteArrayLiteral("qt_specularLightProcessor")))
334 fragmentShader.addDefinition("QSSG_CUSTOM_MATERIAL_SPECULAR_PROCESSOR", "1");
335 if (hasCustomFunction(QByteArrayLiteral("qt_iblProbeProcessor")))
336 fragmentShader.addDefinition("QSSG_CUSTOM_MATERIAL_IBL_PROBE_PROCESSOR", "1");
337 if (hasCustomFunction(QByteArrayLiteral("qt_ambientLightProcessor")))
338 fragmentShader.addDefinition("QSSG_CUSTOM_MATERIAL_AMBIENT_LIGHT_PROCESSOR", "1");
339 if (hasCustomFunction(QByteArrayLiteral("qt_postProcessor")))
340 fragmentShader.addDefinition("QSSG_CUSTOM_MATERIAL_POST_PROCESSOR", "1");
341 }
342
343 if (materialAdapter->usesSharedVariables())
344 fragmentShader.addDefinition("QSSG_CUSTOM_MATERIAL_SHARED_VARIABLES", "1");
345
346 if (keyProps.m_hasShadows.getValue(inKey))
347 fragmentShader.addDefinition("QSSG_ENABLE_SHADOWMAPPING", "1");
348 if (keyProps.m_specularEnabled.getValue(inKey))
349 fragmentShader.addDefinition("QSSG_ENABLE_SPECULAR", "1");
350 if (keyProps.m_clearcoatEnabled.getValue(inKey))
351 fragmentShader.addDefinition("QSSG_ENABLE_CLEARCOAT", "1");
352 if (keyProps.m_transmissionEnabled.getValue(inKey))
353 fragmentShader.addDefinition("QSSG_ENABLE_TRANSMISSION", "1");
354 if (keyProps.m_metallicRoughnessEnabled.getValue(inKey))
355 fragmentShader.addDefinition("QSSG_ENABLE_METALLIC_ROUGHNESS_WORKFLOW", "1");
356 if (keyProps.m_specularGlossyEnabled.getValue(inKey))
357 fragmentShader.addDefinition("QSSG_ENABLE_SPECULAR_GLOSSY_WORKFLOW", "1");
358 switch (keyProps.m_diffuseModel.getDiffuseModel(inKey)) {
359 case QSSGRenderDefaultMaterial::MaterialDiffuseModel::Burley:
360 fragmentShader.addDefinition("QSSG_ENABLE_DIFFUSE_MODEL_BURLEY", "1");
361 break;
362 case QSSGRenderDefaultMaterial::MaterialDiffuseModel::Lambert:
363 fragmentShader.addDefinition("QSSG_ENABLE_DIFFUSE_MODEL_LAMBERT", "1");
364 break;
365 case QSSGRenderDefaultMaterial::MaterialDiffuseModel::LambertWrap:
366 fragmentShader.addDefinition("QSSG_ENABLE_DIFFUSE_MODEL_LAMBERT_WRAP", "1");
367 break;
368 }
369 switch (keyProps.m_specularModel.getSpecularModel(inKey)) {
370 case QSSGRenderDefaultMaterial::MaterialSpecularModel::BlinnPhong:
371 fragmentShader.addDefinition("QSSG_ENABLE_SPECULAR_MODEL_BLINN_PHONG", "1");
372 break;
373 case QSSGRenderDefaultMaterial::MaterialSpecularModel::SchlickGGX:
374 fragmentShader.addDefinition("QSSG_ENABLE_SPECULAR_MODEL_SCHLICK_GGX", "1");
375 break;
376 }
377 // Shadow softness
378 switch (keyProps.m_shadowSoftness.getShadowSoftness(inKey)) {
379 case QSSGRenderLight::SoftShadowQuality::Hard:
380 fragmentShader.addDefinition("QSSG_SHADOW_SOFTNESS", "0");
381 break;
382 case QSSGRenderLight::SoftShadowQuality::PCF4:
383 fragmentShader.addDefinition("QSSG_SHADOW_SOFTNESS", "4");
384 break;
385 case QSSGRenderLight::SoftShadowQuality::PCF8:
386 fragmentShader.addDefinition("QSSG_SHADOW_SOFTNESS", "8");
387 break;
388 case QSSGRenderLight::SoftShadowQuality::PCF16:
389 case QSSGRenderLight::SoftShadowQuality::PCF32:
390 case QSSGRenderLight::SoftShadowQuality::PCF64:
391 fragmentShader.addDefinition("QSSG_SHADOW_SOFTNESS", "16");
392 break;
393 ;}
394
395
396}
397
400 bool m_isActive = false;
402
403 // Use shared texcoord when transforms are identity
407
409 {
410 switch (type) {
411 case QSSGRenderableImage::Type::Diffuse:
412 return QSSGShaderDefaultMaterialKeyProperties::ImageMapNames::DiffuseMap;
413 case QSSGRenderableImage::Type::Opacity:
414 return QSSGShaderDefaultMaterialKeyProperties::ImageMapNames::OpacityMap;
415 case QSSGRenderableImage::Type::Specular:
416 return QSSGShaderDefaultMaterialKeyProperties::ImageMapNames::SpecularMap;
417 case QSSGRenderableImage::Type::Emissive:
418 return QSSGShaderDefaultMaterialKeyProperties::ImageMapNames::EmissiveMap;
419 case QSSGRenderableImage::Type::Bump:
420 return QSSGShaderDefaultMaterialKeyProperties::ImageMapNames::BumpMap;
421 case QSSGRenderableImage::Type::SpecularAmountMap:
422 return QSSGShaderDefaultMaterialKeyProperties::ImageMapNames::SpecularAmountMap;
423 case QSSGRenderableImage::Type::Normal:
424 return QSSGShaderDefaultMaterialKeyProperties::ImageMapNames::NormalMap;
425 case QSSGRenderableImage::Type::Translucency:
426 return QSSGShaderDefaultMaterialKeyProperties::ImageMapNames::TranslucencyMap;
427 case QSSGRenderableImage::Type::Roughness:
428 return QSSGShaderDefaultMaterialKeyProperties::ImageMapNames::RoughnessMap;
429 case QSSGRenderableImage::Type::BaseColor:
430 return QSSGShaderDefaultMaterialKeyProperties::ImageMapNames::BaseColorMap;
431 case QSSGRenderableImage::Type::Metalness:
432 return QSSGShaderDefaultMaterialKeyProperties::ImageMapNames::MetalnessMap;
433 case QSSGRenderableImage::Type::Occlusion:
434 return QSSGShaderDefaultMaterialKeyProperties::ImageMapNames::OcclusionMap;
435 case QSSGRenderableImage::Type::Height:
436 return QSSGShaderDefaultMaterialKeyProperties::ImageMapNames::HeightMap;
437 case QSSGRenderableImage::Type::Clearcoat:
438 return QSSGShaderDefaultMaterialKeyProperties::ImageMapNames::ClearcoatMap;
439 case QSSGRenderableImage::Type::ClearcoatRoughness:
440 return QSSGShaderDefaultMaterialKeyProperties::ImageMapNames::ClearcoatRoughnessMap;
441 case QSSGRenderableImage::Type::ClearcoatNormal:
442 return QSSGShaderDefaultMaterialKeyProperties::ImageMapNames::ClearcoatNormalMap;
443 case QSSGRenderableImage::Type::Transmission:
444 return QSSGShaderDefaultMaterialKeyProperties::ImageMapNames::TransmissionMap;
445 case QSSGRenderableImage::Type::Thickness:
446 return QSSGShaderDefaultMaterialKeyProperties::ImageMapNames::ThicknessMap;
447 case QSSGRenderableImage::Type::Unknown:
448 break;
449 }
450 return {};
451 }
452
453 SamplerState(const QSSGShaderDefaultMaterialKey &inKey, const QSSGShaderDefaultMaterialKeyProperties &keyProps)
454 : m_inKey(inKey)
456 {
457 for (int i = 0; i < QSSGShaderDefaultMaterialKeyProperties::ImageMapNames::ImageMapCount; ++i) {
458 const QSSGShaderDefaultMaterialKeyProperties::ImageMapNames mapName = QSSGShaderDefaultMaterialKeyProperties::ImageMapNames(i);
459 const QSSGShaderKeyImageMap &mapValue = m_keyProps.m_imageMaps[mapName];
460 // just check if any are enabled
461 if (mapValue.isEnabled(m_inKey))
462 m_isActive = true;
463 }
464 }
465
466 bool isActive() const { return m_isActive; }
467
468 bool hasImage(QSSGRenderableImage::Type type) const
469 {
470 if (auto imageType = fromType(type))
471 return m_keyProps.m_imageMaps[*imageType].isEnabled(m_inKey);
472
473 return false;
474 }
475
476 bool uvGenerated(QSSGShaderDefaultMaterialKeyProperties::ImageMapNames imageType) const
477 {
478 if (imageType < 0 || imageType >= QSSGShaderDefaultMaterialKeyProperties::ImageMapNames::ImageMapCount)
479 return false;
480 return uvCoordinatesGenerated[size_t(imageType)];
481 }
482
483 void generateImageUVAndSampler(QSSGRenderableImage::Type imageType,
484 QSSGMaterialVertexPipeline &vertexShader,
485 QSSGStageGeneratorBase &fragmentShader,
486 const QSSGShaderDefaultMaterialKey &key,
487 bool forceFragmentShader = false)
488 {
489 if (auto mapType = fromType(imageType)) {
490 if (uvGenerated(*mapType))
491 return; // don't do it a second time
492
493 const QSSGShaderKeyImageMap &mapValue = m_keyProps.m_imageMaps[size_t(*mapType)];
494 const quint8 indexUV = mapValue.isUsingUV1(m_inKey) ? 1 : 0;
495 const auto &samplerNames = imageStringTable[int(imageType)]; // using the QSSGRenderableImage::Type
496 if (mapValue.isIdentityTransform(m_inKey)) {
497 generateImageUVSampler(vertexShader, fragmentShader, key, samplerNames, imageFragCoords, indexUV);
498 } else {
500 // The frist time we need to declare the shared variable
501 fragmentShader.append(" vec3 qt_uTransform;");
502 fragmentShader.append(" vec3 qt_vTransform;");
504 }
505 generateImageUVCoordinates(vertexShader, fragmentShader, key, samplerNames, forceFragmentShader, indexUV, false, mapValue.isEnvMap(m_inKey) || mapValue.isLightProbe(m_inKey));
506 }
507 uvCoordinatesGenerated[int(*mapType)] = true;
508 }
509 }
510
511 const char *samplerName(QSSGRenderableImage::Type imageType) const
512 {
513 if (imageType <= QSSGRenderableImage::Type::Unknown)
514 return "";
515 return imageStringTable[int(imageType)].imageSampler;
516 }
517
518 const char *fragCoordsName(QSSGRenderableImage::Type imageType) const
519 {
520 if (auto mapType = fromType(imageType)) {
521 if (!uvGenerated(*mapType))
522 qWarning("Requesting image frag coords for image type %d that has not been generated", int(imageType));
523
524 const QSSGShaderKeyImageMap &mapValue = m_keyProps.m_imageMaps[size_t(*mapType)];
525 if (mapValue.isIdentityTransform(m_inKey))
526 return imageFragCoords;
527
528 return imageStringTable[int(imageType)].imageFragCoords;
529 }
530
531 return "";
532 }
533
534};
535
548
549 // Requirments for Pass
550 bool needsBaseColor = false; // qt_diffuseColor
551 bool needsRoughness = false; // qt_roughnessAmount
552 bool needsMetalness = false; // qt_metalnessAmount
553 bool needsDiffuseLight = false; // global_diffuse_light
554 bool needsSpecularLight = false; // global_specular_light
555 bool needsEmission = false; // global_emission
556 bool needsWorldNormal = false; // qt_world_normal
557 bool needsWorldTangent = false; // qt_world_tangent
558 bool needsWorldBinormal = false; // qt_world_binormal
559 bool needsF0 = false; // qt_f0
560 bool needsF90 = false; // qt_f90
561 bool needsAmbientOcclusion = false; // qt_ao_factor
562
563
564 // Available Information
565 bool hasVertexColors = false;
566 bool hasLighting = false;
567 bool hasPunctualLights = false;
568 bool hasSpecularLight = false;
569 bool hasIblProbe = false;
570 bool hasReflectionProbe = false;
571 bool hasIblOrientation = false;
572 bool hasShadowMap = false;
573 bool hasSSAOMap = false;
574 bool hasLightMap = false;
575 bool hasBumpNormalMap = false;
576 bool hasParallaxMapping = false;
577 bool hasClearcoat = false;
578 bool hasTransmission = false;
581 bool hasFog = false;
582
583
584 // Material Properties
585 bool isDoubleSided = false;
589 bool isPbrMaterial = false;
592 int viewCount = 1;
595
596 PassRequirmentsState(const QSSGShaderDefaultMaterialKey &inKey,
597 const QSSGShaderDefaultMaterialKeyProperties &keyProps,
598 const QSSGShaderFeatures &featureSet,
599 const SamplerState &samplerState)
600 {
601 const bool isDepthPass = featureSet.isSet(QSSGShaderFeatures::Feature::DepthPass);
602 const bool isOrthoShadowPass = featureSet.isSet(QSSGShaderFeatures::Feature::OrthoShadowPass);
603 const bool isPerspectiveShadowPass = featureSet.isSet(QSSGShaderFeatures::Feature::PerspectiveShadowPass);
604 isOpaqueDepthPrePass = featureSet.isSet(QSSGShaderFeatures::Feature::OpaqueDepthPrePass);
605 const bool isNormalPass = featureSet.isSet(QSSGShaderFeatures::Feature::NormalPass);
606
607 hasVertexColors = keyProps.m_vertexColorsEnabled.getValue(inKey)
608 || keyProps.m_usesVarColor.getValue(inKey)
609 || keyProps.m_vertexColorsMaskEnabled.getValue(inKey)
610 || keyProps.m_usesInstancing.getValue(inKey)
611 || keyProps.m_blendParticles.getValue(inKey);
612 hasLighting = keyProps.m_hasLighting.getValue(inKey);
613 hasPunctualLights = keyProps.m_hasPunctualLights.getValue(inKey);
614 isDoubleSided = keyProps.m_isDoubleSided.getValue(inKey);
615 hasIblProbe = keyProps.m_hasIbl.getValue(inKey);
616 hasReflectionProbe = featureSet.isSet(QSSGShaderFeatures::Feature::ReflectionProbe);
617 oitMethod = static_cast<QSSGRenderLayer::OITMethod>(keyProps.m_orderIndependentTransparency.getValue(inKey));
618 isSpecularAAEnabled = keyProps.m_specularAAEnabled.getValue(inKey);
619
620 // TODO: Not sure I agree with the following, but this is the current behavior
621 hasSpecularLight |= keyProps.m_specularEnabled.getValue(inKey);
624 hasSpecularLight |= samplerState.hasImage(QSSGRenderableImage::Type::SpecularAmountMap);
625
626 hasIblOrientation = featureSet.isSet(QSSGShaderFeatures::Feature::IblOrientation);
627 hasShadowMap = featureSet.isSet(QSSGShaderFeatures::Feature::Ssm);
628 hasSSAOMap = featureSet.isSet(QSSGShaderFeatures::Feature::Ssao);
629 hasLightMap = featureSet.isSet(QSSGShaderFeatures::Feature::Lightmap);
630 hasBumpNormalMap = samplerState.hasImage(QSSGRenderableImage::Type::Normal) || samplerState.hasImage(QSSGRenderableImage::Type::Bump);
631 hasParallaxMapping = samplerState.hasImage(QSSGRenderableImage::Type::Height);
632 hasClearcoat = keyProps.m_clearcoatEnabled.getValue(inKey);
633 hasTransmission = keyProps.m_transmissionEnabled.getValue(inKey);
634 hasFresnelScaleBias = keyProps.m_fresnelScaleBiasEnabled.getValue(inKey);
635 hasClearcoatFresnelScaleBias = keyProps.m_clearcoatFresnelScaleBiasEnabled.getValue(inKey);
636 isMetallicRoughnessWorkflow = keyProps.m_metallicRoughnessEnabled.getValue(inKey);
637 isSpecularGlossinessWorkflow = keyProps.m_specularGlossyEnabled.getValue(inKey);
639 hasFog = keyProps.m_fogEnabled.getValue(inKey);
640 numMorphTargets = keyProps.m_targetCount.getValue(inKey);
641 viewCount = featureSet.isSet(QSSGShaderFeatures::Feature::DisableMultiView) ? 1 : keyProps.m_viewCount.getValue(inKey);
642
643 if (isDepthPass) {
644 passType = Depth;
646 needsBaseColor = true;
647 } else if (isOrthoShadowPass) {
650 needsBaseColor = true;
651 } else if (isPerspectiveShadowPass) {
654 needsBaseColor = true;
655 } else if (isNormalPass) {
657 needsWorldNormal = true;
658 needsRoughness = true;
659 } else {
660 // Either a Color or Debug Pass
661 passType = Color;
662 debugMode = QSSGRenderLayer::MaterialDebugMode(keyProps.m_debugMode.getValue(inKey));
663 if (debugMode == QSSGRenderLayer::MaterialDebugMode::None) {
664 needsBaseColor = true;
665 needsRoughness = true;
666 needsMetalness = true;
667 needsDiffuseLight = true;
668 needsSpecularLight = true;
669 needsEmission = true;
670 needsWorldNormal = true;
671 needsWorldTangent = true;
672 needsWorldBinormal = true;
673 needsF0 = true;
674 needsF90 = true;
676 } else {
677 passType = Debug;
678 switch (debugMode) {
679 case QSSGRenderLayer::MaterialDebugMode::None:
680 break;
681 case QSSGRenderLayer::MaterialDebugMode::BaseColor:
682 needsBaseColor = true;
683 break;
684 case QSSGRenderLayer::MaterialDebugMode::Roughness:
685 needsRoughness = true;
686 break;
687 case QSSGRenderLayer::MaterialDebugMode::Metalness:
688 needsMetalness = true;
689 break;
690 case QSSGRenderLayer::MaterialDebugMode::Diffuse:
691 needsBaseColor = true;
692 needsRoughness = true;
693 needsMetalness = true;
694 needsDiffuseLight = true;
695 needsEmission = true;
696 needsWorldNormal = true;
697 needsWorldTangent = true;
698 needsWorldBinormal = true;
699 needsF0 = true;
700 needsF90 = true;
702 break;
703 case QSSGRenderLayer::MaterialDebugMode::Specular:
704 needsBaseColor = true;
705 needsRoughness = true;
706 needsMetalness = true;
707 needsSpecularLight = true;
708 needsEmission = true;
709 needsWorldNormal = true;
710 needsWorldTangent = true;
711 needsWorldBinormal = true;
712 needsF0 = true;
713 needsF90 = true;
715 break;
716 case QSSGRenderLayer::MaterialDebugMode::ShadowOcclusion:
717 break;
718 case QSSGRenderLayer::MaterialDebugMode::Emission:
719 needsEmission = true;
720 break;
721 case QSSGRenderLayer::MaterialDebugMode::AmbientOcclusion:
723 break;
724 case QSSGRenderLayer::MaterialDebugMode::Normal:
725 needsWorldNormal = true;
726 break;
727 case QSSGRenderLayer::MaterialDebugMode::Tangent:
728 needsWorldTangent = true;
729 break;
730 case QSSGRenderLayer::MaterialDebugMode::Binormal:
731 needsWorldBinormal = true;
732 break;
733 case QSSGRenderLayer::MaterialDebugMode::F0:
734 needsBaseColor = true;
735 needsRoughness = true;
736 needsMetalness = true;
737 needsSpecularLight = true;
738 needsEmission = true;
739 needsWorldNormal = true;
740 needsWorldTangent = true;
741 needsWorldBinormal = true;
742 needsF0 = true;
743 needsF90 = true;
745 break;
746 }
747 }
748 }
749 }
750
753 return true;
754 return false;
755 }
756
760
761};
762
763
764static void generateFragmentShader(QSSGStageGeneratorBase &fragmentShader,
765 QSSGMaterialVertexPipeline &vertexShader,
766 const QSSGShaderDefaultMaterialKey &inKey,
767 const QSSGShaderDefaultMaterialKeyProperties &keyProps,
768 const QSSGShaderFeatures &featureSet,
769 const QSSGRenderGraphObject &inMaterial,
770 QSSGShaderLibraryManager &shaderLibraryManager)
771{
772 QSSGShaderMaterialAdapter *materialAdapter = getMaterialAdapter(inMaterial);
773 auto hasCustomFunction = [&shaderLibraryManager, materialAdapter](const QByteArray &funcName) {
774 return materialAdapter->hasCustomShaderFunction(QSSGShaderCache::ShaderType::Fragment,
775 funcName,
776 shaderLibraryManager);
777 };
778
779 auto channelStr = [](const QSSGShaderKeyTextureChannel &chProp, const QSSGShaderDefaultMaterialKey &inKey) -> QByteArray {
780 QByteArray ret;
781 switch (chProp.getTextureChannel(inKey)) {
782 case QSSGShaderKeyTextureChannel::R:
783 ret.append(".r");
784 break;
785 case QSSGShaderKeyTextureChannel::G:
786 ret.append(".g");
787 break;
788 case QSSGShaderKeyTextureChannel::B:
789 ret.append(".b");
790 break;
791 case QSSGShaderKeyTextureChannel::A:
792 ret.append(".a");
793 break;
794 }
795 return ret;
796 };
797
798 auto maskVariableByVertexColorChannel = [&fragmentShader, keyProps, inKey]( const QByteArray &maskVariable, const QSSGRenderDefaultMaterial::VertexColorMask &maskEnum ){
799 if (keyProps.m_vertexColorsMaskEnabled.getValue(inKey)) {
800 if ( keyProps.m_vertexColorRedMask.getValue(inKey) & maskEnum )
801 fragmentShader << " " << maskVariable << " *= qt_vertColorMask.r;\n";
802 else if ( keyProps.m_vertexColorGreenMask.getValue(inKey) & maskEnum )
803 fragmentShader << " " << maskVariable << " *= qt_vertColorMask.g;\n";
804 else if ( keyProps.m_vertexColorBlueMask.getValue(inKey) & maskEnum )
805 fragmentShader << " " << maskVariable << " *= qt_vertColorMask.b;\n";
806 else if ( keyProps.m_vertexColorAlphaMask.getValue(inKey) & maskEnum )
807 fragmentShader << " " << maskVariable << " *= qt_vertColorMask.a;\n";
808 }
809 };
810
811 generateFragmentDefines(fragmentShader, inKey, keyProps, materialAdapter, shaderLibraryManager);
812
813 // Determine the available texture channels
814 SamplerState samplerState(inKey, keyProps);
815 // Determine the requirements of this rendering pass
816 const PassRequirmentsState passRequirmentState(inKey, keyProps, featureSet, samplerState);
817
818 const bool hasCustomVert = materialAdapter->hasCustomShaderSnippet(QSSGShaderCache::ShaderType::Vertex);
819
820 const int viewCount = featureSet.isSet(QSSGShaderFeatures::Feature::DisableMultiView)
821 ? 1 : keyProps.m_viewCount.getValue(inKey);
822
823 // Morphing
824 if (passRequirmentState.numMorphTargets > 0 || hasCustomVert) {
825 vertexShader.addDefinition(QByteArrayLiteral("QT_MORPH_MAX_COUNT"),
826 QByteArray::number(passRequirmentState.numMorphTargets));
827 quint8 offset;
828 if ((offset = keyProps.m_targetPositionOffset.getValue(inKey)) < UINT8_MAX) {
829 vertexShader.addDefinition(QByteArrayLiteral("QT_TARGET_POSITION_OFFSET"),
830 QByteArray::number(offset));
831 }
832 if ((offset = keyProps.m_targetNormalOffset.getValue(inKey)) < UINT8_MAX) {
833 vertexShader.addDefinition(QByteArrayLiteral("QT_TARGET_NORMAL_OFFSET"),
834 QByteArray::number(offset));
835 }
836 if ((offset = keyProps.m_targetTangentOffset.getValue(inKey)) < UINT8_MAX) {
837 vertexShader.addDefinition(QByteArrayLiteral("QT_TARGET_TANGENT_OFFSET"),
838 QByteArray::number(offset));
839 }
840 if ((offset = keyProps.m_targetBinormalOffset.getValue(inKey)) < UINT8_MAX) {
841 vertexShader.addDefinition(QByteArrayLiteral("QT_TARGET_BINORMAL_OFFSET"),
842 QByteArray::number(offset));
843 }
844 if ((offset = keyProps.m_targetTexCoord0Offset.getValue(inKey)) < UINT8_MAX) {
845 vertexShader.addDefinition(QByteArrayLiteral("QT_TARGET_TEX0_OFFSET"),
846 QByteArray::number(offset));
847 }
848 if ((offset = keyProps.m_targetTexCoord1Offset.getValue(inKey)) < UINT8_MAX) {
849 vertexShader.addDefinition(QByteArrayLiteral("QT_TARGET_TEX1_OFFSET"),
850 QByteArray::number(offset));
851 }
852 if ((offset = keyProps.m_targetColorOffset.getValue(inKey)) < UINT8_MAX) {
853 vertexShader.addDefinition(QByteArrayLiteral("QT_TARGET_COLOR_OFFSET"),
854 QByteArray::number(offset));
855 }
856 }
857
858 // Unshaded custom materials need no code in main (apart from calling qt_customMain)
859 const bool hasCustomFrag = materialAdapter->hasCustomShaderSnippet(QSSGShaderCache::ShaderType::Fragment);
860 const bool usesSharedVar = materialAdapter->usesSharedVariables();
861
862 vertexShader.beginFragmentGeneration(shaderLibraryManager, passRequirmentState.oitMethod);
863
864 if (passRequirmentState.passType == PassRequirmentsState::OrthoShadow) {
865 vertexShader.generateDepth();
866 fragmentShader.addUniform("qt_shadowDepthAdjust", "vec2");
867 }
868
869
870 if (passRequirmentState.passType == PassRequirmentsState::PerspectiveShadow)
871 vertexShader.generateShadowWorldPosition(inKey);
872
873
874 if (hasCustomFrag && materialAdapter->isUnshaded()) {
875 // Unlike the depth texture pass, the normal texture pass needs to
876 // output valid fragment values. The custom main is skipped in
877 // beginVertexGeneration if isNormalPass is true, but something must be
878 // written to gl_FragColor (the normals), so pretend we are shaded...
879 // if (passRequirmentState.passType != PassRequirmentsState::Normal)
880 return;
881 }
882
883 // hasCustomFrag == Shaded custom material from this point on, for Unshaded we returned above
884
885 // The fragment or vertex shaders may not use the material_properties or diffuse
886 // uniforms in all cases but it is simpler to just add them and let the linker strip them.
887 // if (passRequirmentState.needsEmission)
888 fragmentShader.addUniform("qt_material_emissive_color", "vec3");
889 // if (passRequirmentState.needsBaseColor)
890 fragmentShader.addUniform("qt_material_base_color", "vec4");
891 fragmentShader.addUniform("qt_material_properties", "vec4");
892 fragmentShader.addUniform("qt_material_properties2", "vec4");
893 fragmentShader.addUniform("qt_material_properties3", "vec4");
894 if (passRequirmentState.hasParallaxMapping || passRequirmentState.hasTransmission)
895 fragmentShader.addUniform("qt_material_properties4", "vec4");
896 if (!hasCustomFrag) {
897 if (passRequirmentState.hasTransmission) {
898 fragmentShader.addUniform("qt_material_attenuation", "vec4");
899 fragmentShader.addUniform("qt_material_thickness", "float");
900 }
901 if (passRequirmentState.hasFresnelScaleBias || passRequirmentState.hasClearcoatFresnelScaleBias)
902 fragmentShader.addUniform("qt_material_properties5", "vec4");
903 fragmentShader.addUniform("qt_material_clearcoat_normal_strength", "float");
904 fragmentShader.addUniform("qt_material_clearcoat_fresnel_power", "float");
905 }
906
907 if (passRequirmentState.hasVertexColors) {
908 vertexShader.generateVertexColor(inKey);
909 }else {
910 fragmentShader.append(" vec4 qt_vertColorMask = vec4(1.0);");
911 fragmentShader.append(" vec4 qt_vertColor = vec4(1.0);");
912 }
913
914 if (passRequirmentState.needsWorldNormal || passRequirmentState.needsWorldTangent || passRequirmentState.needsWorldBinormal || hasCustomFrag) {
915 vertexShader.generateViewVector(inKey);
916 if (keyProps.m_usesProjectionMatrix.getValue(inKey)) {
917 if (viewCount >= 2)
918 fragmentShader.addUniformArray("qt_projectionMatrix", "mat4", viewCount);
919 else
920 fragmentShader.addUniform("qt_projectionMatrix", "mat4");
921 }
922 if (keyProps.m_usesInverseProjectionMatrix.getValue(inKey)) {
923 if (viewCount >= 2)
924 fragmentShader.addUniformArray("qt_inverseProjectionMatrix", "mat4", viewCount);
925 else
926 fragmentShader.addUniform("qt_inverseProjectionMatrix", "mat4");
927 }
928 vertexShader.generateWorldNormal(inKey);
929 vertexShader.generateWorldPosition(inKey);
930
931 if (passRequirmentState.needsWorldTangent || passRequirmentState.needsWorldBinormal || hasCustomFrag) {
932 bool genTangent = false;
933 bool genBinormal = false;
934 vertexShader.generateVarTangentAndBinormal(inKey, genTangent, genBinormal);
935
936 if (!genTangent) {
937 QSSGRenderableImage::Type id = QSSGRenderableImage::Type::Unknown;
938 if (passRequirmentState.hasBumpNormalMap) {
939 // Generate imageCoords for bump/normal map first.
940 // Some operations needs to use the TBN transform and if the
941 // tangent vector is not provided, it is necessary.
942 id = samplerState.hasImage(QSSGRenderableImage::Type::Bump) ? QSSGRenderableImage::Type::Bump : QSSGRenderableImage::Type::Normal;
943 } else if (samplerState.hasImage(QSSGRenderableImage::Type::ClearcoatNormal)) {
944 // For the corner case that there is only a clearcoat normal map
945 id = QSSGRenderableImage::Type::ClearcoatNormal;
946 }
947
948 if (id > QSSGRenderableImage::Type::Unknown) {
949 samplerState.generateImageUVAndSampler(id, vertexShader, fragmentShader, inKey, true);
950 fragmentShader << " vec2 dUVdx = dFdx(" << samplerState.fragCoordsName(id) << ");\n"
951 << " vec2 dUVdy = dFdy(" << samplerState.fragCoordsName(id) << ");\n";
952 fragmentShader << " qt_tangent = (dUVdy.y * dFdx(qt_varWorldPos) - dUVdx.y * dFdy(qt_varWorldPos)) / (dUVdx.x * dUVdy.y - dUVdx.y * dUVdy.x);\n"
953 << " qt_tangent = qt_tangent - dot(qt_world_normal, qt_tangent) * qt_world_normal;\n"
954 << " qt_tangent = normalize(qt_tangent);\n";
955 }
956 }
957 if (!genBinormal)
958 fragmentShader << " qt_binormal = cross(qt_world_normal, qt_tangent);\n";
959 }
960
961 if (passRequirmentState.isDoubleSided) {
962 fragmentShader.append("#if QSHADER_HLSL && QSHADER_VIEW_COUNT >= 2");
963 fragmentShader.append(" const float qt_facing = 1.0;");
964 fragmentShader.append("#else");
965 fragmentShader.append(" const float qt_facing = gl_FrontFacing ? 1.0 : -1.0;");
966 fragmentShader.append("#endif");
967 fragmentShader.append(" qt_world_normal *= qt_facing;\n");
968 if (passRequirmentState.needsWorldTangent || passRequirmentState.needsWorldBinormal || hasCustomFrag) {
969 fragmentShader.append(" qt_tangent *= qt_facing;");
970 fragmentShader.append(" qt_binormal *= qt_facing;");
971 }
972 }
973 }
974
975 if (hasCustomFrag) {
976 // A custom shaded material is effectively a principled material for
977 // our purposes here. The defaults are different from a
978 // PrincipledMaterial however, since this is more sensible here.
979 // (because the shader has to state it to get things)
980 // These should match the defaults of PrincipledMaterial.
981 fragmentShader << " float qt_customOcclusionAmount = 1.0;\n";
982 fragmentShader << " float qt_customIOR = 1.5;\n";
983 fragmentShader << " float qt_customSpecularAmount = 0.5;\n"; // overrides qt_material_properties.x
984 fragmentShader << " float qt_customSpecularRoughness = 0.0;\n"; // overrides qt_material_properties.y
985 fragmentShader << " float qt_customMetalnessAmount = 0.0;\n"; // overrides qt_material_properties.z
986 fragmentShader << " float qt_customFresnelPower = 5.0;\n"; // overrides qt_material_properties2.x
987 fragmentShader << " vec4 qt_customBaseColor = vec4(1.0);\n"; // overrides qt_material_base_color
988 fragmentShader << " vec3 qt_customEmissiveColor = vec3(0.0);\n"; // overrides qt_material_emissive_color
989 if (passRequirmentState.hasClearcoat) {
990 fragmentShader << " float qt_customClearcoatAmount = 0.0;\n";
991 fragmentShader << " float qt_customClearcoatFresnelPower = 5.0;\n";
992 fragmentShader << " float qt_customClearcoatRoughness = 0.0;\n";
993 fragmentShader << " vec3 qt_customClearcoatNormal = qt_world_normal;\n";
994 if (passRequirmentState.hasClearcoatFresnelScaleBias) {
995 fragmentShader << " float qt_customClearcoatFresnelScale = 1.0;\n";
996 fragmentShader << " float qt_customClearcoatFresnelBias = 0.0;\n";
997 }
998 }
999 if (passRequirmentState.hasFresnelScaleBias) {
1000 fragmentShader << " float qt_customFresnelScale = 1.0;\n";
1001 fragmentShader << " float qt_customFresnelBias = 0.0;\n";
1002 }
1003
1004 if (passRequirmentState.hasTransmission) {
1005 fragmentShader << " float qt_customTransmissionFactor = 0.0;\n";
1006 fragmentShader << " float qt_customThicknessFactor = 0.0;\n";
1007 fragmentShader << " vec3 qt_customAttenuationColor = vec3(1.0);\n";
1008 fragmentShader << " float qt_customAttenuationDistance = 0.0;\n";
1009 }
1010 if (usesSharedVar)
1011 fragmentShader << " QT_SHARED_VARS qt_customShared;\n";
1012 // Generate the varyings for UV0 and UV1 since customer materials don't use image
1013 // properties directly.
1014 vertexShader.generateUVCoords(0, inKey);
1015 vertexShader.generateUVCoords(1, inKey);
1016 if (passRequirmentState.shouldIncludeCustomFragmentMain() && hasCustomFunction(QByteArrayLiteral("qt_customMain"))) {
1017 fragmentShader << " qt_customMain(qt_customBaseColor,\n"
1018 << " qt_customEmissiveColor,\n"
1019 << " qt_customMetalnessAmount,\n"
1020 << " qt_customSpecularRoughness,\n"
1021 << " qt_customSpecularAmount,\n"
1022 << " qt_customFresnelPower,\n"
1023 << " qt_world_normal,\n"
1024 << " qt_tangent,\n"
1025 << " qt_binormal,\n"
1026 << " qt_texCoord0,\n"
1027 << " qt_texCoord1,\n"
1028 << " qt_view_vector,\n"
1029 << " qt_customIOR,\n"
1030 << " qt_customOcclusionAmount";
1031 if (passRequirmentState.hasClearcoat) {
1032 fragmentShader << ",\n qt_customClearcoatAmount,\n"
1033 << " qt_customClearcoatFresnelPower,\n"
1034 << " qt_customClearcoatRoughness,\n"
1035 << " qt_customClearcoatNormal";
1036 if (passRequirmentState.hasClearcoatFresnelScaleBias) {
1037 fragmentShader << ",\n qt_customClearcoatFresnelScale,\n"
1038 << " qt_customClearcoatFresnelBias";
1039 }
1040 }
1041 if (passRequirmentState.hasFresnelScaleBias) {
1042 fragmentShader << ",\n qt_customFresnelScale,\n"
1043 << " qt_customFresnelBias";
1044 }
1045 if (passRequirmentState.hasTransmission) {
1046 fragmentShader << ",\n qt_customTransmissionFactor,\n"
1047 << " qt_customThicknessFactor,\n"
1048 << " qt_customAttenuationColor,\n"
1049 << " qt_customAttenuationDistance";
1050 }
1051 if (usesSharedVar)
1052 fragmentShader << "\n, qt_customShared);\n";
1053 else
1054 fragmentShader << ");\n";
1055 }
1056 fragmentShader << " vec4 qt_diffuseColor = qt_customBaseColor * qt_vertColor;\n";
1057 fragmentShader << " vec3 qt_global_emission = qt_customEmissiveColor;\n";
1058 fragmentShader << " float qt_iOR = qt_customIOR;\n";
1059 } else {
1060 fragmentShader << " vec4 qt_diffuseColor = qt_material_base_color * qt_vertColor;\n";
1061 fragmentShader << " vec3 qt_global_emission = qt_material_emissive_color;\n";
1062 if (passRequirmentState.hasSpecularLight || samplerState.isActive())
1063 fragmentShader << " float qt_iOR = qt_material_specular.w;\n";
1064 }
1065
1066 const bool hasCustomIblProbe = hasCustomFrag && hasCustomFunction(QByteArrayLiteral("qt_iblProbeProcessor"));
1067
1068
1069 // Lightmaps
1070 // hasLighting && needsDiffuseLight || needsSpecularLight
1071 if (passRequirmentState.hasLighting && (passRequirmentState.needsDiffuseLight || passRequirmentState.needsSpecularLight)) {
1072 if (passRequirmentState.hasLightMap) {
1073 vertexShader.generateLightmapUVCoords(inKey);
1074 fragmentShader.addFunction("lightmap");
1075 }
1076 }
1077
1078 // Heightmap / Parallax Mapping
1079 // Possible Optimization: Also conditionally, only when we plan on using another map/texture since it only gets used when sampling
1080 if (passRequirmentState.hasParallaxMapping) {
1081 // Adjust UV coordinates to account for parallaxMapping before
1082 // reading any other texture.
1083 fragmentShader.addInclude("parallaxMapping.glsllib");
1084 samplerState.generateImageUVAndSampler(QSSGRenderableImage::Type::Height, vertexShader, fragmentShader, inKey, true);
1085 fragmentShader << " float qt_heightAmount = qt_material_properties4.x;\n";
1086 maskVariableByVertexColorChannel( "qt_heightAmount", QSSGRenderDefaultMaterial::HeightAmountMask );
1087 fragmentShader << " qt_texCoord0 = qt_parallaxMapping(" << samplerState.fragCoordsName(QSSGRenderableImage::Type::Height) << ",\n"
1088 << " " << samplerState.samplerName(QSSGRenderableImage::Type::Height) << ",\n"
1089 << " qt_tangent,\n"
1090 << " qt_binormal,\n"
1091 << " qt_world_normal,\n"
1092 << " qt_varWorldPos, \n"
1093 << "#if QSHADER_VIEW_COUNT >= 2\n"
1094 << " qt_cameraPosition[qt_viewIndex],\n"
1095 << "#else\n"
1096 << " qt_cameraPosition,\n"
1097 << "#endif\n"
1098 << " qt_heightAmount,\n"
1099 << " qt_material_properties4.y,\n"
1100 << " qt_material_properties4.z);\n";
1101 }
1102
1103 // Clearcoat (before normal/bump has a chance to overwrite qt_world_normal)
1104 if (passRequirmentState.hasClearcoat && (passRequirmentState.needsDiffuseLight || passRequirmentState.needsSpecularLight)) {
1105 addLocalVariable(fragmentShader, "qt_clearcoatNormal", "vec3");
1106 // Clearcoat normal should be calculated not considering the normalImage for the base material
1107 // If both are to be the same then just set the same normalImage for the base and clearcoat
1108 // This does mean that this value should be calculated before qt_world_normal is overwritten by
1109 // the normalMap.
1110 if (hasCustomFrag) {
1111 fragmentShader << " qt_clearcoatNormal = qt_customClearcoatNormal;\n";
1112 } else {
1113 if (samplerState.hasImage(QSSGRenderableImage::Type::ClearcoatNormal)) {
1114 samplerState.generateImageUVAndSampler(QSSGRenderableImage::Type::ClearcoatNormal, vertexShader, fragmentShader, inKey, passRequirmentState.hasParallaxMapping);
1115 fragmentShader.addFunction("sampleNormalTexture");
1116 fragmentShader << " float qt_clearcoat_normal_strength = qt_material_clearcoat_normal_strength;\n";
1117 maskVariableByVertexColorChannel( "qt_clearcoat_normal_strength", QSSGRenderDefaultMaterial::ClearcoatNormalStrengthMask );
1118 fragmentShader << " qt_clearcoatNormal = qt_sampleNormalTexture(" << samplerState.samplerName(QSSGRenderableImage::Type::ClearcoatNormal)
1119 << ", qt_clearcoat_normal_strength, "
1120 << samplerState.fragCoordsName(QSSGRenderableImage::Type::ClearcoatNormal)
1121 << ", qt_tangent, qt_binormal, qt_world_normal);\n";
1122
1123 } else {
1124 // same as qt_world_normal then
1125 fragmentShader << " qt_clearcoatNormal = qt_world_normal;\n";
1126 }
1127 }
1128 }
1129
1130 // Normal / Bump Map
1131 if (passRequirmentState.needsWorldNormal) {
1132 if (samplerState.hasImage(QSSGRenderableImage::Type::Bump)) {
1133 samplerState.generateImageUVAndSampler(QSSGRenderableImage::Type::Bump, vertexShader, fragmentShader, inKey, passRequirmentState.hasParallaxMapping);
1134 fragmentShader.append(" float qt_bumpAmount = qt_material_properties2.y;\n");
1135 maskVariableByVertexColorChannel( "qt_bumpAmount", QSSGRenderDefaultMaterial::NormalStrengthMask );
1136 fragmentShader.addInclude("defaultMaterialBumpNoLod.glsllib");
1137 fragmentShader << " qt_world_normal = qt_defaultMaterialBumpNoLod("
1138 << samplerState.samplerName(QSSGRenderableImage::Type::Bump)
1139 << ", qt_bumpAmount, " << samplerState.fragCoordsName(QSSGRenderableImage::Type::Bump)
1140 << ", qt_tangent, qt_binormal, qt_world_normal);\n";
1141 } else if (samplerState.hasImage(QSSGRenderableImage::Type::Normal)) {
1142 samplerState.generateImageUVAndSampler(QSSGRenderableImage::Type::Normal, vertexShader, fragmentShader, inKey, passRequirmentState.hasParallaxMapping);
1143 fragmentShader.append(" float qt_normalStrength = qt_material_properties2.y;\n");
1144 maskVariableByVertexColorChannel( "qt_normalStrength", QSSGRenderDefaultMaterial::NormalStrengthMask );
1145 fragmentShader.addFunction("sampleNormalTexture");
1146 fragmentShader << " qt_world_normal = qt_sampleNormalTexture(" << samplerState.samplerName(QSSGRenderableImage::Type::Normal)
1147 << ", qt_normalStrength, " << samplerState.fragCoordsName(QSSGRenderableImage::Type::Normal)
1148 << ", qt_tangent, qt_binormal, qt_world_normal);\n";
1149 }
1150 }
1151
1152 // !hasLighting does not mean 'no light source'
1153 // it should be KHR_materials_unlit
1154 // https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_materials_unlit
1155 if ((passRequirmentState.hasLighting || passRequirmentState.passType == PassRequirmentsState::Normal) && passRequirmentState.needsWorldNormal) {
1156 fragmentShader.append(" vec3 tmp_light_color;");
1157 }
1158
1159 if (passRequirmentState.hasSpecularLight || samplerState.isActive()) {
1160 fragmentShader.append(" vec3 qt_specularBase;");
1161 fragmentShader.addUniform("qt_material_specular", "vec4");
1162 if (hasCustomFrag)
1163 fragmentShader.append(" vec3 qt_specularTint = vec3(1.0);");
1164 else
1165 fragmentShader.append(" vec3 qt_specularTint = qt_material_specular.rgb;");
1166 }
1167
1168 // Base Color / Diffuse / Albedo
1169 if ((samplerState.hasImage(QSSGRenderableImage::Type::BaseColor) || samplerState.hasImage(QSSGRenderableImage::Type::Diffuse)) && passRequirmentState.needsBaseColor) {
1170
1171 // first off, which one
1172 QSSGRenderableImage::Type baseImageType = QSSGRenderableImage::Type::Unknown;
1173 if (samplerState.hasImage(QSSGRenderableImage::Type::BaseColor))
1174 baseImageType = QSSGRenderableImage::Type::BaseColor;
1175 else if (samplerState.hasImage(QSSGRenderableImage::Type::Diffuse))
1176 baseImageType = QSSGRenderableImage::Type::Diffuse;
1177
1178 // Generate the UVs and sampler snippets
1179 samplerState.generateImageUVAndSampler(baseImageType, vertexShader, fragmentShader, inKey, passRequirmentState.hasParallaxMapping);
1180
1181 if (keyProps.m_baseColorSingleChannelEnabled.getValue(inKey)) {
1182 const auto &channelProps = keyProps.m_textureChannels[QSSGShaderDefaultMaterialKeyProperties::BaseColorChannel];
1183 fragmentShader << " vec4 qt_base_texture_color = vec4(vec3(texture2D(" << samplerState.samplerName(baseImageType)
1184 << ", " << samplerState.fragCoordsName(baseImageType) << ")" << channelStr(channelProps, inKey) << "), 1.0f);\n";
1185 } else {
1186 fragmentShader << " vec4 qt_base_texture_color = texture2D(" << samplerState.samplerName(baseImageType)
1187 << ", " << samplerState.fragCoordsName(baseImageType) << ");\n";
1188 }
1189 if (!keyProps.m_imageMaps[QSSGShaderDefaultMaterialKeyProperties::BaseColorMap].isLinear(inKey)) {
1190 // Diffuse/BaseColor maps need to converted to linear color space
1191 fragmentShader.addInclude("tonemapping.glsllib");
1192 fragmentShader << " qt_base_texture_color = qt_sRGBToLinear(qt_base_texture_color);\n";
1193 }
1194 fragmentShader << " qt_diffuseColor *= qt_base_texture_color;\n";
1195 }
1196
1197 // Alpha cutoff
1198 if (keyProps.m_alphaMode.getAlphaMode(inKey) == QSSGRenderDefaultMaterial::MaterialAlphaMode::Mask) {
1199 // The Implementation Notes from
1200 // https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#alpha-coverage
1201 // must be met. Hence the discard.
1202 fragmentShader << " if (qt_diffuseColor.a < qt_material_properties3.y) {\n"
1203 << " qt_diffuseColor = vec4(0.0);\n"
1204 << " discard;\n"
1205 << " } else {\n"
1206 << " qt_diffuseColor.a = 1.0;\n"
1207 << " }\n";
1208 } else if (keyProps.m_alphaMode.getAlphaMode(inKey) == QSSGRenderDefaultMaterial::MaterialAlphaMode::Opaque) {
1209 fragmentShader << " qt_diffuseColor.a = 1.0;\n";
1210 }
1211
1212 // Opacity
1213 if (samplerState.hasImage(QSSGRenderableImage::Type::Opacity)) {
1214 samplerState.generateImageUVAndSampler(QSSGRenderableImage::Type::Opacity, vertexShader, fragmentShader, inKey, passRequirmentState.hasParallaxMapping);
1215 const auto &channelProps = keyProps.m_textureChannels[QSSGShaderDefaultMaterialKeyProperties::OpacityChannel];
1216 fragmentShader << " float qt_opacity_map_value = texture2D(" << samplerState.samplerName(QSSGRenderableImage::Type::Opacity)
1217 << ", " << samplerState.fragCoordsName(QSSGRenderableImage::Type::Opacity) << ")" << channelStr(channelProps, inKey) << ";\n";
1218 if (keyProps.m_invertOpacityMapValue.getValue(inKey))
1219 fragmentShader << " qt_opacity_map_value = 1.0 - qt_opacity_map_value;\n";
1220 fragmentShader << " qt_objectOpacity *= qt_opacity_map_value;\n";
1221 }
1222
1223 // Ambient Occlusion
1224 if (passRequirmentState.needsAmbientOcclusion) {
1225 addLocalVariable(fragmentShader, "qt_aoFactor", "float");
1226
1227 if (passRequirmentState.hasSSAOMap) {
1228 fragmentShader.addInclude("ssao.glsllib");
1229 fragmentShader.append(" qt_aoFactor = qt_screenSpaceAmbientOcclusionFactor();");
1230 } else {
1231 fragmentShader.append(" qt_aoFactor = 1.0;");
1232 }
1233
1234 if (hasCustomFrag)
1235 fragmentShader << " qt_aoFactor *= qt_customOcclusionAmount;\n";
1236 }
1237
1238 // Roughness
1239 if (passRequirmentState.needsRoughness) {
1240 if (hasCustomFrag)
1241 fragmentShader << " float qt_roughnessAmount = qt_customSpecularRoughness;\n";
1242 else
1243 fragmentShader << " float qt_roughnessAmount = qt_material_properties.y;\n";
1244
1245 maskVariableByVertexColorChannel( "qt_roughnessAmount", QSSGRenderDefaultMaterial::RoughnessMask );
1246
1247 if (samplerState.hasImage(QSSGRenderableImage::Type::Roughness)) {
1248 samplerState.generateImageUVAndSampler(QSSGRenderableImage::Type::Roughness, vertexShader, fragmentShader, inKey, passRequirmentState.hasParallaxMapping);
1249 const auto &channelProps = keyProps.m_textureChannels[QSSGShaderDefaultMaterialKeyProperties::RoughnessChannel];
1250 fragmentShader << " qt_roughnessAmount *= texture2D(" << samplerState.samplerName(QSSGRenderableImage::Type::Roughness) << ", "
1251 << samplerState.fragCoordsName(QSSGRenderableImage::Type::Roughness) << ")" << channelStr(channelProps, inKey) << ";\n";
1252 }
1253
1254 // Convert Glossy to Roughness
1255 if (passRequirmentState.isSpecularGlossinessWorkflow)
1256 fragmentShader << " qt_roughnessAmount = clamp(1.0 - qt_roughnessAmount, 0.0, 1.0);\n";
1257 }
1258
1259 // Metalness
1260 if (passRequirmentState.needsMetalness) {
1261 if (hasCustomFrag)
1262 fragmentShader << " float qt_metalnessAmount = qt_customMetalnessAmount;\n";
1263 else if (!passRequirmentState.isSpecularGlossinessWorkflow)
1264 fragmentShader << " float qt_metalnessAmount = qt_material_properties.z;\n";
1265 else
1266 fragmentShader << " float qt_metalnessAmount = 0.0;\n";
1267
1268 maskVariableByVertexColorChannel( "qt_metalnessAmount", QSSGRenderDefaultMaterial::MetalnessMask );
1269
1270 if (passRequirmentState.hasSpecularLight && samplerState.hasImage(QSSGRenderableImage::Type::Metalness)) {
1271 const auto &channelProps = keyProps.m_textureChannels[QSSGShaderDefaultMaterialKeyProperties::MetalnessChannel];
1272 samplerState.generateImageUVAndSampler(QSSGRenderableImage::Type::Metalness, vertexShader, fragmentShader, inKey, passRequirmentState.hasParallaxMapping);
1273 fragmentShader << " float qt_sampledMetalness = texture2D(" << samplerState.samplerName(QSSGRenderableImage::Type::Metalness) << ", "
1274 << samplerState.fragCoordsName(QSSGRenderableImage::Type::Metalness) << ")" << channelStr(channelProps, inKey) << ";\n";
1275 fragmentShader << " qt_metalnessAmount = clamp(qt_metalnessAmount * qt_sampledMetalness, 0.0, 1.0);\n";
1276 }
1277 }
1278
1279 // Special case for depth pre-pass
1280 if (passRequirmentState.shouldDiscardNonOpaque()) {
1281 fragmentShader << " if ((qt_diffuseColor.a * qt_objectOpacity) < 1.0)\n";
1282 fragmentShader << " discard;\n";
1283 }
1284
1285 // This is a Lighting Pass
1286 if (passRequirmentState.hasLighting && (passRequirmentState.needsDiffuseLight || passRequirmentState.needsSpecularLight)) {
1287 if (passRequirmentState.hasSpecularLight) {
1288 vertexShader.generateViewVector(inKey);
1289 fragmentShader.addUniform("qt_material_properties", "vec4");
1290
1291 if (passRequirmentState.isPbrMaterial)
1292 fragmentShader << " qt_specularBase = vec3(1.0);\n";
1293 else
1294 fragmentShader << " qt_specularBase = qt_diffuseColor.rgb;\n";
1295 if (hasCustomFrag)
1296 fragmentShader << " float qt_specularFactor = qt_customSpecularAmount;\n";
1297 else
1298 fragmentShader << " float qt_specularFactor = qt_material_properties.x;\n";
1299
1300 maskVariableByVertexColorChannel( "qt_specularFactor", QSSGRenderDefaultMaterial::SpecularAmountMask );
1301 }
1302
1303 fragmentShader.addUniform("qt_light_ambient_total", "vec3");
1304
1305 fragmentShader.append(" vec4 global_diffuse_light = vec4(0.0);");
1306
1307 if (passRequirmentState.hasLightMap) {
1308 fragmentShader << " global_diffuse_light.rgb = qt_lightmap_color(qt_texCoordLightmap) * (1.0 - qt_metalnessAmount) * qt_diffuseColor.rgb;\n";
1309 } else {
1310 if (hasCustomFrag && hasCustomFunction(QByteArrayLiteral("qt_ambientLightProcessor"))) {
1311 // DIFFUSE, TOTAL_AMBIENT_COLOR, NORMAL, VIEW_VECTOR(, SHARED)
1312 fragmentShader.append(" qt_ambientLightProcessor(global_diffuse_light.rgb, qt_light_ambient_total.rgb * (1.0 - qt_metalnessAmount) * qt_diffuseColor.rgb, qt_world_normal, qt_view_vector");
1313 if (usesSharedVar)
1314 fragmentShader << ", qt_customShared);\n";
1315 else
1316 fragmentShader << ");\n";
1317 } else {
1318 fragmentShader.append(" global_diffuse_light = vec4(qt_light_ambient_total.rgb * (1.0 - qt_metalnessAmount) * qt_diffuseColor.rgb, 0.0);");
1319 }
1320 }
1321
1322 fragmentShader.append(" vec3 global_specular_light = vec3(0.0);");
1323
1324 // Fragment lighting means we can perhaps attenuate the specular amount by a texture
1325 // lookup.
1326 if (samplerState.hasImage(QSSGRenderableImage::Type::SpecularAmountMap)) {
1327 samplerState.generateImageUVAndSampler(QSSGRenderableImage::Type::SpecularAmountMap, vertexShader, fragmentShader, inKey, passRequirmentState.hasParallaxMapping);
1328
1329 if (keyProps.m_specularSingleChannelEnabled.getValue(inKey)) {
1330 const auto &channelProps = keyProps.m_textureChannels[QSSGShaderDefaultMaterialKeyProperties::SpecularAmountChannel];
1331 fragmentShader << " vec4 qt_specular_amount_map = vec4(vec3(texture2D(" << samplerState.samplerName(QSSGRenderableImage::Type::SpecularAmountMap)
1332 << ", " << samplerState.fragCoordsName(QSSGRenderableImage::Type::SpecularAmountMap) << ")" << channelStr(channelProps, inKey) << "), 1.0f);\n";
1333 } else {
1334 fragmentShader << " vec4 qt_specular_amount_map = texture2D(" << samplerState.samplerName(QSSGRenderableImage::Type::SpecularAmountMap)
1335 << ", " << samplerState.fragCoordsName(QSSGRenderableImage::Type::SpecularAmountMap) << ");\n";
1336 }
1337 fragmentShader << " qt_specularBase *= qt_sRGBToLinear(qt_specular_amount_map).rgb;\n";
1338 }
1339
1340 if (passRequirmentState.hasSpecularLight) {
1341 if (passRequirmentState.isSpecularGlossinessWorkflow) {
1342 fragmentShader << " qt_specularTint *= qt_specularBase;\n";
1343 fragmentShader << " vec3 qt_specularAmount = vec3(1.0);\n";
1344 } else {
1345 fragmentShader << " vec3 qt_specularAmount = qt_specularBase * vec3(qt_metalnessAmount + qt_specularFactor * (1.0 - qt_metalnessAmount));\n";
1346 }
1347 }
1348
1349 if (samplerState.hasImage(QSSGRenderableImage::Type::Translucency)) {
1350 samplerState.generateImageUVAndSampler(QSSGRenderableImage::Type::Translucency, vertexShader, fragmentShader, inKey, passRequirmentState.hasParallaxMapping);
1351 const auto &channelProps = keyProps.m_textureChannels[QSSGShaderDefaultMaterialKeyProperties::TranslucencyChannel];
1352 fragmentShader << " float qt_translucent_depth_range = texture2D(" << samplerState.samplerName(QSSGRenderableImage::Type::Translucency)
1353 << ", " << samplerState.fragCoordsName(QSSGRenderableImage::Type::Translucency) << ")" << channelStr(channelProps, inKey) << ";\n";
1354 fragmentShader << " float qt_translucent_thickness = qt_translucent_depth_range * qt_translucent_depth_range;\n";
1355 fragmentShader << " float qt_translucent_thickness_exp = exp(qt_translucent_thickness * qt_material_properties2.z);\n";
1356 }
1357
1358 // Occlusion Map
1359 if (samplerState.hasImage(QSSGRenderableImage::Type::Occlusion)) {
1360 addLocalVariable(fragmentShader, "qt_ao", "float");
1361 samplerState.generateImageUVAndSampler(QSSGRenderableImage::Type::Occlusion, vertexShader, fragmentShader, inKey, passRequirmentState.hasParallaxMapping);
1362 const auto &channelProps = keyProps.m_textureChannels[QSSGShaderDefaultMaterialKeyProperties::OcclusionChannel];
1363 fragmentShader << " qt_ao = texture2D(" << samplerState.samplerName(QSSGRenderableImage::Type::Occlusion) << ", "
1364 << samplerState.fragCoordsName(QSSGRenderableImage::Type::Occlusion) << ")" << channelStr(channelProps, inKey) << ";\n";
1365 fragmentShader << " qt_aoFactor *= qt_ao * qt_material_properties3.x;\n"; // qt_material_properties3.x is the OcclusionAmount
1366 maskVariableByVertexColorChannel( "qt_aoFactor", QSSGRenderDefaultMaterial::OcclusionAmountMask );
1367 }
1368
1369 if (passRequirmentState.hasClearcoat) {
1370 addLocalVariable(fragmentShader, "qt_clearcoatAmount", "float");
1371 addLocalVariable(fragmentShader, "qt_clearcoatRoughness", "float");
1372 addLocalVariable(fragmentShader, "qt_clearcoatF0", "vec3");
1373 addLocalVariable(fragmentShader, "qt_clearcoatF90", "vec3");
1374 addLocalVariable(fragmentShader, "qt_global_clearcoat", "vec3");
1375
1376 if (hasCustomFrag)
1377 fragmentShader << " qt_clearcoatAmount = qt_customClearcoatAmount;\n";
1378 else
1379 fragmentShader << " qt_clearcoatAmount = qt_material_properties3.z;\n";
1380 maskVariableByVertexColorChannel( "qt_clearcoatAmount", QSSGRenderDefaultMaterial::ClearcoatAmountMask );
1381 if (hasCustomFrag)
1382 fragmentShader << " qt_clearcoatRoughness = qt_customClearcoatRoughness;\n";
1383 else
1384 fragmentShader << " qt_clearcoatRoughness = qt_material_properties3.w;\n";
1385 maskVariableByVertexColorChannel( "qt_clearcoatRoughness", QSSGRenderDefaultMaterial::ClearcoatRoughnessAmountMask );
1386 fragmentShader << " qt_clearcoatF0 = vec3(((1.0-qt_iOR) * (1.0-qt_iOR)) / ((1.0+qt_iOR) * (1.0+qt_iOR)));\n";
1387 fragmentShader << " qt_clearcoatF90 = vec3(1.0);\n";
1388 fragmentShader << " qt_global_clearcoat = vec3(0.0);\n";
1389
1390 if (samplerState.hasImage(QSSGRenderableImage::Type::Clearcoat)) {
1391 samplerState.generateImageUVAndSampler(QSSGRenderableImage::Type::Clearcoat, vertexShader, fragmentShader, inKey, passRequirmentState.hasParallaxMapping);
1392 const auto &channelProps = keyProps.m_textureChannels[QSSGShaderDefaultMaterialKeyProperties::ClearcoatChannel];
1393 fragmentShader << " qt_clearcoatAmount *= texture2D(" << samplerState.samplerName(QSSGRenderableImage::Type::Clearcoat) << ", "
1394 << samplerState.fragCoordsName(QSSGRenderableImage::Type::Clearcoat) << ")" << channelStr(channelProps, inKey) << ";\n";
1395 }
1396
1397 if (samplerState.hasImage(QSSGRenderableImage::Type::ClearcoatRoughness)) {
1398 samplerState.generateImageUVAndSampler(QSSGRenderableImage::Type::ClearcoatRoughness, vertexShader, fragmentShader, inKey, passRequirmentState.hasParallaxMapping);
1399 const auto &channelProps = keyProps.m_textureChannels[QSSGShaderDefaultMaterialKeyProperties::ClearcoatRoughnessChannel];
1400 fragmentShader << " qt_clearcoatRoughness *= texture2D(" << samplerState.samplerName(QSSGRenderableImage::Type::ClearcoatRoughness) << ", "
1401 << samplerState.fragCoordsName(QSSGRenderableImage::Type::ClearcoatRoughness) << ")" << channelStr(channelProps, inKey) << ";\n";
1402 fragmentShader << " qt_clearcoatRoughness = clamp(qt_clearcoatRoughness, 0.0, 1.0);\n";
1403 }
1404 }
1405
1406 if (passRequirmentState.hasTransmission) {
1407 fragmentShader.addInclude("transmission.glsllib");
1408 addLocalVariable(fragmentShader, "qt_transmissionFactor", "float");
1409 addLocalVariable(fragmentShader, "qt_global_transmission", "vec3");
1410 // Volume
1411 addLocalVariable(fragmentShader, "qt_thicknessFactor", "float");
1412 addLocalVariable(fragmentShader, "qt_attenuationColor", "vec3");
1413 addLocalVariable(fragmentShader, "qt_attenuationDistance", "float");
1414 fragmentShader << " qt_global_transmission = vec3(0.0);\n";
1415
1416 if (hasCustomFrag) {
1417 fragmentShader << " qt_transmissionFactor = qt_customTransmissionFactor;\n";
1418 fragmentShader << " qt_thicknessFactor = qt_customThicknessFactor;\n";
1419 fragmentShader << " qt_attenuationColor = qt_customAttenuationColor;\n";
1420 fragmentShader << " qt_attenuationDistance = qt_customAttenuationDistance;\n";
1421 } else {
1422 fragmentShader << " qt_transmissionFactor = qt_material_properties4.w;\n";
1423 maskVariableByVertexColorChannel( "qt_transmissionFactor", QSSGRenderDefaultMaterial::TransmissionFactorMask );
1424
1425 if (samplerState.hasImage(QSSGRenderableImage::Type::Transmission)) {
1426 samplerState.generateImageUVAndSampler(QSSGRenderableImage::Type::Transmission, vertexShader, fragmentShader, inKey, passRequirmentState.hasParallaxMapping);
1427 const auto &channelProps = keyProps.m_textureChannels[QSSGShaderDefaultMaterialKeyProperties::TransmissionChannel];
1428 fragmentShader << " qt_transmissionFactor *= texture2D(" << samplerState.samplerName(QSSGRenderableImage::Type::Transmission) << ", "
1429 << samplerState.fragCoordsName(QSSGRenderableImage::Type::Transmission) << ")" << channelStr(channelProps, inKey) << ";\n";
1430 }
1431
1432 fragmentShader << " qt_thicknessFactor = qt_material_thickness;\n";
1433 maskVariableByVertexColorChannel( "qt_thicknessFactor", QSSGRenderDefaultMaterial::ThicknessFactorMask );
1434 fragmentShader << " qt_attenuationColor = qt_material_attenuation.xyz;\n";
1435 fragmentShader << " qt_attenuationDistance = qt_material_attenuation.w;\n";
1436
1437 if (samplerState.hasImage(QSSGRenderableImage::Type::Thickness)) {
1438 samplerState.generateImageUVAndSampler(QSSGRenderableImage::Type::Thickness, vertexShader, fragmentShader, inKey, passRequirmentState.hasParallaxMapping);
1439 const auto &channelProps = keyProps.m_textureChannels[QSSGShaderDefaultMaterialKeyProperties::ThicknessChannel];
1440 fragmentShader << " qt_thicknessFactor *= texture2D(" << samplerState.samplerName(QSSGRenderableImage::Type::Thickness) << ", "
1441 << samplerState.fragCoordsName(QSSGRenderableImage::Type::Thickness) << ")" << channelStr(channelProps, inKey) << ";\n";
1442 }
1443 }
1444 }
1445 if (passRequirmentState.hasPunctualLights || passRequirmentState.hasSpecularLight) {
1446 fragmentShader << " vec3 qt_f0 = vec3(1.0);\n";
1447 fragmentShader << " vec3 qt_f90 = vec3(1.0);\n";
1448 }
1449
1450 if (passRequirmentState.hasSpecularLight) {
1451 fragmentShader.addInclude("principledMaterialFresnel.glsllib");
1452 if (!passRequirmentState.isSpecularGlossinessWorkflow) {
1453 fragmentShader << " qt_f0 = qt_F0_ior(qt_iOR, qt_metalnessAmount, qt_diffuseColor.rgb);\n";
1454 } else {
1455 fragmentShader << " const float qt_reflectance = max(max(qt_specularTint.r, qt_specularTint.g), qt_specularTint.b);\n";
1456 fragmentShader << " qt_f0 = qt_specularTint;\n";
1457 fragmentShader << " qt_specularTint = vec3(1.0);\n";
1458 fragmentShader << " qt_f90 = vec3(clamp(qt_reflectance * 50.0, 0.0, 1.0));\n";
1459 fragmentShader << " qt_diffuseColor.rgb *= (1 - qt_reflectance);\n";
1460 }
1461
1462 if (passRequirmentState.isSpecularAAEnabled) {
1463 fragmentShader.append(" vec3 vNormalWsDdx = dFdx(qt_world_normal.xyz);\n");
1464 fragmentShader.append(" vec3 vNormalWsDdy = dFdy(qt_world_normal.xyz);\n");
1465 fragmentShader.append(" float flGeometricRoughnessFactor = pow(clamp(max(dot(vNormalWsDdx, vNormalWsDdx), dot(vNormalWsDdy, vNormalWsDdy)), 0.0, 1.0), 0.333);\n");
1466 fragmentShader.append(" qt_roughnessAmount = max(flGeometricRoughnessFactor, qt_roughnessAmount);\n");
1467 }
1468
1469 if (hasCustomFrag)
1470 fragmentShader << " float qt_fresnelPower = qt_customFresnelPower;\n";
1471 else
1472 fragmentShader << " float qt_fresnelPower = qt_material_properties2.x;\n";
1473
1474 if (passRequirmentState.isPbrMaterial) {
1475 fragmentShader << " vec3 qt_principledMaterialFresnelValue = qt_principledMaterialFresnel(qt_world_normal, qt_view_vector, qt_f0, qt_roughnessAmount, qt_fresnelPower);\n";
1476 if (passRequirmentState.hasFresnelScaleBias) {
1477 if (hasCustomFrag) {
1478 fragmentShader << " float qt_fresnelScale = qt_customFresnelScale;\n";
1479 fragmentShader << " float qt_fresnelBias = qt_customFresnelBias;\n";
1480 } else {
1481 fragmentShader << " float qt_fresnelScale = qt_material_properties5.x;\n";
1482 fragmentShader << " float qt_fresnelBias = qt_material_properties5.y;\n";
1483 }
1484 fragmentShader << " qt_principledMaterialFresnelValue = clamp(vec3(qt_fresnelBias) + "
1485 << "qt_fresnelScale * qt_principledMaterialFresnelValue, 0.0, 1.0);\n";
1486 }
1487 fragmentShader << " qt_specularAmount *= qt_principledMaterialFresnelValue;\n";
1488 if (passRequirmentState.isMetallicRoughnessWorkflow) {
1489 // Make sure that we scale the specularTint with repsect to metalness (no tint if qt_metalnessAmount == 1)
1490 // We actually need to do this here because we won't know the final metalness value until this point.
1491 fragmentShader << " qt_specularTint = mix(vec3(1.0), qt_specularTint, 1.0 - qt_metalnessAmount);\n";
1492 }
1493 } else {
1494 fragmentShader << " qt_specularAmount *= qt_principledMaterialFresnel(qt_world_normal, qt_view_vector, qt_f0, qt_roughnessAmount, qt_fresnelPower);\n";
1495 }
1496 }
1497
1498 if (passRequirmentState.hasLighting && passRequirmentState.hasPunctualLights) {
1499 fragmentShader.addUniform("qt_lightAndShadowCounts", "vec4");
1500 fragmentShader.addFunction("processPunctualLighting");
1501 fragmentShader << " qt_processPunctualLighting(global_diffuse_light.rgb,\n"
1502 << " global_specular_light.rgb,\n"
1503 << " qt_diffuseColor.rgb,\n"
1504 << " qt_world_normal.xyz,\n"
1505 << " qt_view_vector,\n"
1506 << "#if QSSG_ENABLE_SPECULAR\n"
1507 << " qt_specularAmount,\n"
1508 << " qt_specularTint,\n"
1509 << "#endif // QSSG_ENABLE_SPECULAR\n"
1510 << " qt_roughnessAmount,\n"
1511 << " qt_metalnessAmount,\n"
1512 << "#if QSSG_CUSTOM_MATERIAL_DIRECTIONAL_LIGHT_PROCESSOR || QSSG_CUSTOM_MATERIAL_POINT_LIGHT_PROCESSOR || QSSG_CUSTOM_MATERIAL_SPOT_LIGHT_PROCESSOR || QSSG_CUSTOM_MATERIAL_SPECULAR_PROCESSOR\n"
1513 << " qt_customBaseColor,\n"
1514 << "#endif // QSSG_CUSTOM_MATERIAL_*\n"
1515 << "#if QSSG_CUSTOM_MATERIAL_SPECULAR_PROCESSOR\n"
1516 << " qt_customSpecularAmount,\n"
1517 << "#endif // QSSG_CUSTOM_MATERIAL_SPECULAR_PROCESSOR\n"
1518 << "#if QSSG_CUSTOM_MATERIAL_SHARED_VARIABLES\n"
1519 << " qt_customShared,\n"
1520 << "#endif // QSSG_CUSTOM_MATERIAL_SHARED_VARIABLES\n"
1521 << "#if QSSG_ENABLE_CLEARCOAT\n"
1522 << " qt_global_clearcoat,\n"
1523 << " qt_clearcoatNormal,\n"
1524 << " qt_clearcoatRoughness,\n"
1525 << " qt_clearcoatF0,\n"
1526 << " qt_clearcoatF90,\n"
1527 << "#endif // QSSG_ENABLE_CLEARCOAT\n"
1528 << "#if QSSG_ENABLE_TRANSMISSION\n"
1529 << " qt_global_transmission,\n"
1530 << " qt_thicknessFactor,\n"
1531 << " qt_iOR,\n"
1532 << " qt_transmissionFactor,\n"
1533 << " qt_attenuationColor,\n"
1534 << " qt_attenuationDistance,\n"
1535 << "#endif // QSSG_ENABLE_TRANSMISSION\n"
1536 << " qt_f0,\n"
1537 << " qt_f90);\n";
1538 } //QSSG_CUSTOM_MATERIAL_SPECULAR_PROCESSOR
1539
1540 // The color in rgb is ready, including shadowing, just need to apply
1541 // the ambient occlusion factor. The alpha is the model opacity
1542 // multiplied by the alpha from the material color and/or the vertex colors.
1543 fragmentShader << " global_diffuse_light = vec4(global_diffuse_light.rgb * qt_aoFactor, qt_objectOpacity * qt_diffuseColor.a);\n";
1544
1545 if (passRequirmentState.hasReflectionProbe) {
1546 vertexShader.generateWorldNormal(inKey);
1547 fragmentShader.addInclude("sampleReflectionProbe.glsllib");
1548
1549 // Diffuse
1550 if (passRequirmentState.isPbrMaterial)
1551 fragmentShader << " global_diffuse_light.rgb += qt_diffuseColor.rgb * (1.0 - qt_specularAmount) * qt_sampleDiffuseReflection(qt_reflectionMap, qt_world_normal).rgb;\n";
1552 else
1553 fragmentShader << " global_diffuse_light.rgb += qt_diffuseColor.rgb * qt_sampleDiffuseReflection(qt_reflectionMap, qt_world_normal).rgb;\n";
1554
1555 // Specular
1556 if (passRequirmentState.hasSpecularLight) {
1557 if (passRequirmentState.isPbrMaterial)
1558 fragmentShader << " global_specular_light += qt_specularTint * qt_sampleGlossyReflectionPrincipled(qt_reflectionMap, qt_world_normal, qt_view_vector, qt_specularAmount, qt_roughnessAmount).rgb;\n";
1559 else
1560 fragmentShader << " global_specular_light += qt_specularAmount * qt_specularTint * qt_sampleGlossyReflection(qt_reflectionMap, qt_world_normal, qt_view_vector, qt_roughnessAmount).rgb;\n";
1561 }
1562
1563 // Clearcoat (pbr Only)
1564 if (passRequirmentState.hasClearcoat)
1565 fragmentShader << " qt_global_clearcoat += qt_sampleGlossyReflectionPrincipled(qt_reflectionMap, qt_clearcoatNormal, qt_view_vector, qt_clearcoatF0, qt_clearcoatRoughness).rgb;\n";
1566
1567 } else if (passRequirmentState.hasIblProbe) {
1568 vertexShader.generateWorldNormal(inKey);
1569 fragmentShader.addInclude("sampleProbe.glsllib");
1570 if (hasCustomIblProbe) {
1571 // DIFFUSE, SPECULAR, BASE_COLOR, AO_FACTOR, SPECULAR_AMOUNT, NORMAL, VIEW_VECTOR, IBL_ORIENTATION(, SHARED)
1572 fragmentShader << " vec3 qt_iblDiffuse = vec3(0.0);\n";
1573 fragmentShader << " vec3 qt_iblSpecular = vec3(0.0);\n";
1574 fragmentShader << " qt_iblProbeProcessor(qt_iblDiffuse, qt_iblSpecular, qt_customBaseColor, qt_aoFactor, qt_specularFactor, qt_roughnessAmount, qt_world_normal, qt_view_vector";
1575 if (passRequirmentState.hasIblOrientation)
1576 fragmentShader << ", qt_lightProbeOrientation";
1577 else
1578 fragmentShader << ", mat3(1.0)";
1579 if (usesSharedVar)
1580 fragmentShader << ", qt_customShared);\n";
1581 else
1582 fragmentShader << ");\n";
1583 } else {
1584 // Diffuse
1585 if (passRequirmentState.isPbrMaterial)
1586 fragmentShader << " vec3 qt_iblDiffuse = qt_diffuseColor.rgb * (1.0 - qt_specularAmount) * qt_sampleDiffuse(qt_world_normal).rgb;\n";
1587 else
1588 fragmentShader << " vec3 qt_iblDiffuse = qt_diffuseColor.rgb * qt_sampleDiffuse(qt_world_normal).rgb;\n";
1589
1590 // Specular
1591 if (passRequirmentState.hasSpecularLight) {
1592 if (passRequirmentState.isPbrMaterial)
1593 fragmentShader << " vec3 qt_iblSpecular = qt_specularTint * qt_sampleGlossyPrincipled(qt_world_normal, qt_view_vector, qt_specularAmount, qt_roughnessAmount).rgb;\n";
1594 else
1595 fragmentShader << " vec3 qt_iblSpecular = qt_specularAmount * qt_specularTint * qt_sampleGlossy(qt_world_normal, qt_view_vector, qt_roughnessAmount).rgb;\n";
1596 }
1597
1598 // Clearcoat (pbr Only)
1599 if (passRequirmentState.hasClearcoat)
1600 fragmentShader << " vec3 qt_iblClearcoat = qt_sampleGlossyPrincipled(qt_clearcoatNormal, qt_view_vector, qt_clearcoatF0, qt_clearcoatRoughness).rgb;\n";
1601 }
1602
1603 fragmentShader << " global_diffuse_light.rgb += qt_iblDiffuse * qt_aoFactor;\n";
1604 if (passRequirmentState.hasSpecularLight)
1605 fragmentShader << " global_specular_light += qt_iblSpecular * qt_aoFactor;\n";
1606 if (passRequirmentState.hasClearcoat)
1607 fragmentShader << " qt_global_clearcoat += qt_iblClearcoat * qt_aoFactor;\n";
1608 } else if (hasCustomIblProbe) {
1609 // Prevent breaking the fragment code while seeking uniforms
1610 fragmentShader.addUniform("qt_lightProbe", "samplerCube");
1611 fragmentShader.addUniform("qt_lightProbeProperties", "vec4");
1612 }
1613
1614 // This can run even without a IBL probe
1615 if (passRequirmentState.hasTransmission) {
1616 fragmentShader << " qt_global_transmission += qt_transmissionFactor * qt_getIBLVolumeRefraction(qt_world_normal, qt_view_vector, qt_roughnessAmount, "
1617 "qt_diffuseColor.rgb, qt_specularAmount, qt_varWorldPos, qt_iOR, qt_thicknessFactor, qt_attenuationColor, qt_attenuationDistance);\n";
1618 }
1619
1620
1621 // Handle specular and emissive maps which just add additional color
1622 if (samplerState.hasImage(QSSGRenderableImage::Type::Specular) || samplerState.hasImage(QSSGRenderableImage::Type::Emissive)) {
1623 addLocalVariable(fragmentShader, "qt_texture_color", "vec4");
1624
1625 if (samplerState.hasImage(QSSGRenderableImage::Type::Specular)) {
1626 samplerState.generateImageUVAndSampler(QSSGRenderableImage::Type::Specular, vertexShader, fragmentShader, inKey, passRequirmentState.hasParallaxMapping);
1627 fragmentShader << " qt_texture_color = texture2D(" << samplerState.samplerName(QSSGRenderableImage::Type::Specular) << ", "
1628 << samplerState.fragCoordsName(QSSGRenderableImage::Type::Specular) << ");\n";
1629 fragmentShader.addInclude("tonemapping.glsllib");
1630 fragmentShader << " global_specular_light += qt_sRGBToLinear(qt_texture_color.rgb) * qt_specularTint;\n";
1631 fragmentShader << " global_diffuse_light.a *= qt_texture_color.a;\n";
1632 }
1633
1634 if (samplerState.hasImage(QSSGRenderableImage::Type::Emissive)) {
1635 samplerState.generateImageUVAndSampler(QSSGRenderableImage::Type::Emissive, vertexShader, fragmentShader, inKey, passRequirmentState.hasParallaxMapping);
1636 fragmentShader << " qt_texture_color = texture2D(" << samplerState.samplerName(QSSGRenderableImage::Type::Emissive) << ", "
1637 << samplerState.fragCoordsName(QSSGRenderableImage::Type::Emissive) << ");\n";
1638 fragmentShader.addInclude("tonemapping.glsllib");
1639 if (keyProps.m_emissiveSingleChannelEnabled.getValue(inKey)) {
1640 const auto &channelProps = keyProps.m_textureChannels[QSSGShaderDefaultMaterialKeyProperties::EmissiveChannel];
1641 fragmentShader << " qt_global_emission *= qt_sRGBToLinear(vec3(qt_texture_color" <<
1642 channelStr(channelProps, inKey) << "));\n";
1643 } else {
1644 fragmentShader << " qt_global_emission *= qt_sRGBToLinear(qt_texture_color.rgb);\n";
1645 }
1646 }
1647 }
1648
1649 if (passRequirmentState.hasTransmission)
1650 fragmentShader << " global_diffuse_light.rgb = mix(global_diffuse_light.rgb, qt_global_transmission, qt_transmissionFactor);\n";
1651
1652 if (passRequirmentState.isMetallicRoughnessWorkflow) {
1653 fragmentShader << " global_diffuse_light.rgb *= 1.0 - qt_metalnessAmount;\n";
1654 }
1655
1656 if (passRequirmentState.hasFog) {
1657 fragmentShader.addInclude("fog.glsllib");
1658 fragmentShader << " calculateFog(qt_global_emission, global_specular_light, global_diffuse_light.rgb);\n";
1659 }
1660
1661 fragmentShader << " vec4 qt_color_sum = vec4(global_diffuse_light.rgb + global_specular_light + qt_global_emission, global_diffuse_light.a);\n";
1662
1663 if (passRequirmentState.hasClearcoat) {
1664 fragmentShader.addInclude("bsdf.glsllib");
1665 if (hasCustomFrag)
1666 fragmentShader << " float qt_clearcoatFresnelPower = qt_customClearcoatFresnelPower;\n";
1667 else
1668 fragmentShader << " float qt_clearcoatFresnelPower = qt_material_clearcoat_fresnel_power;\n";
1669 fragmentShader << " vec3 qt_clearcoatFresnel = qt_schlick3(qt_clearcoatF0, qt_clearcoatF90, clamp(dot(qt_clearcoatNormal, qt_view_vector), 0.0, 1.0), qt_clearcoatFresnelPower);\n";
1670 if (passRequirmentState.hasClearcoatFresnelScaleBias) {
1671 if (hasCustomFrag) {
1672 fragmentShader << " float qt_clearcoatFresnelScale = qt_customClearcoatFresnelScale;\n";
1673 fragmentShader << " float qt_clearcoatFresnelBias = qt_customClearcoatFresnelBias;\n";
1674 }else {
1675 fragmentShader << " float qt_clearcoatFresnelScale = qt_material_properties5.z;\n";
1676 fragmentShader << " float qt_clearcoatFresnelBias = qt_material_properties5.w;\n";
1677 }
1678 fragmentShader << " qt_clearcoatFresnel = clamp(vec3(qt_clearcoatFresnelBias) + qt_clearcoatFresnelScale * qt_clearcoatFresnel, 0.0, 1.0);\n";
1679 }
1680 fragmentShader << " qt_global_clearcoat = qt_global_clearcoat * qt_clearcoatAmount;\n";
1681 fragmentShader << " qt_color_sum.rgb = qt_color_sum.rgb * (1.0 - qt_clearcoatAmount * qt_clearcoatFresnel) + qt_global_clearcoat;\n";
1682 }
1683
1684 if (hasCustomFrag && hasCustomFunction(QByteArrayLiteral("qt_customPostProcessor"))) {
1685 // COLOR_SUM, DIFFUSE, SPECULAR, EMISSIVE, UV0, UV1(, SHARED)
1686 fragmentShader << " qt_customPostProcessor(qt_color_sum, global_diffuse_light, global_specular_light, qt_global_emission, qt_texCoord0, qt_texCoord1";
1687 if (usesSharedVar)
1688 fragmentShader << ", qt_customShared);\n";
1689 else
1690 fragmentShader << ");\n";
1691 }
1692 } // end of lighting block
1693
1694 // Outputs
1695 switch (passRequirmentState.passType) {
1696
1698 break;
1700 // Unlit color pass
1701 if (!passRequirmentState.hasLighting)
1702 fragmentShader.append(" vec4 qt_color_sum = vec4(qt_diffuseColor.rgb, qt_diffuseColor.a * qt_objectOpacity);");
1703
1704 if (passRequirmentState.oitMethod == QSSGRenderLayer::OITMethod::WeightedBlended) {
1705 fragmentShader.addInclude("orderindependenttransparency.glsllib");
1706 fragmentShader.addInclude("tonemapping.glsllib");
1707 fragmentShader.addUniform("qt_cameraPosition", "vec3");
1708 fragmentShader.addUniform("qt_cameraProperties", "vec2");
1709 fragmentShader.append(" float z = abs(gl_FragCoord.z);");
1710 fragmentShader.append(" qt_color_sum.rgb = qt_tonemap(qt_color_sum.rgb) * qt_color_sum.a;");
1711 fragmentShader.append(" fragOutput = qt_color_sum * qt_transparencyWeight(z, qt_color_sum.a, qt_cameraProperties.y);");
1712 fragmentShader.append(" revealageOutput = vec4(qt_color_sum.a);");
1713 } else {
1714 fragmentShader.addInclude("tonemapping.glsllib");
1715 fragmentShader.append(" fragOutput = vec4(qt_tonemap(qt_color_sum));");
1716 }
1717 break;
1719 fragmentShader << " vec4 fragOutput = vec4(0.0);\n";
1720 break;
1722 Q_ASSERT(viewCount == 1);
1723 fragmentShader << " // directional shadow pass\n"
1724 << " float qt_shadowDepth = (qt_varDepth + qt_shadowDepthAdjust.x) * qt_shadowDepthAdjust.y;\n"
1725 << " fragOutput = vec4(qt_shadowDepth);\n";
1726 break;
1728 Q_ASSERT(viewCount == 1);
1729 fragmentShader.addUniform("qt_cameraPosition", "vec3");
1730 fragmentShader.addUniform("qt_cameraProperties", "vec2");
1731 fragmentShader << " // omnidirectional shadow pass\n"
1732 << " vec3 qt_shadowCamPos = vec3(qt_cameraPosition.x, qt_cameraPosition.y, qt_cameraPosition.z);\n"
1733 << " float qt_shadowDist = length(qt_varShadowWorldPos - qt_shadowCamPos);\n"
1734 << " qt_shadowDist = (qt_shadowDist - qt_cameraProperties.x) / (qt_cameraProperties.y - qt_cameraProperties.x);\n"
1735 << " fragOutput = vec4(qt_shadowDist, qt_shadowDist, qt_shadowDist, 1.0);\n";
1736 break;
1738 // world space normal in rgb, roughness in alpha
1739 fragmentShader.append(" fragOutput = vec4(qt_world_normal, qt_roughnessAmount);\n");
1740 break;
1742 fragmentShader.append(" vec3 debugOutput = vec3(0.0);\n");
1743 switch (passRequirmentState.debugMode) {
1744 case QSSGRenderLayer::MaterialDebugMode::BaseColor:
1745 fragmentShader.addInclude("tonemapping.glsllib");
1746 fragmentShader.append(" debugOutput += qt_tonemap(qt_diffuseColor.rgb);\n");
1747 break;
1748 case QSSGRenderLayer::MaterialDebugMode::Roughness:
1749 fragmentShader.append(" debugOutput += vec3(qt_roughnessAmount);\n");
1750 break;
1751 case QSSGRenderLayer::MaterialDebugMode::Metalness:
1752 fragmentShader.append(" debugOutput += vec3(qt_metalnessAmount);\n");
1753 break;
1754 case QSSGRenderLayer::MaterialDebugMode::Diffuse:
1755 fragmentShader.addInclude("tonemapping.glsllib");
1756 fragmentShader.append(" debugOutput += qt_tonemap(global_diffuse_light.rgb);\n");
1757 break;
1758 case QSSGRenderLayer::MaterialDebugMode::Specular:
1759 fragmentShader.addInclude("tonemapping.glsllib");
1760 fragmentShader.append(" debugOutput += qt_tonemap(global_specular_light);\n");
1761 break;
1762 case QSSGRenderLayer::MaterialDebugMode::ShadowOcclusion:
1763 // Technically speaking this was just outputing the occlusion value of the last light processed, which is likely not super useful
1764 // So for now this just outputs 1.0 (no occlusion)
1765 fragmentShader.addFunction("debugShadowOcclusion");
1766 vertexShader.generateWorldPosition(inKey);
1767 fragmentShader.append(" debugOutput += vec3(qt_debugShadowOcclusion());\n");
1768 break;
1769 case QSSGRenderLayer::MaterialDebugMode::Emission:
1770 fragmentShader.addInclude("tonemapping.glsllib");
1771 fragmentShader.append(" debugOutput += qt_tonemap(qt_global_emission);\n");
1772 break;
1773 case QSSGRenderLayer::MaterialDebugMode::AmbientOcclusion:
1774 fragmentShader.append(" debugOutput += vec3(qt_aoFactor);\n");
1775 break;
1776 case QSSGRenderLayer::MaterialDebugMode::Normal:
1777 fragmentShader.append(" debugOutput += qt_world_normal * 0.5 + 0.5;\n");
1778 break;
1779 case QSSGRenderLayer::MaterialDebugMode::Tangent:
1780 fragmentShader.append(" debugOutput += qt_tangent * 0.5 + 0.5;\n");
1781 break;
1782 case QSSGRenderLayer::MaterialDebugMode::Binormal:
1783 fragmentShader.append(" debugOutput += qt_binormal * 0.5 + 0.5;\n");
1784 break;
1785 case QSSGRenderLayer::MaterialDebugMode::F0:
1786 if (passRequirmentState.isPbrMaterial)
1787 fragmentShader.append(" debugOutput += qt_f0;");
1788 break;
1789 case QSSGRenderLayer::MaterialDebugMode::None:
1790 Q_UNREACHABLE();
1791 break;
1792 }
1793 fragmentShader.append(" fragOutput = vec4(debugOutput, 1.0);\n");
1794 break;
1796 // TODO handle the user pass case by pulling the pass specific code from somewhere
1797 break;
1798 }
1799}
1800
1801QSSGRhiShaderPipelinePtr QSSGMaterialShaderGenerator::generateMaterialRhiShader(const QByteArray &inShaderKeyPrefix,
1802 QSSGMaterialVertexPipeline &vertexPipeline,
1803 const QSSGShaderDefaultMaterialKey &key,
1804 const QSSGShaderDefaultMaterialKeyProperties &inProperties,
1805 const QSSGShaderFeatures &inFeatureSet,
1806 const QSSGRenderGraphObject &inMaterial,
1807 QSSGShaderLibraryManager &shaderLibraryManager,
1808 QSSGShaderCache &theCache)
1809{
1810 const int viewCount = inFeatureSet.isSet(QSSGShaderFeatures::Feature::DisableMultiView)
1811 ? 1 : inProperties.m_viewCount.getValue(key);
1812
1813 bool perTargetCompilation = false;
1814 // Cull mode None implies doing the gl_FrontFacing-based double sided logic
1815 // in the shader. This may want to ifdef the generated shader code based the
1816 // target shading language. This is only possible if the QShaderBaker is
1817 // told to compile to SPIR-V (and then transpile) separately for each target
1818 // (GLSL, HLSL, etc.), instead of just compiling to SPIR-V once (and
1819 // transpiling the same bytecode to each target language). This takes more
1820 // time, so we only do it for multiview since that's also how the logic is
1821 // going to be written in the generated shader code.
1822 if (viewCount >= 2) {
1823 const bool isDoubleSided = inProperties.m_isDoubleSided.getValue(key);
1824 if (isDoubleSided)
1825 perTargetCompilation = true;
1826 }
1827
1828 QByteArray materialInfoString; // also serves as the key for the cache in compileGeneratedRhiShader
1829 // inShaderKeyPrefix can be a static string for default materials, but must
1830 // be unique for different sets of shaders in custom materials.
1831 materialInfoString = inShaderKeyPrefix;
1832 key.toString(materialInfoString, inProperties);
1833
1834 // the call order is: beginVertex, beginFragment, endVertex, endFragment
1835 vertexPipeline.beginVertexGeneration(key, inFeatureSet, shaderLibraryManager);
1836 generateFragmentShader(vertexPipeline.fragment(), vertexPipeline, key, inProperties, inFeatureSet, inMaterial, shaderLibraryManager);
1837 vertexPipeline.endVertexGeneration();
1838 vertexPipeline.endFragmentGeneration();
1839
1840 return vertexPipeline.programGenerator()->compileGeneratedRhiShader(materialInfoString,
1841 inFeatureSet,
1842 shaderLibraryManager,
1843 theCache,
1844 {},
1845 viewCount,
1846 perTargetCompilation);
1847}
1848
1849static quint32 softShadowQualityToInt(QSSGRenderLight::SoftShadowQuality quality)
1850{
1851 quint32 samplesCount = 0;
1852 switch (quality) {
1853 case QSSGRenderLight::SoftShadowQuality::Hard:
1854 samplesCount = 0;
1855 break;
1856 case QSSGRenderLight::SoftShadowQuality::PCF4:
1857 samplesCount = 4;
1858 break;
1859 case QSSGRenderLight::SoftShadowQuality::PCF8:
1860 samplesCount = 8;
1861 break;
1862 case QSSGRenderLight::SoftShadowQuality::PCF16:
1863 case QSSGRenderLight::SoftShadowQuality::PCF32:
1864 case QSSGRenderLight::SoftShadowQuality::PCF64:
1865 samplesCount = 16;
1866 break;
1867 }
1868
1869 return samplesCount;
1870}
1871
1872void QSSGMaterialShaderGenerator::setRhiMaterialProperties(const QSSGRenderContextInterface &renderContext,
1873 QSSGRhiShaderPipeline &shaders,
1874 char *ubufData,
1875 QSSGRhiGraphicsPipelineState *inPipelineState,
1876 const QSSGRenderGraphObject &inMaterial,
1877 const QSSGShaderDefaultMaterialKey &inKey,
1878 const QSSGShaderDefaultMaterialKeyProperties &inProperties,
1879 const QSSGRenderCameraList &inCameras,
1880 const QSSGRenderMvpArray &inModelViewProjections,
1881 const QMatrix3x3 &inNormalMatrix,
1882 const QMatrix4x4 &inGlobalTransform,
1883 const QMatrix4x4 &clipSpaceCorrMatrix,
1884 const QMatrix4x4 &localInstanceTransform,
1885 const QMatrix4x4 &globalInstanceTransform,
1886 const QSSGDataView<float> &inMorphWeights,
1887 QSSGRenderableImage *inFirstImage,
1888 float inOpacity,
1889 const QSSGLayerRenderData &inRenderProperties,
1890 const QSSGShaderLightListView &inLights,
1891 const QSSGShaderReflectionProbe &reflectionProbe,
1892 bool receivesShadows,
1893 bool receivesReflections,
1894 const QVector2D *shadowDepthAdjust,
1895 QRhiTexture *lightmapTexture)
1896{
1897 QSSGShaderMaterialAdapter *materialAdapter = getMaterialAdapter(inMaterial);
1898 QSSGRhiShaderPipeline::CommonUniformIndices &cui = shaders.commonUniformIndices;
1899
1900 materialAdapter->setCustomPropertyUniforms(ubufData, shaders, renderContext);
1901
1902 const QVector2D camProperties(inCameras[0]->clipPlanes);
1903 shaders.setUniform(ubufData, "qt_cameraProperties", &camProperties, 2 * sizeof(float), &cui.cameraPropertiesIdx);
1904
1905 const int viewCount = inCameras.count();
1906
1907 // Pull the camera transforms from the render data once.
1908 QMatrix4x4 camGlobalTransforms[2] { QMatrix4x4{Qt::Uninitialized}, QMatrix4x4{Qt::Uninitialized} };
1909 if (viewCount < 2) {
1910 camGlobalTransforms[0] = inRenderProperties.getGlobalTransform(*inCameras[0]);
1911 } else {
1912 for (size_t viewIndex = 0; viewIndex != std::size(camGlobalTransforms); ++viewIndex)
1913 camGlobalTransforms[viewIndex] = inRenderProperties.getGlobalTransform(*inCameras[viewIndex]);
1914 }
1915
1916 if (viewCount < 2) {
1917 const QMatrix4x4 &camGlobalTransform = camGlobalTransforms[0];
1918 const QVector3D camGlobalPos = QSSGRenderNode::getGlobalPos(camGlobalTransform);
1919 shaders.setUniform(ubufData, "qt_cameraPosition", &camGlobalPos, 3 * sizeof(float), &cui.cameraPositionIdx);
1920 const QVector3D camDirection = QSSG_GUARD(inRenderProperties.renderedCameraData.has_value())
1921 ? inRenderProperties.renderedCameraData.value()[0].direction
1922 : QVector3D{ 0.0f, 0.0f, -1.0f };
1923 shaders.setUniform(ubufData, "qt_cameraDirection", &camDirection, 3 * sizeof(float), &cui.cameraDirectionIdx);
1924 } else {
1925 QVarLengthArray<QVector3D, 2> camGlobalPos(viewCount);
1926 QVarLengthArray<QVector3D> camDirection(viewCount);
1927 for (size_t viewIndex = 0; viewIndex != std::size(camGlobalTransforms); ++viewIndex) {
1928 const QMatrix4x4 &camGlobalTransform = camGlobalTransforms[viewIndex];
1929 camGlobalPos[viewIndex] = QSSGRenderNode::getGlobalPos(camGlobalTransform);
1930 camDirection[viewIndex] = QSSG_GUARD(inRenderProperties.renderedCameraData.has_value())
1931 ? inRenderProperties.renderedCameraData.value()[viewIndex].direction
1932 : QVector3D{ 0.0f, 0.0f, -1.0f };
1933 }
1934 shaders.setUniformArray(ubufData, "qt_cameraPosition", camGlobalPos.constData(), viewCount, QSSGRenderShaderValue::Vec3, &cui.cameraPositionIdx);
1935 shaders.setUniformArray(ubufData, "qt_cameraDirection", camDirection.constData(), viewCount, QSSGRenderShaderValue::Vec3, &cui.cameraDirectionIdx);
1936 }
1937
1938 const auto globalRenderData = QSSGLayerRenderData::globalRenderProperties(renderContext);
1939
1940 // Only calculate and update Matrix uniforms if they are needed
1941 bool usesProjectionMatrix = false;
1942 bool usesInvProjectionMatrix = false;
1943 bool usesViewProjectionMatrix = false;
1944 bool usesModelViewProjectionMatrix = false;
1945 bool usesNormalMatrix = false;
1946 bool usesParentMatrix = false;
1947
1948 if (inMaterial.type == QSSGRenderGraphObject::Type::CustomMaterial) {
1949 const auto *customMaterial = static_cast<const QSSGRenderCustomMaterial *>(&inMaterial);
1950 usesProjectionMatrix = customMaterial->m_renderFlags.testFlag(QSSGRenderCustomMaterial::RenderFlag::ProjectionMatrix);
1951 usesInvProjectionMatrix = customMaterial->m_renderFlags.testFlag(QSSGRenderCustomMaterial::RenderFlag::InverseProjectionMatrix);
1952 // ### these should use flags like the above two
1953 usesViewProjectionMatrix = true;
1954 }
1955
1956 const bool usesInstancing = inProperties.m_usesInstancing.getValue(inKey);
1957 if (usesInstancing) {
1958 // Instanced calls have to calculate MVP and normalMatrix in the vertex shader
1959 usesViewProjectionMatrix = true;
1960 usesParentMatrix = true;
1961 } else {
1962 usesModelViewProjectionMatrix = true;
1963 usesNormalMatrix = true;
1964 }
1965
1966 if (materialAdapter->isTransmissionEnabled())
1967 usesViewProjectionMatrix = true;
1968
1969 // Update matrix uniforms
1970 if (usesProjectionMatrix || usesInvProjectionMatrix) {
1971 if (viewCount < 2) {
1972 const QMatrix4x4 projection = clipSpaceCorrMatrix * inCameras[0]->projection;
1973 if (usesProjectionMatrix)
1974 shaders.setUniform(ubufData, "qt_projectionMatrix", projection.constData(), 16 * sizeof(float), &cui.projectionMatrixIdx);
1975 if (usesInvProjectionMatrix)
1976 shaders.setUniform(ubufData, "qt_inverseProjectionMatrix", projection.inverted().constData(), 16 * sizeof (float), &cui.inverseProjectionMatrixIdx);
1977 } else {
1978 QVarLengthArray<QMatrix4x4, 2> projections(viewCount);
1979 QVarLengthArray<QMatrix4x4, 2> invertedProjections(viewCount);
1980 for (size_t viewIndex = 0; viewIndex != std::size(camGlobalTransforms); ++viewIndex) {
1981 projections[viewIndex] = clipSpaceCorrMatrix * inCameras[viewIndex]->projection;
1982 if (usesInvProjectionMatrix)
1983 invertedProjections[viewIndex] = projections[viewIndex].inverted();
1984 }
1985 if (usesProjectionMatrix)
1986 shaders.setUniformArray(ubufData, "qt_projectionMatrix", projections.constData(), viewCount, QSSGRenderShaderValue::Matrix4x4, &cui.projectionMatrixIdx);
1987 if (usesInvProjectionMatrix)
1988 shaders.setUniformArray(ubufData, "qt_inverseProjectionMatrix", invertedProjections.constData(), viewCount, QSSGRenderShaderValue::Matrix4x4, &cui.inverseProjectionMatrixIdx);
1989 }
1990 }
1991
1992 if (viewCount < 2) {
1993 const QMatrix4x4 viewMatrix = camGlobalTransforms[0].inverted();
1994 shaders.setUniform(ubufData, "qt_viewMatrix", viewMatrix.constData(), 16 * sizeof(float), &cui.viewMatrixIdx);
1995 } else {
1996 QVarLengthArray<QMatrix4x4, 2> viewMatrices(viewCount);
1997 for (size_t viewIndex = 0; viewIndex != std::size(camGlobalTransforms); ++viewIndex)
1998 viewMatrices[viewIndex] = camGlobalTransforms[viewIndex].inverted();
1999 shaders.setUniformArray(ubufData, "qt_viewMatrix", viewMatrices.constData(), viewCount, QSSGRenderShaderValue::Matrix4x4, &cui.viewMatrixIdx);
2000 }
2001
2002 if (usesViewProjectionMatrix) {
2003 if (viewCount < 2) {
2004 const QMatrix4x4 &camGlobalTransform = camGlobalTransforms[0];
2005 QMatrix4x4 viewProj(Qt::Uninitialized);
2006 inCameras[0]->calculateViewProjectionMatrix(camGlobalTransform, viewProj);
2007 viewProj = clipSpaceCorrMatrix * viewProj;
2008 shaders.setUniform(ubufData, "qt_viewProjectionMatrix", viewProj.constData(), 16 * sizeof(float), &cui.viewProjectionMatrixIdx);
2009 } else {
2010 QVarLengthArray<QMatrix4x4, 2> viewProjections(viewCount);
2011 for (size_t viewIndex = 0; viewIndex != std::size(camGlobalTransforms); ++viewIndex) {
2012 const auto &camGlobalTransform = camGlobalTransforms[viewIndex];
2013 inCameras[viewIndex]->calculateViewProjectionMatrix(camGlobalTransform, viewProjections[viewIndex]);
2014 viewProjections[viewIndex] = clipSpaceCorrMatrix * viewProjections[viewIndex];
2015 }
2016 shaders.setUniformArray(ubufData, "qt_viewProjectionMatrix", viewProjections.constData(), viewCount, QSSGRenderShaderValue::Matrix4x4, &cui.viewProjectionMatrixIdx);
2017 }
2018 }
2019
2020 // qt_modelMatrix is always available, but differnt when using instancing
2021 if (usesInstancing)
2022 shaders.setUniform(ubufData, "qt_modelMatrix", localInstanceTransform.constData(), 16 * sizeof(float), &cui.modelMatrixIdx);
2023 else
2024 shaders.setUniform(ubufData, "qt_modelMatrix", inGlobalTransform.constData(), 16 * sizeof(float), &cui.modelMatrixIdx);
2025
2026 if (usesModelViewProjectionMatrix) {
2027 if (viewCount < 2) {
2028 QMatrix4x4 mvp { clipSpaceCorrMatrix };
2029 mvp *= inModelViewProjections[0];
2030 shaders.setUniform(ubufData, "qt_modelViewProjection", mvp.constData(), 16 * sizeof(float), &cui.modelViewProjectionIdx);
2031 } else {
2032 QVarLengthArray<QMatrix4x4, 2> mvps(viewCount);
2033 for (int viewIndex = 0; viewIndex < viewCount; ++viewIndex)
2034 mvps[viewIndex] = clipSpaceCorrMatrix * inModelViewProjections[viewIndex];
2035 shaders.setUniformArray(ubufData, "qt_modelViewProjection", mvps.constData(), viewCount, QSSGRenderShaderValue::Matrix4x4, &cui.modelViewProjectionIdx);
2036 }
2037 }
2038 if (usesNormalMatrix)
2039 shaders.setUniform(ubufData, "qt_normalMatrix", inNormalMatrix.constData(), 12 * sizeof(float), &cui.normalMatrixIdx,
2040 QSSGRhiShaderPipeline::UniformFlag::Mat3); // real size will be 12 floats, setUniform repacks as needed
2041 if (usesParentMatrix)
2042 shaders.setUniform(ubufData, "qt_parentMatrix", globalInstanceTransform.constData(), 16 * sizeof(float));
2043
2044 // Morphing
2045 const qsizetype morphSize = inProperties.m_targetCount.getValue(inKey);
2046 if (morphSize > 0) {
2047 if (inMorphWeights.mSize >= morphSize) {
2048 shaders.setUniformArray(ubufData, "qt_morphWeights", inMorphWeights.mData, morphSize,
2049 QSSGRenderShaderValue::Float, &cui.morphWeightsIdx);
2050 } else {
2051 const QList<float> zeroWeights(morphSize - inMorphWeights.mSize, 0.0f);
2052 QList<float> newWeights(inMorphWeights.mData, inMorphWeights.mData + inMorphWeights.mSize);
2053 newWeights.append(zeroWeights);
2054 shaders.setUniformArray(ubufData, "qt_morphWeights", newWeights.constData(), morphSize,
2055 QSSGRenderShaderValue::Float, &cui.morphWeightsIdx);
2056 }
2057 }
2058
2059 QVector3D theLightAmbientTotal;
2060 quint32 lightCount = 0;
2061 quint32 directionalLightCount = 0;
2062 quint32 shadowCount = 0;
2063 quint32 directionalShadowCount = 0;
2064 QSSGShaderLightsUniformData &lightsUniformData(shaders.lightsUniformData());
2065 QSSGShaderDirectionalLightsUniformData &directionalLightsUniformData(shaders.directionalLightsUniformData());
2066
2067 for (quint32 lightIdx = 0, lightEnd = inLights.size();
2068 lightIdx < lightEnd && lightIdx < QSSG_MAX_NUM_LIGHTS; ++lightIdx)
2069 {
2070 QSSGRenderLight *theLight(inLights[lightIdx].light);
2071
2072 // Gather Common Properties
2073 const bool lightShadows = inLights[lightIdx].shadows;
2074 const float brightness = theLight->m_brightness;
2075 quint32 lightmapState = 0;
2076 if (theLight->m_bakingEnabled) {
2077 if (theLight->m_fullyBaked) {
2078 // Lightmap provides Indirect + Diffuse (we still need to provide specular)
2079 lightmapState = 2;
2080 } else {
2081 // Lightmap provides Indirect (we still provide direct diffuse + specular)
2082 lightmapState = 1;
2083 }
2084 }
2085
2086 const QVector3D diffuseColor(theLight->m_diffuseColor.x() * brightness,
2087 theLight->m_diffuseColor.y() * brightness,
2088 theLight->m_diffuseColor.z() * brightness);
2089 const QVector3D specularColor(theLight->m_specularColor.x() * brightness,
2090 theLight->m_specularColor.y() * brightness,
2091 theLight->m_specularColor.z() * brightness);
2092 const QVector3D direction(inLights[lightIdx].direction);
2093
2094
2095 if (theLight->type == QSSGRenderGraphObject::Type::DirectionalLight) {
2096 // Directional Light
2097 QSSGShaderDirectionalLightData &lightData(directionalLightsUniformData.directionalLightData[directionalLightCount]);
2098 lightData.direction[0] = direction.x();
2099 lightData.direction[1] = direction.y();
2100 lightData.direction[2] = direction.z();
2101 lightData.diffuseColor[0] = diffuseColor.x();
2102 lightData.diffuseColor[1] = diffuseColor.y();
2103 lightData.diffuseColor[2] = diffuseColor.z();
2104 lightData.specularColor[0] = specularColor.x();
2105 lightData.specularColor[1] = specularColor.y();
2106 lightData.specularColor[2] = specularColor.z();
2107 lightData.lightmapState = lightmapState;
2108 if (lightShadows && receivesShadows) {
2109 lightData.enableShadows = 1.0f;
2110 QSSGShadowMapEntry *pEntry = inRenderProperties.getShadowMapManager()->shadowMapEntry(lightIdx);
2111 Q_ASSERT(pEntry);
2112
2113 const quint32 layerCount = pEntry->m_csmNumSplits + 1;
2114
2115 for (quint32 i = 0; i < layerCount; ++i)
2116 memcpy(lightData.matrices[i], pEntry->m_fixedScaleBiasMatrix[i].constData(), 16 * sizeof(float));
2117
2118 lightData.shadowBias = theLight->m_shadowBias;
2119 // If all cascades are inactive, disable shadows for this light, as there are no casters.
2120 const bool noCascades = !(pEntry->m_csmActive[0] || pEntry->m_csmActive[1] || pEntry->m_csmActive[2] || pEntry->m_csmActive[3]);
2121 if (theLight->type == QSSGRenderLight::Type::DirectionalLight && noCascades)
2122 lightData.enableShadows = 0.0f;
2123 lightData.shadowFactor = theLight->m_shadowFactor;
2124 lightData.shadowMapFar = theLight->m_shadowMapFar;
2125 lightData.shadowPcfSamples = softShadowQualityToInt(theLight->m_softShadowQuality);
2126 lightData.shadowPcfFactor = theLight->m_pcfFactor;
2127
2128 for (quint32 i = 0; i < layerCount; ++i) {
2129 const auto &atlasInfo = pEntry->m_atlasInfo[i];
2130 lightData.atlasLocations[i][0] = atlasInfo.uOffset;
2131 lightData.atlasLocations[i][1] = atlasInfo.vOffset;
2132 lightData.atlasLocations[i][2] = atlasInfo.uvScale;
2133 lightData.atlasLocations[i][3] = atlasInfo.layerIndex;
2134 }
2135
2136 lightData.csmNumSplits = pEntry->m_csmNumSplits;
2137 memcpy(lightData.csmSplits, pEntry->m_csmSplits, 4 * sizeof(float));
2138 memcpy(lightData.csmActive, pEntry->m_csmActive, 4 * sizeof(float));
2139 lightData.csmBlendRatio = theLight->m_csmBlendRatio;
2140 for (quint32 i = 0; i < layerCount; ++i)
2141 memcpy(lightData.dimensionsInverted[i], &pEntry->m_dimensionsInverted[i], 4 * sizeof(float));
2142
2143 directionalShadowCount++;
2144 } else {
2145 lightData.enableShadows = 0.0f;
2146 }
2147 directionalLightCount++;
2148 } else {
2149 // Point or Spot Light
2150 QSSGShaderLightData &lightData(lightsUniformData.lightData[lightCount]);
2151 const auto gt = inRenderProperties.getGlobalTransform(*theLight);
2152 const QVector3D globalPos = QSSGRenderNode::getGlobalPos(gt);
2153 lightData.position[0] = globalPos.x();
2154 lightData.position[1] = globalPos.y();
2155 lightData.position[2] = globalPos.z();
2156 lightData.constantAttenuation = QSSGUtils::aux::translateConstantAttenuation(theLight->m_constantFade);
2157 lightData.linearAttenuation = QSSGUtils::aux::translateLinearAttenuation(theLight->m_linearFade);
2158 lightData.quadraticAttenuation = QSSGUtils::aux::translateQuadraticAttenuation(theLight->m_quadraticFade);
2159 lightData.coneAngle = 360.0f;
2160 lightData.direction[0] = direction.x();
2161 lightData.direction[1] = direction.y();
2162 lightData.direction[2] = direction.z();
2163 lightData.diffuseColor[0] = diffuseColor.x();
2164 lightData.diffuseColor[1] = diffuseColor.y();
2165 lightData.diffuseColor[2] = diffuseColor.z();
2166 lightData.specularColor[0] = specularColor.x();
2167 lightData.specularColor[1] = specularColor.y();
2168 lightData.specularColor[2] = specularColor.z();
2169 lightData.lightmapState = lightmapState;
2170 if (theLight->type == QSSGRenderLight::Type::SpotLight) {
2171 // NB: This is how we tell in the shader that this is a spot light
2172 // PointLights have a coneAngle of 360.0f which is greater than 1.0
2173 // Since cos(any value) will be between -1 and 1, we can use this.
2174 const float coneAngle = theLight->m_coneAngle;
2175 const float innerConeAngle = (theLight->m_innerConeAngle > coneAngle) ? coneAngle : theLight->m_innerConeAngle;
2176 lightData.coneAngle = qCos(qDegreesToRadians(coneAngle));
2177 lightData.innerConeAngle = qCos(qDegreesToRadians(innerConeAngle));
2178 }
2179
2180 if (lightShadows && receivesShadows) {
2181 QSSGShadowMapEntry *pEntry = inRenderProperties.getShadowMapManager()->shadowMapEntry(lightIdx);
2182 Q_ASSERT(pEntry);
2183 lightData.enableShadows = 1.0f;
2184 lightData.shadowPcfFactor = theLight->m_pcfFactor;
2185 lightData.shadowPcfSamples = softShadowQualityToInt(theLight->m_softShadowQuality);
2186 lightData.shadowFactor = theLight->m_shadowFactor;
2187 lightData.shadowBias = theLight->m_shadowBias;
2188 lightData.shadowClipNear = 1.0f;
2189 lightData.shadowMapFar = pEntry->m_shadowMapFar;
2190 lightData.shadowTextureSize = pEntry->m_atlasInfo[0].uvScale;
2191
2192 if (theLight->type == QSSGRenderLight::Type::SpotLight) {
2193 // add fixed scale bias matrix
2194 static const QMatrix4x4 bias = {
2195 0.5, 0.0, 0.0, 0.5,
2196 0.0, 0.5, 0.0, 0.5,
2197 0.0, 0.0, 0.5, 0.5,
2198 0.0, 0.0, 0.0, 1.0 };
2199 const QMatrix4x4 m = bias * pEntry->m_lightViewProjection[0];
2200 memcpy(lightData.shadowMatrix, m.constData(), 16 * sizeof(float));
2201 lightData.shadowAtlasUV0[0] = pEntry->m_atlasInfo[0].uOffset;
2202 lightData.shadowAtlasUV0[1] = pEntry->m_atlasInfo[0].vOffset;
2203 lightData.shadowAtlasLayer0 = pEntry->m_atlasInfo[0].layerIndex;
2204
2205 } else {
2206 Q_ASSERT(theLight->type == QSSGRenderLight::Type::PointLight);
2207 memcpy(lightData.shadowMatrix, pEntry->m_lightView.constData(), 16 * sizeof(float));
2208 lightData.shadowAtlasUV0[0] = pEntry->m_atlasInfo[0].uOffset;
2209 lightData.shadowAtlasUV0[1] = pEntry->m_atlasInfo[0].vOffset;
2210 lightData.shadowAtlasLayer0 = pEntry->m_atlasInfo[0].layerIndex;
2211 lightData.shadowAtlasUV1[0] = pEntry->m_atlasInfo[1].uOffset;
2212 lightData.shadowAtlasUV1[1] = pEntry->m_atlasInfo[1].vOffset;
2213 lightData.shadowAtlasLayer1 = pEntry->m_atlasInfo[1].layerIndex;
2214 }
2215 shadowCount++;
2216
2217 } else {
2218 lightData.enableShadows = 0.0f;
2219 }
2220
2221 lightCount++;
2222 }
2223
2224 theLightAmbientTotal += theLight->m_ambientColor;
2225 }
2226
2227 // Shadow Map Atlas Texture (if needed)
2228 if (shadowCount > 0 || directionalShadowCount > 0)
2229 shaders.setShadowMapAtlasTexture(inRenderProperties.getShadowMapManager()->shadowMapAtlasTexture());
2230 else
2231 shaders.setShadowMapAtlasTexture(nullptr);
2232
2233 const QSSGRhiRenderableTexture *depthTexture = inRenderProperties.getRenderResult(QSSGFrameData::RenderResult::DepthTexture);
2234 const QSSGRhiRenderableTexture *normalTexture = inRenderProperties.getRenderResult(QSSGFrameData::RenderResult::NormalTexture);
2235 const QSSGRhiRenderableTexture *ssaoTexture = inRenderProperties.getRenderResult(QSSGFrameData::RenderResult::AoTexture);
2236 const QSSGRhiRenderableTexture *screenTexture = inRenderProperties.getRenderResult(QSSGFrameData::RenderResult::ScreenTexture);
2237
2238 shaders.setDepthTexture(depthTexture->texture);
2239 shaders.setNormalTexture(normalTexture->texture);
2240 shaders.setSsaoTexture(ssaoTexture->texture);
2241 shaders.setScreenTexture(screenTexture->texture);
2242 shaders.setLightmapTexture(lightmapTexture);
2243
2244 const QSSGRenderLayer &layer = QSSGLayerRenderData::getCurrent(*renderContext.renderer())->layer;
2245 QSSGRenderImage *theLightProbe = layer.lightProbe;
2246 const auto &lightProbeData = layer.lightProbeSettings;
2247
2248 // If the material has its own IBL Override, we should use that image instead.
2249 QSSGRenderImage *materialIblProbe = materialAdapter->iblProbe();
2250 if (materialIblProbe)
2251 theLightProbe = materialIblProbe;
2252 QSSGRenderImageTexture lightProbeTexture;
2253 if (theLightProbe)
2254 lightProbeTexture = renderContext.bufferManager()->loadRenderImage(theLightProbe, QSSGBufferManager::MipModeBsdf);
2255 if (theLightProbe && lightProbeTexture.m_texture) {
2256 QSSGRenderTextureCoordOp theHorzLightProbeTilingMode = theLightProbe->m_horizontalTilingMode;
2257 QSSGRenderTextureCoordOp theVertLightProbeTilingMode = theLightProbe->m_verticalTilingMode;
2258 const int maxMipLevel = lightProbeTexture.m_mipmapCount - 1;
2259
2260 if (!materialIblProbe && !lightProbeData.probeOrientation.isIdentity()) {
2261 shaders.setUniform(ubufData, "qt_lightProbeOrientation",
2262 lightProbeData.probeOrientation.constData(),
2263 12 * sizeof(float), &cui.lightProbeOrientationIdx,
2264 QSSGRhiShaderPipeline::UniformFlag::Mat3);
2265 }
2266
2267 const float props[4] = { 0.0f, float(maxMipLevel), lightProbeData.probeHorizon, lightProbeData.probeExposure };
2268 shaders.setUniform(ubufData, "qt_lightProbeProperties", props, 4 * sizeof(float), &cui.lightProbePropertiesIdx);
2269
2270 shaders.setLightProbeTexture(lightProbeTexture.m_texture, theHorzLightProbeTilingMode, theVertLightProbeTilingMode);
2271 } else {
2272 // no lightprobe
2273 const float emptyProps[4] = { 0.0f, 0.0f, -1.0f, 0.0f };
2274 shaders.setUniform(ubufData, "qt_lightProbeProperties", emptyProps, 4 * sizeof(float), &cui.lightProbePropertiesIdx);
2275
2276 shaders.setLightProbeTexture(nullptr);
2277 }
2278
2279 if (receivesReflections && reflectionProbe.enabled) {
2280 shaders.setUniform(ubufData, "qt_reflectionProbeCubeMapCenter", &reflectionProbe.probeCubeMapCenter, 3 * sizeof(float), &cui.reflectionProbeCubeMapCenter);
2281 shaders.setUniform(ubufData, "qt_reflectionProbeBoxMin", &reflectionProbe.probeBoxMin, 3 * sizeof(float), &cui.reflectionProbeBoxMin);
2282 shaders.setUniform(ubufData, "qt_reflectionProbeBoxMax", &reflectionProbe.probeBoxMax, 3 * sizeof(float), &cui.reflectionProbeBoxMax);
2283 shaders.setUniform(ubufData, "qt_reflectionProbeCorrection", &reflectionProbe.parallaxCorrection, sizeof(int), &cui.reflectionProbeCorrection);
2284 }
2285
2286 const QVector3D emissiveColor = materialAdapter->emissiveColor();
2287 shaders.setUniform(ubufData, "qt_material_emissive_color", &emissiveColor, 3 * sizeof(float), &cui.material_emissiveColorIdx);
2288
2289 const auto qMix = [](float x, float y, float a) {
2290 return (x * (1.0f - a) + (y * a));
2291 };
2292
2293 const auto qMix3 = [&qMix](const QVector3D &x, const QVector3D &y, float a) {
2294 return QVector3D{qMix(x.x(), y.x(), a), qMix(x.y(), y.y(), a), qMix(x.z(), y.z(), a)};
2295 };
2296
2297 const QVector4D color = materialAdapter->color();
2298 const QVector3D materialSpecularTint = materialAdapter->specularTint();
2299 const QVector3D specularTint = materialAdapter->isPrincipled() ? qMix3(QVector3D(1.0f, 1.0f, 1.0f), color.toVector3D(), materialSpecularTint.x())
2300 : materialSpecularTint;
2301 shaders.setUniform(ubufData, "qt_material_base_color", &color, 4 * sizeof(float), &cui.material_baseColorIdx);
2302
2303 const float ior = materialAdapter->ior();
2304 QVector4D specularColor(specularTint, ior);
2305 shaders.setUniform(ubufData, "qt_material_specular", &specularColor, 4 * sizeof(float), &cui.material_specularIdx);
2306
2307 const bool hasLighting = materialAdapter->hasLighting();
2308 shaders.setLightsEnabled(hasLighting);
2309 if (hasLighting) {
2310 const float lightAndShadowCounts[4] = {
2311 float(lightCount),
2312 float(directionalLightCount),
2313 float(shadowCount),
2314 float(directionalShadowCount)
2315 };
2316 shaders.setUniform(ubufData, "qt_lightAndShadowCounts", &lightAndShadowCounts, 4 * sizeof(float), &cui.lightAndShadowCountsIdx);
2317
2318 const size_t lightDataSize = lightCount * sizeof(QSSGShaderLightData);
2319 const size_t directionalLightDataSize = directionalLightCount * sizeof(QSSGShaderDirectionalLightData);
2320
2321 memcpy(ubufData + shaders.ub0LightDataOffset(), &lightsUniformData, lightDataSize);
2322 memcpy(ubufData + shaders.ub0DirectionalLightDataOffset(), &directionalLightsUniformData, directionalLightDataSize);
2323 }
2324
2325 shaders.setUniform(ubufData, "qt_light_ambient_total", &theLightAmbientTotal, 3 * sizeof(float), &cui.light_ambient_totalIdx);
2326
2327 const float materialProperties[4] = {
2328 materialAdapter->specularAmount(),
2329 materialAdapter->specularRoughness(),
2330 materialAdapter->metalnessAmount(),
2331 inOpacity
2332 };
2333 shaders.setUniform(ubufData, "qt_material_properties", materialProperties, 4 * sizeof(float), &cui.material_propertiesIdx);
2334
2335 const float materialProperties2[4] = {
2336 materialAdapter->fresnelPower(),
2337 materialAdapter->bumpAmount(),
2338 materialAdapter->translucentFallOff(),
2339 materialAdapter->diffuseLightWrap()
2340 };
2341 shaders.setUniform(ubufData, "qt_material_properties2", materialProperties2, 4 * sizeof(float), &cui.material_properties2Idx);
2342
2343 const float materialProperties3[4] = {
2344 materialAdapter->occlusionAmount(),
2345 materialAdapter->alphaCutOff(),
2346 materialAdapter->clearcoatAmount(),
2347 materialAdapter->clearcoatRoughnessAmount()
2348 };
2349 shaders.setUniform(ubufData, "qt_material_properties3", materialProperties3, 4 * sizeof(float), &cui.material_properties3Idx);
2350
2351 const float materialProperties4[4] = {
2352 materialAdapter->heightAmount(),
2353 materialAdapter->minHeightSamples(),
2354 materialAdapter->maxHeightSamples(),
2355 materialAdapter->transmissionFactor()
2356 };
2357 shaders.setUniform(ubufData, "qt_material_properties4", materialProperties4, 4 * sizeof(float), &cui.material_properties4Idx);
2358
2359 const bool hasCustomFrag = materialAdapter->hasCustomShaderSnippet(QSSGShaderCache::ShaderType::Fragment);
2360 if (!hasCustomFrag) {
2361 if (inProperties.m_fresnelScaleBiasEnabled.getValue(inKey) || inProperties.m_clearcoatFresnelScaleBiasEnabled.getValue(inKey)) {
2362 const float materialProperties5[4] = {
2363 materialAdapter->fresnelScale(),
2364 materialAdapter->fresnelBias(),
2365 materialAdapter->clearcoatFresnelScale(),
2366 materialAdapter->clearcoatFresnelBias()
2367 };
2368 shaders.setUniform(ubufData, "qt_material_properties5", materialProperties5, 4 * sizeof(float), &cui.material_properties5Idx);
2369 }
2370
2371 const float material_clearcoat_normal_strength = materialAdapter->clearcoatNormalStrength();
2372 shaders.setUniform(ubufData, "qt_material_clearcoat_normal_strength", &material_clearcoat_normal_strength, sizeof(float), &cui.clearcoatNormalStrengthIdx);
2373
2374 const float material_clearcoat_fresnel_power = materialAdapter->clearcoatFresnelPower();
2375 shaders.setUniform(ubufData, "qt_material_clearcoat_fresnel_power", &material_clearcoat_fresnel_power, sizeof(float), &cui.clearcoatFresnelPowerIdx);
2376 // We only ever use attenuation and thickness uniforms when using transmission
2377 if (materialAdapter->isTransmissionEnabled()) {
2378 const QVector4D attenuationProperties(materialAdapter->attenuationColor(), materialAdapter->attenuationDistance());
2379 shaders.setUniform(ubufData, "qt_material_attenuation", &attenuationProperties, 4 * sizeof(float), &cui.material_attenuationIdx);
2380
2381 const float thickness = materialAdapter->thicknessFactor();
2382 shaders.setUniform(ubufData, "qt_material_thickness", &thickness, sizeof(float), &cui.thicknessFactorIdx);
2383 }
2384 }
2385
2386 const float rhiProperties[4] = {
2387 globalRenderData.isYUpInFramebuffer ? 1.0f : -1.0f,
2388 globalRenderData.isYUpInNDC ? 1.0f : -1.0f,
2389 globalRenderData.isClipDepthZeroToOne ? 0.0f : -1.0f,
2390 0.0f // unused
2391 };
2392 shaders.setUniform(ubufData, "qt_rhi_properties", rhiProperties, 4 * sizeof(float), &cui.rhiPropertiesIdx);
2393
2394 qsizetype imageIdx = 0;
2395 for (QSSGRenderableImage *theImage = inFirstImage; theImage; theImage = theImage->m_nextImage, ++imageIdx) {
2396 // we need to map image to uniform name: "image0_rotations", "image0_offsets", etc...
2397 const auto &names = imageStringTable[int(theImage->m_mapType)];
2398 if (imageIdx == cui.imageIndices.size())
2399 cui.imageIndices.append(QSSGRhiShaderPipeline::CommonUniformIndices::ImageIndices());
2400 auto &indices = cui.imageIndices[imageIdx];
2401
2402 const QMatrix4x4 &textureTransform = theImage->m_imageNode.m_textureTransform;
2403 // We separate rotational information from offset information so that just maybe the shader
2404 // will attempt to push less information to the card.
2405 const float *dataPtr(textureTransform.constData());
2406 // The third member of the offsets contains a flag indicating if the texture was
2407 // premultiplied or not.
2408 // We use this to mix the texture alpha.
2409 const float offsets[3] = { dataPtr[12], dataPtr[13], 0.0f /* non-premultiplied */ };
2410 shaders.setUniform(ubufData, names.imageOffsets, offsets, sizeof(offsets), &indices.imageOffsetsUniformIndex);
2411 // Grab just the upper 2x2 rotation matrix from the larger matrix.
2412 const float rotations[4] = { dataPtr[0], dataPtr[4], dataPtr[1], dataPtr[5] };
2413 shaders.setUniform(ubufData, names.imageRotations, rotations, sizeof(rotations), &indices.imageRotationsUniformIndex);
2414 }
2415
2416 if (shadowDepthAdjust)
2417 shaders.setUniform(ubufData, "qt_shadowDepthAdjust", shadowDepthAdjust, 2 * sizeof(float), &cui.shadowDepthAdjustIdx);
2418
2419 const bool usesPointsTopology = inProperties.m_usesPointsTopology.getValue(inKey);
2420 if (usesPointsTopology) {
2421 const float pointSize = materialAdapter->pointSize();
2422 shaders.setUniform(ubufData, "qt_materialPointSize", &pointSize, sizeof(float), &cui.pointSizeIdx);
2423 }
2424
2425 // qt_fogColor = (fogColor.x, fogColor.y, fogColor.z, fogDensity)
2426 // qt_fogDepthProperties = (fogDepthBegin, fogDepthEnd, fogDepthCurve, fogDepthEnabled ? 1.0 : 0.0)
2427 // qt_fogHeightProperties = (fogHeightMin, fogHeightMax, fogHeightCurve, fogHeightEnabled ? 1.0 : 0.0)
2428 // qt_fogTransmitProperties = (fogTransmitCurve, 0.0, 0.0, fogTransmitEnabled ? 1.0 : 0.0)
2429 if (inRenderProperties.layer.fog.enabled) {
2430 const float fogColor[4] = {
2431 inRenderProperties.layer.fog.color.x(),
2432 inRenderProperties.layer.fog.color.y(),
2433 inRenderProperties.layer.fog.color.z(),
2434 inRenderProperties.layer.fog.density
2435 };
2436 shaders.setUniform(ubufData, "qt_fogColor", fogColor, 4 * sizeof(float), &cui.fogColorIdx);
2437 const float fogDepthProperties[4] = {
2438 inRenderProperties.layer.fog.depthBegin,
2439 inRenderProperties.layer.fog.depthEnd,
2440 inRenderProperties.layer.fog.depthCurve,
2441 inRenderProperties.layer.fog.depthEnabled ? 1.0f : 0.0f
2442 };
2443 shaders.setUniform(ubufData, "qt_fogDepthProperties", fogDepthProperties, 4 * sizeof(float), &cui.fogDepthPropertiesIdx);
2444 const float fogHeightProperties[4] = {
2445 inRenderProperties.layer.fog.heightMin,
2446 inRenderProperties.layer.fog.heightMax,
2447 inRenderProperties.layer.fog.heightCurve,
2448 inRenderProperties.layer.fog.heightEnabled ? 1.0f : 0.0f
2449 };
2450 shaders.setUniform(ubufData, "qt_fogHeightProperties", fogHeightProperties, 4 * sizeof(float), &cui.fogHeightPropertiesIdx);
2451 const float fogTransmitProperties[4] = {
2452 inRenderProperties.layer.fog.transmitCurve,
2453 0.0f,
2454 0.0f,
2455 inRenderProperties.layer.fog.transmitEnabled ? 1.0f : 0.0f
2456 };
2457 shaders.setUniform(ubufData, "qt_fogTransmitProperties", fogTransmitProperties, 4 * sizeof(float), &cui.fogTransmitPropertiesIdx);
2458 }
2459
2460 inPipelineState->lineWidth = materialAdapter->lineWidth();
2461}
2462
2463QT_END_NAMESPACE
2464
2465QList<QByteArrayView> QtQuick3DEditorHelpers::CustomMaterial::reservedArgumentNames()
2466{
2467 return {std::begin(qssg_shader_arg_names), std::end(qssg_shader_arg_names) };;
2468}
void textureCoordVariableName(char(&outString)[TEXCOORD_VAR_LEN], quint8 uvSet)
void textureCoordVaryingName(char(&outString)[TEXCOORD_VAR_LEN], quint8 uvSet)
static void generateImageUVSampler(QSSGMaterialVertexPipeline &vertexGenerator, QSSGStageGeneratorBase &fragmentShader, const QSSGShaderDefaultMaterialKey &key, const ImageStringSet &names, char(&outString)[TEXCOORD_VAR_LEN], quint8 uvSet=0)
static void generateImageUVCoordinates(QSSGMaterialVertexPipeline &vertexShader, QSSGStageGeneratorBase &fragmentShader, const QSSGShaderDefaultMaterialKey &key, const ImageStringSet &names, bool forceFragmentShader=false, quint32 uvSet=0, bool reuseImageCoords=false, bool useEnvironmentMapping=false)
static constexpr QByteArrayView qssg_shader_arg_names[]
static QByteArray uvTransform(const QByteArray &imageRotations, const QByteArray &imageOffsets)
static void addLocalVariable(QSSGStageGeneratorBase &inGenerator, const QByteArray &inName, const QByteArray &inType)
static void generateFragmentShader(QSSGStageGeneratorBase &fragmentShader, QSSGMaterialVertexPipeline &vertexShader, const QSSGShaderDefaultMaterialKey &inKey, const QSSGShaderDefaultMaterialKeyProperties &keyProps, const QSSGShaderFeatures &featureSet, const QSSGRenderGraphObject &inMaterial, QSSGShaderLibraryManager &shaderLibraryManager)
static void generateFragmentDefines(QSSGStageGeneratorBase &fragmentShader, const QSSGShaderDefaultMaterialKey &inKey, const QSSGShaderDefaultMaterialKeyProperties &keyProps, QSSGShaderMaterialAdapter *materialAdapter, QSSGShaderLibraryManager &shaderLibraryManager)
static QSSGShaderMaterialAdapter * getMaterialAdapter(const QSSGRenderGraphObject &inMaterial)
static quint32 softShadowQualityToInt(QSSGRenderLight::SoftShadowQuality quality)
PassRequirmentsState(const QSSGShaderDefaultMaterialKey &inKey, const QSSGShaderDefaultMaterialKeyProperties &keyProps, const QSSGShaderFeatures &featureSet, const SamplerState &samplerState)
QSSGRenderLayer::MaterialDebugMode debugMode
void generateImageUVAndSampler(QSSGRenderableImage::Type imageType, QSSGMaterialVertexPipeline &vertexShader, QSSGStageGeneratorBase &fragmentShader, const QSSGShaderDefaultMaterialKey &key, bool forceFragmentShader=false)
const char * samplerName(QSSGRenderableImage::Type imageType) const
bool uvCoordinatesGenerated[QSSGShaderDefaultMaterialKeyProperties::ImageMapNames::ImageMapCount]
bool uvGenerated(QSSGShaderDefaultMaterialKeyProperties::ImageMapNames imageType) const
SamplerState(const QSSGShaderDefaultMaterialKey &inKey, const QSSGShaderDefaultMaterialKeyProperties &keyProps)
const QSSGShaderDefaultMaterialKey & m_inKey
std::optional< QSSGShaderDefaultMaterialKeyProperties::ImageMapNames > fromType(QSSGRenderableImage::Type type) const
bool hasImage(QSSGRenderableImage::Type type) const
const QSSGShaderDefaultMaterialKeyProperties & m_keyProps
const char * fragCoordsName(QSSGRenderableImage::Type imageType) const