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