1 /****************************************************************************
2 **
3 ** Copyright (C) 2008-2012 NVIDIA Corporation.
4 ** Copyright (C) 2019 The Qt Company Ltd.
5 ** Contact: https://www.qt.io/licensing/
6 **
7 ** This file is part of Qt Quick 3D.
8 **
9 ** $QT_BEGIN_LICENSE:GPL$
10 ** Commercial License Usage
11 ** Licensees holding valid commercial Qt licenses may use this file in
12 ** accordance with the commercial license agreement provided with the
13 ** Software or, alternatively, in accordance with the terms contained in
14 ** a written agreement between you and The Qt Company. For licensing terms
15 ** and conditions see https://www.qt.io/terms-conditions. For further
16 ** information use the contact form at https://www.qt.io/contact-us.
17 **
18 ** GNU General Public License Usage
19 ** Alternatively, this file may be used under the terms of the GNU
20 ** General Public License version 3 or (at your option) any later version
21 ** approved by the KDE Free Qt Foundation. The licenses are as published by
22 ** the Free Software Foundation and appearing in the file LICENSE.GPL3
23 ** included in the packaging of this file. Please review the following
24 ** information to ensure the GNU General Public License requirements will
25 ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
26 **
27 ** $QT_END_LICENSE$
28 **
29 ****************************************************************************/
30
31 /* clang-format off */
32
33 #include <QtQuick3DUtils/private/qssgutils_p.h>
34
35 #include <QtQuick3DRender/private/qssgrendercontext_p.h>
36 #include <QtQuick3DRender/private/qssgrendershaderprogram_p.h>
37 #include <QtQuick3DRender/private/qssgrendershaderprogram_p.h>
38
39 #include <QtQuick3DRuntimeRender/private/qssgrenderdefaultmaterialshadergenerator_p.h>
40 #include <QtQuick3DRuntimeRender/private/qssgrendercontextcore_p.h>
41 #include <QtQuick3DRuntimeRender/private/qssgrendershadercodegeneratorv2_p.h>
42 #include <QtQuick3DRuntimeRender/private/qssgrenderableimage_p.h>
43 #include <QtQuick3DRuntimeRender/private/qssgrenderimage_p.h>
44 #include <QtQuick3DRuntimeRender/private/qssgrenderlight_p.h>
45 #include <QtQuick3DRuntimeRender/private/qssgrendercamera_p.h>
46 #include <QtQuick3DRuntimeRender/private/qssgrendershadowmap_p.h>
47 #include <QtQuick3DRuntimeRender/private/qssgrendercustommaterial_p.h>
48 #include <QtQuick3DRuntimeRender/private/qssgrenderdynamicobjectsystem_p.h>
49 #include <QtQuick3DRuntimeRender/private/qssgrenderlightconstantproperties_p.h>
50 #include <QtQuick3DRuntimeRender/private/qssgrendershaderkeys_p.h>
51 #include <QtQuick3DRuntimeRender/private/qssgrendererimplshaders_p.h>
52
53 #include <QtCore/QByteArray>
54
55 QT_BEGIN_NAMESPACE
56
57 namespace {
58 /**
59 * Cached light property lookups, used one per light so a shader generator for N
60 * lights will have an array of N of these lookup objects.
61 */
62 struct QSSGShaderLightProperties
63 {
64 // Color of the light
65 QVector3D lightColor;
66 QSSGLightSourceShader lightData;
67 };
68
69 struct QSSGShadowMapProperties
70 {
71 QSSGRenderCachedShaderProperty<QSSGRenderTexture2D *> m_shadowmapTexture; ///< shadow texture
72 QSSGRenderCachedShaderProperty<QSSGRenderTextureCube *> m_shadowCubeTexture; ///< shadow cubemap
73 QSSGRenderCachedShaderProperty<QMatrix4x4> m_shadowmapMatrix; ///< world to ligh space transform matrix
74 QSSGRenderCachedShaderProperty<QVector4D> m_shadowmapSettings; ///< shadow rendering settings
75
76 QSSGShadowMapProperties() = default;
QSSGShadowMapProperties__anon06cffe670111::QSSGShadowMapProperties77 QSSGShadowMapProperties(const QByteArray &shadowmapTextureName,
78 const QByteArray &shadowcubeTextureName,
79 const QByteArray &shadowmapMatrixName,
80 const QByteArray &shadowmapSettingsName,
81 const QSSGRef<QSSGRenderShaderProgram> &inShader)
82 : m_shadowmapTexture(shadowmapTextureName, inShader)
83 , m_shadowCubeTexture(shadowcubeTextureName, inShader)
84 , m_shadowmapMatrix(shadowmapMatrixName, inShader)
85 , m_shadowmapSettings(shadowmapSettingsName, inShader)
86 {
87 }
88 };
89
90 /**
91 * The results of generating a shader. Caches all possible variable names into
92 * typesafe objects.
93 */
94 struct QSSGShaderGeneratorGeneratedShader
95 {
96 QAtomicInt ref;
97 QSSGRef<QSSGRenderShaderProgram> m_shader;
98 // Specific properties we know the shader has to have.
99 QSSGRenderCachedShaderProperty<QMatrix4x4> m_mvp;
100 QSSGRenderCachedShaderProperty<QMatrix3x3> m_normalMatrix;
101 QSSGRenderCachedShaderProperty<QMatrix4x4> m_globalTransform;
102 QSSGRenderCachedShaderProperty<QMatrix4x4> m_viewProj;
103 QSSGRenderCachedShaderProperty<QMatrix4x4> m_viewMatrix;
104 QSSGRenderCachedShaderProperty<QVector3D> m_materialDiffuse;
105 QSSGRenderCachedShaderProperty<QVector4D> m_materialProperties;
106 // tint, ior
107 QSSGRenderCachedShaderProperty<QVector4D> m_materialSpecular;
108 QSSGRenderCachedShaderProperty<float> m_bumpAmount;
109 QSSGRenderCachedShaderProperty<float> m_displaceAmount;
110 QSSGRenderCachedShaderProperty<float> m_translucentFalloff;
111 QSSGRenderCachedShaderProperty<float> m_diffuseLightWrap;
112 QSSGRenderCachedShaderProperty<float> m_fresnelPower;
113 QSSGRenderCachedShaderProperty<float> m_occlusionAmount;
114 QSSGRenderCachedShaderProperty<float> m_alphaCutoff;
115 QSSGRenderCachedShaderProperty<QVector4D> m_baseColor;
116 QSSGRenderCachedShaderProperty<QVector3D> m_cameraPosition;
117 QSSGRenderCachedShaderProperty<QVector3D> m_cameraDirection;
118 QVector3D m_lightAmbientTotal;
119 QSSGRenderCachedShaderProperty<QVector3D> m_materialDiffuseLightAmbientTotal;
120 QSSGRenderCachedShaderProperty<QVector2D> m_cameraProperties;
121
122 QSSGRenderCachedShaderProperty<QSSGRenderTexture2D *> m_depthTexture;
123 QSSGRenderCachedShaderProperty<QSSGRenderTexture2D *> m_aoTexture;
124 QSSGRenderCachedShaderProperty<QSSGRenderTexture2D *> m_lightProbe;
125 QSSGRenderCachedShaderProperty<QVector4D> m_lightProbeProps;
126 QSSGRenderCachedShaderProperty<QVector4D> m_lightProbeOpts;
127 QSSGRenderCachedShaderProperty<QVector4D> m_lightProbeRot;
128 QSSGRenderCachedShaderProperty<QVector4D> m_lightProbeOfs;
129 QSSGRenderCachedShaderProperty<QVector2D> m_lightProbeSize;
130 QSSGRenderCachedShaderProperty<QSSGRenderTexture2D *> m_lightProbe2;
131 QSSGRenderCachedShaderProperty<QVector4D> m_lightProbe2Props;
132 QSSGRenderCachedShaderProperty<QVector2D> m_lightProbe2Size;
133
134 QSSGRenderCachedShaderBuffer<QSSGRenderShaderConstantBuffer> m_aoShadowParams;
135 QSSGRenderCachedShaderBuffer<QSSGRenderShaderConstantBuffer> m_lightsBuffer;
136
137 QSSGLightConstantProperties<QSSGShaderGeneratorGeneratedShader> *m_lightConstantProperties = nullptr;
138
139 // Cache the image property name lookups
140 QVector<QSSGShaderTextureProperties> m_images;
141 QVector<QSSGShaderLightProperties> m_lights;
142 // Cache shadow map properties
143 QVector<QSSGShadowMapProperties> m_shadowMaps;
144
QSSGShaderGeneratorGeneratedShader__anon06cffe670111::QSSGShaderGeneratorGeneratedShader145 QSSGShaderGeneratorGeneratedShader(const QSSGRef<QSSGRenderShaderProgram> &inShader,
146 const QSSGRef<QSSGRenderContext> &inContext)
147 : m_shader(inShader)
148 , m_mvp("modelViewProjection", inShader)
149 , m_normalMatrix("normalMatrix", inShader)
150 , m_globalTransform("modelMatrix", inShader)
151 , m_viewProj("viewProjectionMatrix", inShader)
152 , m_viewMatrix("viewMatrix", inShader)
153 , m_materialDiffuse("material_diffuse", inShader)
154 , m_materialProperties("material_properties", inShader)
155 , m_materialSpecular("material_specular", inShader)
156 , m_bumpAmount("bumpAmount", inShader)
157 , m_displaceAmount("displaceAmount", inShader)
158 , m_translucentFalloff("translucentFalloff", inShader)
159 , m_diffuseLightWrap("diffuseLightWrap", inShader)
160 , m_fresnelPower("fresnelPower", inShader)
161 , m_occlusionAmount("occlusionAmount", inShader)
162 , m_alphaCutoff("alphaCutoff", inShader)
163 , m_baseColor("base_color", inShader)
164 , m_cameraPosition("cameraPosition", inShader)
165 , m_cameraDirection("cameraDirection", inShader)
166 , m_materialDiffuseLightAmbientTotal("light_ambient_total", inShader)
167 , m_cameraProperties("cameraProperties", inShader)
168 , m_depthTexture("depthTexture", inShader)
169 , m_aoTexture("aoTexture", inShader)
170 , m_lightProbe("lightProbe", inShader)
171 , m_lightProbeProps("lightProbeProperties", inShader)
172 , m_lightProbeOpts("lightProbeOptions", inShader)
173 , m_lightProbeRot("lightProbeRotation", inShader)
174 , m_lightProbeOfs("lightProbeOffset", inShader)
175 , m_lightProbeSize("lightProbeSize", inShader)
176 , m_lightProbe2("lightProbe2", inShader)
177 , m_lightProbe2Props("lightProbe2Properties", inShader)
178 , m_lightProbe2Size("lightProbe2Size", inShader)
179 , m_aoShadowParams("aoShadow", inShader)
180 , m_lightsBuffer("lightsBuffer", inShader)
181 {
182 Q_UNUSED(inContext)
183 }
~QSSGShaderGeneratorGeneratedShader__anon06cffe670111::QSSGShaderGeneratorGeneratedShader184 ~QSSGShaderGeneratorGeneratedShader() { delete m_lightConstantProperties; }
185 };
186
187 struct QSSGShaderGenerator : public QSSGDefaultMaterialShaderGeneratorInterface
188 {
189 const QSSGRenderDefaultMaterial *m_currentMaterial;
190
191 typedef QHash<QSSGRef<QSSGRenderShaderProgram>, QSSGRef<QSSGShaderGeneratorGeneratedShader>> ProgramToShaderMap;
192 ProgramToShaderMap m_programToShaderMap;
193
194 QSSGRef<QSSGRenderShadowMap> m_shadowMapManager;
195 bool m_lightsAsSeparateUniforms;
196
197 QByteArray m_imageSampler;
198 QByteArray m_imageFragCoords;
199 QByteArray m_imageOffsets;
200 QByteArray m_imageRotations;
201 QByteArray m_imageTemp;
202 QByteArray m_imageSamplerSize;
203
204 QByteArray m_lightColor;
205 QByteArray m_lightSpecularColor;
206 QByteArray m_lightAttenuation;
207 QByteArray m_lightConstantAttenuation;
208 QByteArray m_lightLinearAttenuation;
209 QByteArray m_lightQuadraticAttenuation;
210 QByteArray m_normalizedDirection;
211 QByteArray m_lightDirection;
212 QByteArray m_lightPos;
213 QByteArray m_lightUp;
214 QByteArray m_lightRt;
215 QByteArray m_lightConeAngle;
216 QByteArray m_lightInnerConeAngle;
217 QByteArray m_relativeDistance;
218 QByteArray m_relativeDirection;
219 QByteArray m_spotAngle;
220
221 QByteArray m_shadowMapStem;
222 QByteArray m_shadowCubeStem;
223 QByteArray m_shadowMatrixStem;
224 QByteArray m_shadowCoordStem;
225 QByteArray m_shadowControlStem;
226
QSSGShaderGenerator__anon06cffe670111::QSSGShaderGenerator227 QSSGShaderGenerator(QSSGRenderContextInterface *inRc)
228 : QSSGDefaultMaterialShaderGeneratorInterface (inRc)
229 , m_shadowMapManager(nullptr)
230 , m_lightsAsSeparateUniforms(false)
231 {
232 }
233
programGenerator__anon06cffe670111::QSSGShaderGenerator234 QSSGRef<QSSGShaderProgramGeneratorInterface> programGenerator() { return m_programGenerator; }
vertexGenerator__anon06cffe670111::QSSGShaderGenerator235 QSSGDefaultMaterialVertexPipelineInterface &vertexGenerator() { return *m_currentPipeline; }
fragmentGenerator__anon06cffe670111::QSSGShaderGenerator236 QSSGShaderStageGeneratorInterface &fragmentGenerator()
237 {
238 return *m_programGenerator->getStage(QSSGShaderGeneratorStage::Fragment);
239 }
key__anon06cffe670111::QSSGShaderGenerator240 QSSGShaderDefaultMaterialKey &key() { return *m_currentKey; }
material__anon06cffe670111::QSSGShaderGenerator241 const QSSGRenderDefaultMaterial *material() { return m_currentMaterial; }
hasTransparency__anon06cffe670111::QSSGShaderGenerator242 bool hasTransparency() { return m_hasTransparency; }
243
addFunction__anon06cffe670111::QSSGShaderGenerator244 void addFunction(QSSGShaderStageGeneratorInterface &generator, const QByteArray &functionName)
245 {
246 generator.addFunction(functionName);
247 }
248
setupImageVariableNames__anon06cffe670111::QSSGShaderGenerator249 void setupImageVariableNames(size_t imageIdx)
250 {
251 QByteArray imageStem = "image";
252 char buf[16];
253 qsnprintf(buf, 16, "%d", int(imageIdx));
254 imageStem.append(buf);
255 imageStem.append("_");
256
257 m_imageSampler = imageStem;
258 m_imageSampler.append("sampler");
259 m_imageOffsets = imageStem;
260 m_imageOffsets.append("offsets");
261 m_imageRotations = imageStem;
262 m_imageRotations.append("rotations");
263 m_imageFragCoords = imageStem;
264 m_imageFragCoords.append("uv_coords");
265 m_imageSamplerSize = imageStem;
266 m_imageSamplerSize.append("size");
267 }
268
textureCoordVariableName__anon06cffe670111::QSSGShaderGenerator269 QByteArray textureCoordVariableName(size_t uvSet)
270 {
271 QByteArray texCoordTemp = "varTexCoord";
272 char buf[16];
273 qsnprintf(buf, 16, "%d", int(uvSet));
274 texCoordTemp.append(buf);
275 return texCoordTemp;
276 }
277
getImageVariableNames__anon06cffe670111::QSSGShaderGenerator278 ImageVariableNames getImageVariableNames(quint32 inIdx) override
279 {
280 setupImageVariableNames(inIdx);
281 ImageVariableNames retval;
282 retval.m_imageSampler = m_imageSampler;
283 retval.m_imageFragCoords = m_imageFragCoords;
284 return retval;
285 }
286
addLocalVariable__anon06cffe670111::QSSGShaderGenerator287 void addLocalVariable(QSSGShaderStageGeneratorInterface &inGenerator, const QByteArray &inName, const QByteArray &inType)
288 {
289 inGenerator << " " << inType << " " << inName << ";\n";
290 }
291
uvTransform__anon06cffe670111::QSSGShaderGenerator292 QByteArray uvTransform()
293 {
294 QByteArray transform;
295 transform = " uTransform = vec3(" + m_imageRotations + ".x, " + m_imageRotations + ".y, " + m_imageOffsets + ".x);\n";
296 transform += " vTransform = vec3(" + m_imageRotations + ".z, " + m_imageRotations + ".w, " + m_imageOffsets + ".y);\n";
297 return transform;
298 }
299
300 bool uvCoordsGenerated[32];
clearUVCoordsGen__anon06cffe670111::QSSGShaderGenerator301 void clearUVCoordsGen()
302 {
303 memset(uvCoordsGenerated, 0, sizeof(uvCoordsGenerated));
304 }
305
generateImageUVCoordinates__anon06cffe670111::QSSGShaderGenerator306 void generateImageUVCoordinates(QSSGShaderStageGeneratorInterface &inVertexPipeline, quint32 idx, quint32 uvSet, QSSGRenderableImage &image) override
307 {
308 if (uvCoordsGenerated[idx])
309 return;
310 QSSGDefaultMaterialVertexPipelineInterface &vertexShader(
311 static_cast<QSSGDefaultMaterialVertexPipelineInterface &>(inVertexPipeline));
312 QSSGShaderStageGeneratorInterface &fragmentShader(fragmentGenerator());
313 setupImageVariableNames(idx);
314 QByteArray textureCoordName = textureCoordVariableName(uvSet);
315 fragmentShader.addUniform(m_imageSampler, "sampler2D");
316 vertexShader.addUniform(m_imageOffsets, "vec3");
317 vertexShader.addUniform(m_imageRotations, "vec4");
318 QByteArray uvTrans = uvTransform();
319 if (image.m_image.m_mappingMode == QSSGRenderImage::MappingModes::Normal) {
320 vertexShader << uvTrans;
321 vertexShader.addOutgoing(m_imageFragCoords, "vec2");
322 addFunction(vertexShader, "getTransformedUVCoords");
323 vertexShader.generateUVCoords(key(), uvSet);
324 m_imageTemp = m_imageFragCoords;
325 m_imageTemp.append("temp");
326 vertexShader << " vec2 " << m_imageTemp << " = getTransformedUVCoords(vec3(" << textureCoordName << ", 1.0), uTransform, vTransform);\n";
327 if (image.m_image.m_textureData.m_textureFlags.isInvertUVCoords())
328 vertexShader << " " << m_imageTemp << ".y = 1.0 - " << m_imageTemp << ".y;\n";
329
330 vertexShader.assignOutput(m_imageFragCoords, m_imageTemp);
331 } else {
332 fragmentShader.addUniform(m_imageOffsets, "vec3");
333 fragmentShader.addUniform(m_imageRotations, "vec4");
334 fragmentShader << uvTrans;
335 vertexShader.generateEnvMapReflection(key());
336 addFunction(fragmentShader, "getTransformedUVCoords");
337 fragmentShader << " vec2 " << m_imageFragCoords << " = getTransformedUVCoords(environment_map_reflection, uTransform, vTransform);\n";
338 if (image.m_image.m_textureData.m_textureFlags.isInvertUVCoords())
339 fragmentShader << " " << m_imageFragCoords << ".y = 1.0 - " << m_imageFragCoords << ".y;\n";
340 }
341 uvCoordsGenerated[idx] = true;
342 }
343
generateImageUVSampler__anon06cffe670111::QSSGShaderGenerator344 void generateImageUVSampler(quint32 idx, quint32 uvSet = 0)
345 {
346 QSSGShaderStageGeneratorInterface &fragmentShader(fragmentGenerator());
347 setupImageVariableNames(idx);
348 fragmentShader.addUniform(m_imageSampler, "sampler2D");
349 m_imageFragCoords = textureCoordVariableName(uvSet);
350 vertexGenerator().generateUVCoords(key(), uvSet);
351 }
352
generateImageUVCoordinates__anon06cffe670111::QSSGShaderGenerator353 void generateImageUVCoordinates(quint32 idx, QSSGRenderableImage &image, quint32 uvSet = 0)
354 {
355 generateImageUVCoordinates(vertexGenerator(), idx, uvSet, image);
356 }
357
outputSpecularEquation__anon06cffe670111::QSSGShaderGenerator358 void outputSpecularEquation(QSSGRenderDefaultMaterial::MaterialSpecularModel inSpecularModel,
359 QSSGShaderStageGeneratorInterface &fragmentShader,
360 const QByteArray &inLightDir,
361 const QByteArray &inLightSpecColor)
362 {
363 switch (inSpecularModel) {
364 case QSSGRenderDefaultMaterial::MaterialSpecularModel::KGGX: {
365 fragmentShader.addInclude("defaultMaterialPhysGlossyBSDF.glsllib");
366 fragmentShader.addUniform("material_specular", "vec4");
367 fragmentShader << " global_specular_light.rgb += lightAttenuation * specularAmount"
368 " * kggxGlossyDefaultMtl(world_normal, tangent, -" << inLightDir << ".xyz, view_vector, " << inLightSpecColor << ".rgb, vec3(material_specular.rgb), roughnessAmount).rgb;\n";
369 } break;
370 case QSSGRenderDefaultMaterial::MaterialSpecularModel::KWard: {
371 fragmentShader.addInclude("defaultMaterialPhysGlossyBSDF.glsllib");
372 fragmentShader.addUniform("material_specular", "vec4");
373 fragmentShader << " global_specular_light.rgb += lightAttenuation * specularAmount"
374 " * wardGlossyDefaultMtl(world_normal, tangent, -" << inLightDir << ".xyz, view_vector, " << inLightSpecColor << ".rgb, vec3(material_specular.rgb), roughnessAmount).rgb;\n";
375 } break;
376 default:
377 addFunction(fragmentShader, "specularBSDF");
378 fragmentShader << " global_specular_light.rgb += lightAttenuation * specularAmount"
379 " * specularBSDF(world_normal, -" << inLightDir << ".xyz, view_vector, " << inLightSpecColor << ".rgb, 2.56 / (roughnessAmount + 0.01)).rgb;\n";
380 break;
381 }
382 }
383
outputDiffuseAreaLighting__anon06cffe670111::QSSGShaderGenerator384 void outputDiffuseAreaLighting(QSSGShaderStageGeneratorInterface &infragmentShader, const QByteArray &inPos, const QByteArray &inLightPrefix)
385 {
386 m_normalizedDirection = inLightPrefix + "_areaDir";
387 addLocalVariable(infragmentShader, m_normalizedDirection, "vec3");
388 infragmentShader << " lightAttenuation = calculateDiffuseAreaOld(" << m_lightDirection << ".xyz, " << m_lightPos << ".xyz, " << m_lightUp << ", " << m_lightRt << ", " << inPos << ", " << m_normalizedDirection << ");\n";
389 }
390
outputSpecularAreaLighting__anon06cffe670111::QSSGShaderGenerator391 void outputSpecularAreaLighting(QSSGShaderStageGeneratorInterface &infragmentShader,
392 const QByteArray &inPos,
393 const QByteArray &inView,
394 const QByteArray &inLightSpecColor)
395 {
396 addFunction(infragmentShader, "sampleAreaGlossyDefault");
397 infragmentShader.addUniform("material_specular", "vec4");
398 infragmentShader << "global_specular_light.rgb += " << inLightSpecColor << ".rgb * lightAttenuation * shadowFac * material_specular.rgb * specularAmount"
399 " * sampleAreaGlossyDefault(tanFrame, " << inPos << ", " << m_normalizedDirection << ", " << m_lightPos << ".xyz, " << m_lightRt << ".w, " << m_lightUp << ".w, " << inView << ", roughnessAmount).rgb;\n";
400 }
401
addTranslucencyIrradiance__anon06cffe670111::QSSGShaderGenerator402 void addTranslucencyIrradiance(QSSGShaderStageGeneratorInterface &infragmentShader,
403 QSSGRenderableImage *image,
404 bool areaLight)
405 {
406 if (image == nullptr)
407 return;
408
409 addFunction(infragmentShader, "diffuseReflectionWrapBSDF");
410 if (areaLight) {
411 infragmentShader << " global_diffuse_light.rgb += lightAttenuation * translucent_thickness_exp * diffuseReflectionWrapBSDF(-world_normal, " << m_normalizedDirection << ", " << m_lightColor << ".rgb, diffuseLightWrap).rgb;\n";
412 } else {
413 infragmentShader << " global_diffuse_light.rgb += lightAttenuation * translucent_thickness_exp * diffuseReflectionWrapBSDF(-world_normal, -" << m_normalizedDirection << ", " << m_lightColor << ".rgb, diffuseLightWrap).rgb;\n";
414 }
415 }
416
setupShadowMapVariableNames__anon06cffe670111::QSSGShaderGenerator417 void setupShadowMapVariableNames(size_t lightIdx)
418 {
419 m_shadowMapStem = "shadowmap";
420 m_shadowCubeStem = "shadowcube";
421 char buf[16];
422 qsnprintf(buf, 16, "%d", int(lightIdx));
423 m_shadowMapStem.append(buf);
424 m_shadowCubeStem.append(buf);
425 m_shadowMatrixStem = m_shadowMapStem;
426 m_shadowMatrixStem.append("_matrix");
427 m_shadowCoordStem = m_shadowMapStem;
428 m_shadowCoordStem.append("_coord");
429 m_shadowControlStem = m_shadowMapStem;
430 m_shadowControlStem.append("_control");
431 }
432
addShadowMapContribution__anon06cffe670111::QSSGShaderGenerator433 void addShadowMapContribution(QSSGShaderStageGeneratorInterface &inLightShader, quint32 lightIndex, QSSGRenderLight::Type inType)
434 {
435 setupShadowMapVariableNames(lightIndex);
436
437 inLightShader.addInclude("shadowMapping.glsllib");
438 if (inType == QSSGRenderLight::Type::Directional) {
439 inLightShader.addUniform(m_shadowMapStem, "sampler2D");
440 } else {
441 inLightShader.addUniform(m_shadowCubeStem, "samplerCube");
442 }
443 inLightShader.addUniform(m_shadowControlStem, "vec4");
444 inLightShader.addUniform(m_shadowMatrixStem, "mat4");
445
446 /*
447 if ( inType == RenderLightTypes::Area )
448 {
449 inLightShader << "vec2 " << m_shadowCoordStem << ";" << "\n";
450 inLightShader << " shadow_map_occl = sampleParaboloid( " << m_shadowMapStem << ", "
451 << m_shadowControlStem << ", "
452 <<
453 m_shadowMatrixStem << ", varWorldPos, vec2(1.0, " << m_shadowControlStem << ".z), "
454 << m_shadowCoordStem
455 << " );" << "\n";
456 }
457 else */
458 if (inType != QSSGRenderLight::Type::Directional) {
459 inLightShader << " shadow_map_occl = sampleCubemap(" << m_shadowCubeStem << ", " << m_shadowControlStem << ", " << m_shadowMatrixStem << ", " << m_lightPos << ".xyz, varWorldPos, vec2(1.0, " << m_shadowControlStem << ".z));\n";
460 } else {
461 inLightShader << " shadow_map_occl = sampleOrthographic(" << m_shadowMapStem << ", " << m_shadowControlStem << ", " << m_shadowMatrixStem << ", varWorldPos, vec2(1.0, " << m_shadowControlStem << ".z));\n";
462 }
463 }
464
addDisplacementMappingForDepthPass__anon06cffe670111::QSSGShaderGenerator465 void addDisplacementMappingForDepthPass(QSSGShaderStageGeneratorInterface &inShader) override
466 {
467 inShader.addIncoming("attr_uv0", "vec2");
468 inShader.addIncoming("attr_norm", "vec3");
469 inShader.addUniform("displacementSampler", "sampler2D");
470 inShader.addUniform("displaceAmount", "float");
471 inShader.addUniform("displacementMap_rot", "vec4");
472 inShader.addUniform("displacementMap_offset", "vec3");
473 inShader.addInclude("defaultMaterialFileDisplacementTexture.glsllib");
474
475 inShader << " vec3 uTransform = vec3(displacementMap_rot.x, displacementMap_rot.y, displacementMap_offset.x);\n"
476 " vec3 vTransform = vec3(displacementMap_rot.z, displacementMap_rot.w, displacementMap_offset.y);\n";
477 addFunction(inShader, "getTransformedUVCoords");
478 inShader << " vec2 uv_coords = attr_uv0;\n"
479 " uv_coords = getTransformedUVCoords(vec3(uv_coords, 1.0), uTransform, vTransform);\n"
480 " vec3 displacedPos = defaultMaterialFileDisplacementTexture(displacementSampler , displaceAmount, uv_coords , attr_norm, attr_pos);\n"
481 " gl_Position = modelViewProjection * vec4(displacedPos, 1.0);\n";
482 }
483
addDisplacementImageUniforms__anon06cffe670111::QSSGShaderGenerator484 void addDisplacementImageUniforms(QSSGShaderStageGeneratorInterface &inGenerator,
485 quint32 displacementImageIdx,
486 QSSGRenderableImage *displacementImage) override
487 {
488 if (displacementImage) {
489 setupImageVariableNames(displacementImageIdx);
490 inGenerator.addInclude("defaultMaterialFileDisplacementTexture.glsllib");
491 inGenerator.addUniform("modelMatrix", "mat4");
492 inGenerator.addUniform("cameraPosition", "vec3");
493 inGenerator.addUniform("displaceAmount", "float");
494 inGenerator.addUniform(m_imageSampler, "sampler2D");
495 }
496 }
497
maybeAddMaterialFresnel__anon06cffe670111::QSSGShaderGenerator498 void maybeAddMaterialFresnel(QSSGShaderStageGeneratorInterface &fragmentShader, QSSGDataView<quint32> inKey, bool &fragmentHasSpecularAmount, bool hasMetalness)
499 {
500 if (m_defaultMaterialShaderKeyProperties.m_fresnelEnabled.getValue(inKey)) {
501 addSpecularAmount(fragmentShader, fragmentHasSpecularAmount);
502 fragmentShader.addInclude("defaultMaterialFresnel.glsllib");
503 fragmentShader.addUniform("fresnelPower", "float");
504 fragmentShader.addUniform("material_specular", "vec4");
505 if (hasMetalness) {
506 fragmentShader << " // Add fresnel ratio\n"
507 " specularAmount *= defaultMaterialSimpleFresnel(specularBase, metalnessAmount, world_normal, view_vector, dielectricSpecular(material_properties.w), fresnelPower);\n";
508 } else {
509 fragmentShader << " // Add fresnel ratio\n"
510 " specularAmount *= defaultMaterialSimpleFresnelNoMetalness(world_normal, view_vector, dielectricSpecular(material_properties.w), fresnelPower);\n";
511 }
512 }
513 }
setupLightVariableNames__anon06cffe670111::QSSGShaderGenerator514 void setupLightVariableNames(qint32 lightIdx, QSSGRenderLight &inLight)
515 {
516 Q_ASSERT(lightIdx > -1);
517 if (m_lightsAsSeparateUniforms) {
518 char buf[16];
519 qsnprintf(buf, 16, "light_%d", int(lightIdx));
520 QByteArray lightStem = buf;
521 m_lightColor = lightStem;
522 m_lightColor.append("_diffuse");
523 m_lightDirection = lightStem;
524 m_lightDirection.append("_direction");
525 m_lightSpecularColor = lightStem;
526 m_lightSpecularColor.append("_specular");
527 if (inLight.m_lightType == QSSGRenderLight::Type::Point) {
528 m_lightPos = lightStem;
529 m_lightPos.append("_position");
530 m_lightAttenuation = lightStem;
531 m_lightAttenuation.append("_attenuation");
532 } else if (inLight.m_lightType == QSSGRenderLight::Type::Area) {
533 m_lightPos = lightStem;
534 m_lightPos.append("_position");
535 m_lightUp = lightStem;
536 m_lightUp.append("_up");
537 m_lightRt = lightStem;
538 m_lightRt.append("_right");
539 } else if (inLight.m_lightType == QSSGRenderLight::Type::Spot) {
540 m_lightPos = lightStem;
541 m_lightPos.append("_position");
542 m_lightAttenuation = lightStem;
543 m_lightAttenuation.append("_attenuation");
544 m_lightConeAngle = lightStem;
545 m_lightConeAngle.append("_coneAngle");
546 m_lightInnerConeAngle = lightStem;
547 m_lightInnerConeAngle.append("_innerConeAngle");
548 }
549 } else {
550 QByteArray lightStem = "lights";
551 char buf[16];
552 qsnprintf(buf, 16, "[%d].", int(lightIdx));
553 lightStem.append(buf);
554
555 m_lightColor = lightStem;
556 m_lightColor.append("diffuse");
557 m_lightDirection = lightStem;
558 m_lightDirection.append("direction");
559 m_lightSpecularColor = lightStem;
560 m_lightSpecularColor.append("specular");
561 if (inLight.m_lightType == QSSGRenderLight::Type::Point) {
562 m_lightPos = lightStem;
563 m_lightPos.append("position");
564 m_lightConstantAttenuation = lightStem;
565 m_lightConstantAttenuation.append("constantAttenuation");
566 m_lightLinearAttenuation = lightStem;
567 m_lightLinearAttenuation.append("linearAttenuation");
568 m_lightQuadraticAttenuation = lightStem;
569 m_lightQuadraticAttenuation.append("quadraticAttenuation");
570 } else if (inLight.m_lightType == QSSGRenderLight::Type::Area) {
571 m_lightPos = lightStem;
572 m_lightPos.append("position");
573 m_lightUp = lightStem;
574 m_lightUp.append("up");
575 m_lightRt = lightStem;
576 m_lightRt.append("right");
577 } else if (inLight.m_lightType == QSSGRenderLight::Type::Spot) {
578 m_lightPos = lightStem;
579 m_lightPos.append("position");
580 m_lightConstantAttenuation = lightStem;
581 m_lightConstantAttenuation.append("constantAttenuation");
582 m_lightLinearAttenuation = lightStem;
583 m_lightLinearAttenuation.append("linearAttenuation");
584 m_lightQuadraticAttenuation = lightStem;
585 m_lightQuadraticAttenuation.append("quadraticAttenuation");
586 m_lightConeAngle = lightStem;
587 m_lightConeAngle.append("coneAngle");
588 m_lightInnerConeAngle = lightStem;
589 m_lightInnerConeAngle.append("innerConeAngle");
590 }
591 }
592 }
593
addDisplacementMapping__anon06cffe670111::QSSGShaderGenerator594 void addDisplacementMapping(QSSGDefaultMaterialVertexPipelineInterface &inShader)
595 {
596 inShader.addIncoming("attr_uv0", "vec2");
597 inShader.addIncoming("attr_norm", "vec3");
598 inShader.addUniform("displacementSampler", "sampler2D");
599 inShader.addUniform("displaceAmount", "float");
600 inShader.addUniform("displacementMap_rot", "vec4");
601 inShader.addUniform("displacementMap_offset", "vec3");
602 inShader.addInclude("defaultMaterialFileDisplacementTexture.glsllib");
603
604 inShader << " vec3 uTransform = vec3(displacementMap_rot.x, displacementMap_rot.y, displacementMap_offset.x);\n"
605 " vec3 vTransform = vec3(displacementMap_rot.z, displacementMap_rot.w, displacementMap_offset.y);\n";
606 addFunction(inShader, "getTransformedUVCoords");
607 inShader.generateUVCoords(key());
608 inShader << " varTexCoord0 = getTransformedUVCoords(vec3(varTexCoord0, 1.0), uTransform, vTransform);\n"
609 " vec3 displacedPos = defaultMaterialFileDisplacementTexture(displacementSampler , displaceAmount, varTexCoord0 , attr_norm, attr_pos);\n"
610 " gl_Position = modelViewProjection * vec4(displacedPos, 1.0);\n";
611 }
612
generateTextureSwizzle__anon06cffe670111::QSSGShaderGenerator613 void generateTextureSwizzle(QSSGRenderTextureSwizzleMode swizzleMode, QByteArray &texSwizzle, QByteArray &lookupSwizzle)
614 {
615 QSSGRenderContextTypes deprecatedContextFlags(QSSGRenderContextType::GL2 | QSSGRenderContextType::GLES2);
616
617 if (!(deprecatedContextFlags & m_renderContext->renderContext()->renderContextType())) {
618 switch (swizzleMode) {
619 case QSSGRenderTextureSwizzleMode::L8toR8:
620 case QSSGRenderTextureSwizzleMode::L16toR16:
621 texSwizzle.append(".rgb");
622 lookupSwizzle.append(".rrr");
623 break;
624 case QSSGRenderTextureSwizzleMode::L8A8toRG8:
625 texSwizzle.append(".rgba");
626 lookupSwizzle.append(".rrrg");
627 break;
628 case QSSGRenderTextureSwizzleMode::A8toR8:
629 texSwizzle.append(".a");
630 lookupSwizzle.append(".r");
631 break;
632 default:
633 break;
634 }
635 }
636 }
637
638 ///< get the light constant buffer and generate if necessary
getLightConstantBuffer__anon06cffe670111::QSSGShaderGenerator639 QSSGRef<QSSGRenderConstantBuffer> getLightConstantBuffer(qint32 inLightCount)
640 {
641 Q_ASSERT(inLightCount >= 0);
642 const QSSGRef<QSSGRenderContext> &theContext = m_renderContext->renderContext();
643
644 // we assume constant buffer support
645 Q_ASSERT(theContext->supportsConstantBuffer());
646
647 // we only create if if we have lights
648 if (!inLightCount || !theContext->supportsConstantBuffer())
649 return nullptr;
650
651 static const QByteArray theName = QByteArrayLiteral("lightsBuffer");
652 QSSGRef<QSSGRenderConstantBuffer> pCB = theContext->getConstantBuffer(theName);
653 if (pCB)
654 return pCB;
655
656 // create
657 const size_t size = sizeof(QSSGLightSourceShader) * QSSG_MAX_NUM_LIGHTS + (4 * sizeof(qint32));
658 quint8 stackData[size];
659 memset(stackData, 0, 4 * sizeof(qint32));
660 // QSSGLightSourceShader *s = new (stackData + 4*sizeof(qint32)) QSSGLightSourceShader[QSSG_MAX_NUM_LIGHTS];
661 QSSGByteView cBuffer(stackData, size);
662 pCB = *m_constantBuffers.insert(theName, new QSSGRenderConstantBuffer(theContext, theName, QSSGRenderBufferUsageType::Static, cBuffer));
663 if (Q_UNLIKELY(!pCB)) {
664 Q_ASSERT(false);
665 return nullptr;
666 }
667
668 return pCB;
669
670 }
671
setImageShaderVariables__anon06cffe670111::QSSGShaderGenerator672 void setImageShaderVariables(const QSSGRef<QSSGShaderGeneratorGeneratedShader> &inShader, QSSGRenderableImage &inImage, quint32 idx)
673 {
674 size_t numImageVariables = inShader->m_images.size();
675 for (size_t namesIdx = numImageVariables; namesIdx <= idx; ++namesIdx) {
676 setupImageVariableNames(idx);
677 inShader->m_images.push_back(
678 QSSGShaderTextureProperties(inShader->m_shader, m_imageSampler, m_imageOffsets, m_imageRotations, m_imageSamplerSize));
679 }
680 QSSGShaderTextureProperties &theShaderProps = inShader->m_images[idx];
681 const QMatrix4x4 &textureTransform = inImage.m_image.m_textureTransform;
682 // We separate rotational information from offset information so that just maybe the shader
683 // will attempt to push less information to the card.
684 const float *dataPtr(textureTransform.constData());
685 // The third member of the offsets contains a flag indicating if the texture was
686 // premultiplied or not.
687 // We use this to mix the texture alpha.
688 QVector3D offsets(dataPtr[12], dataPtr[13], inImage.m_image.m_textureData.m_textureFlags.isPreMultiplied() ? 1.0f : 0.0f);
689 // Grab just the upper 2x2 rotation matrix from the larger matrix.
690 QVector4D rotations(dataPtr[0], dataPtr[4], dataPtr[1], dataPtr[5]);
691
692 // The image horizontal and vertical tiling modes need to be set here, before we set texture
693 // on the shader.
694 // because setting the image on the texture forces the textue to bind and immediately apply
695 // any tex params.
696 const QSSGRef<QSSGRenderTexture2D> &imageTexture = inImage.m_image.m_textureData.m_texture;
697 imageTexture->setTextureWrapS(inImage.m_image.m_horizontalTilingMode);
698 imageTexture->setTextureWrapT(inImage.m_image.m_verticalTilingMode);
699 theShaderProps.sampler.set(imageTexture.data());
700
701 // If item size has changed, force sampler parameters update.
702 bool forceParamsUpdate = inImage.m_image.m_flags.testFlag(QSSGRenderImage::Flag::ItemSizeDirty);
703 if (forceParamsUpdate) {
704 imageTexture->setsamplerParamsDirty();
705 inImage.m_image.m_flags.setFlag(QSSGRenderImage::Flag::ItemSizeDirty, false);
706 }
707
708 theShaderProps.offsets.set(offsets);
709 theShaderProps.rotations.set(rotations);
710 theShaderProps.size.set(QVector2D(imageTexture->textureDetails().width, imageTexture->textureDetails().height));
711 }
712
generateShadowMapOcclusion__anon06cffe670111::QSSGShaderGenerator713 void generateShadowMapOcclusion(quint32 lightIdx, bool inShadowEnabled, QSSGRenderLight::Type inType)
714 {
715 if (inShadowEnabled) {
716 vertexGenerator().generateWorldPosition();
717 addShadowMapContribution(fragmentGenerator(), lightIdx, inType);
718 /*
719 VertexGenerator().AddUniform( m_ShadowMatrixStem, "mat4" );
720 VertexGenerator().AddOutgoing( m_ShadowCoordStem, "vec4" );
721 VertexGenerator() << " vec4 local_" << m_ShadowCoordStem << " = " << m_ShadowMatrixStem
722 << " * vec4(local_model_world_position, 1.0);" << "\n";
723 m_TempStr.assign( "local_" );
724 m_TempStr.append( m_ShadowCoordStem );
725 VertexGenerator().AssignOutput( m_ShadowCoordStem, m_TempStr );
726 */
727 } else {
728 fragmentGenerator() << " shadow_map_occl = 1.0;\n";
729 }
730 }
731
generateVertexShader__anon06cffe670111::QSSGShaderGenerator732 void generateVertexShader(const QSSGShaderDefaultMaterialKey &inKey)
733 {
734 // vertex displacement
735 quint32 imageIdx = 0;
736 QSSGRenderableImage *displacementImage = nullptr;
737 quint32 displacementImageIdx = 0;
738
739 for (QSSGRenderableImage *img = m_firstImage; img != nullptr; img = img->m_nextImage, ++imageIdx) {
740 if (img->m_mapType == QSSGImageMapTypes::Displacement) {
741 displacementImage = img;
742 displacementImageIdx = imageIdx;
743 break;
744 }
745 }
746
747 // the pipeline opens/closes up the shaders stages
748 vertexGenerator().beginVertexGeneration(inKey, displacementImageIdx, displacementImage);
749 }
750
addSpecularAmount__anon06cffe670111::QSSGShaderGenerator751 void addSpecularAmount(QSSGShaderStageGeneratorInterface &fragmentShader, bool &fragmentHasSpecularAmount, bool reapply = false)
752 {
753 if (!fragmentHasSpecularAmount)
754 fragmentShader << " vec3 specularAmount = specularBase * vec3(material_properties.z + material_properties.x * (1.0 - material_properties.z));\n";
755 else if (reapply)
756 fragmentShader << " specularAmount = specularBase * vec3(material_properties.z + material_properties.x * (1.0 - material_properties.z));\n";
757 fragmentHasSpecularAmount = true;
758 }
759
generateFragmentShader__anon06cffe670111::QSSGShaderGenerator760 void generateFragmentShader(QSSGShaderDefaultMaterialKey &inKey)
761 {
762 const bool metalnessEnabled = material()->isMetalnessEnabled();
763 const bool specularEnabled = material()->isSpecularEnabled();
764 bool vertexColorsEnabled = material()->isVertexColorsEnabled();
765 bool specularLightingEnabled = metalnessEnabled || specularEnabled;
766
767 const auto &keyProps = m_defaultMaterialShaderKeyProperties;
768
769 bool hasLighting = material()->hasLighting();
770 bool isDoubleSided = keyProps.m_isDoubleSided.getValue(inKey);
771 bool hasImage = m_firstImage != nullptr;
772
773 bool hasIblProbe = keyProps.m_hasIbl.getValue(inKey);
774 bool hasEmissiveMap = false;
775 bool hasLightmaps = false;
776 bool hasBaseColorMap = false;
777 // Pull the bump out as
778 QSSGRenderableImage *bumpImage = nullptr;
779 quint32 imageIdx = 0;
780 quint32 bumpImageIdx = 0;
781 QSSGRenderableImage *specularAmountImage = nullptr;
782 quint32 specularAmountImageIdx = 0;
783 QSSGRenderableImage *roughnessImage = nullptr;
784 quint32 roughnessImageIdx = 0;
785 QSSGRenderableImage *metalnessImage = nullptr;
786 quint32 metalnessImageIdx = 0;
787 QSSGRenderableImage *occlusionImage = nullptr;
788 quint32 occlusionImageIdx = 0;
789 // normal mapping
790 QSSGRenderableImage *normalImage = nullptr;
791 quint32 normalImageIdx = 0;
792 // translucency map
793 QSSGRenderableImage *translucencyImage = nullptr;
794 quint32 translucencyImageIdx = 0;
795 // lightmaps
796 QSSGRenderableImage *lightmapIndirectImage = nullptr;
797 quint32 lightmapIndirectImageIdx = 0;
798 QSSGRenderableImage *lightmapRadiosityImage = nullptr;
799 quint32 lightmapRadiosityImageIdx = 0;
800 QSSGRenderableImage *lightmapShadowImage = nullptr;
801 quint32 lightmapShadowImageIdx = 0;
802 const bool supportStandardDerivatives = m_renderContext->renderContext()->supportsStandardDerivatives();
803
804 QSSGRenderableImage *baseImage = nullptr;
805 quint32 baseImageIdx = 0;
806
807 // Use shared texcoord when transforms are identity
808 QVector<QSSGRenderableImage *> identityImages;
809
810 Q_UNUSED(lightmapShadowImage)
811 Q_UNUSED(lightmapShadowImageIdx)
812 Q_UNUSED(supportStandardDerivatives)
813
814 auto channelStr = [](const QSSGShaderKeyTextureChannel &chProp, const QSSGShaderDefaultMaterialKey &inKey) -> QByteArray {
815 QByteArray ret;
816 switch (chProp.getTextureChannel(inKey)) {
817 case QSSGShaderKeyTextureChannel::R:
818 ret.append(".r");
819 break;
820 case QSSGShaderKeyTextureChannel::G:
821 ret.append(".g");
822 break;
823 case QSSGShaderKeyTextureChannel::B:
824 ret.append(".b");
825 break;
826 case QSSGShaderKeyTextureChannel::A:
827 ret.append(".a");
828 break;
829 }
830 return ret;
831 };
832
833 // Reset uv cooordinate generation
834 clearUVCoordsGen();
835
836 for (QSSGRenderableImage *img = m_firstImage; img != nullptr; img = img->m_nextImage, ++imageIdx) {
837 if (img->m_image.isImageTransformIdentity())
838 identityImages.push_back(img);
839 if (img->m_mapType == QSSGImageMapTypes::BaseColor || img->m_mapType == QSSGImageMapTypes::Diffuse) {
840 hasBaseColorMap = img->m_mapType == QSSGImageMapTypes::BaseColor;
841 baseImage = img;
842 baseImageIdx = imageIdx;
843 } else if (img->m_mapType == QSSGImageMapTypes::Bump) {
844 bumpImage = img;
845 bumpImageIdx = imageIdx;
846 } else if (img->m_mapType == QSSGImageMapTypes::SpecularAmountMap) {
847 specularAmountImage = img;
848 specularAmountImageIdx = imageIdx;
849 } else if (img->m_mapType == QSSGImageMapTypes::Roughness) {
850 roughnessImage = img;
851 roughnessImageIdx = imageIdx;
852 } else if (img->m_mapType == QSSGImageMapTypes::Metalness) {
853 metalnessImage = img;
854 metalnessImageIdx = imageIdx;
855 } else if (img->m_mapType == QSSGImageMapTypes::Occlusion) {
856 occlusionImage = img;
857 occlusionImageIdx = imageIdx;
858 } else if (img->m_mapType == QSSGImageMapTypes::Normal) {
859 normalImage = img;
860 normalImageIdx = imageIdx;
861 } else if (img->m_mapType == QSSGImageMapTypes::Translucency) {
862 translucencyImage = img;
863 translucencyImageIdx = imageIdx;
864 } else if (img->m_mapType == QSSGImageMapTypes::Emissive) {
865 hasEmissiveMap = true;
866 } else if (img->m_mapType == QSSGImageMapTypes::LightmapIndirect) {
867 lightmapIndirectImage = img;
868 lightmapIndirectImageIdx = imageIdx;
869 hasLightmaps = true;
870 } else if (img->m_mapType == QSSGImageMapTypes::LightmapRadiosity) {
871 lightmapRadiosityImage = img;
872 lightmapRadiosityImageIdx = imageIdx;
873 hasLightmaps = true;
874 } else if (img->m_mapType == QSSGImageMapTypes::LightmapShadow) {
875 lightmapShadowImage = img;
876 lightmapShadowImageIdx = imageIdx;
877 hasLightmaps = true;
878 }
879 }
880
881 bool enableSSAO = false;
882 bool enableSSDO = false;
883 bool enableShadowMaps = false;
884 bool enableBumpNormal = normalImage || bumpImage;
885 specularLightingEnabled |= specularAmountImage != nullptr;
886
887 for (qint32 idx = 0; idx < m_currentFeatureSet.size(); ++idx) {
888 const auto &name = m_currentFeatureSet.at(idx).name;
889 if (name == QSSGShaderDefines::asString(QSSGShaderDefines::Ssao))
890 enableSSAO = m_currentFeatureSet.at(idx).enabled;
891 else if (name == QSSGShaderDefines::asString(QSSGShaderDefines::Ssdo))
892 enableSSDO = m_currentFeatureSet.at(idx).enabled;
893 else if (name == QSSGShaderDefines::asString(QSSGShaderDefines::Ssm))
894 enableShadowMaps = m_currentFeatureSet.at(idx).enabled;
895 }
896
897 bool includeSSAOSSDOVars = enableSSAO || enableSSDO || enableShadowMaps;
898
899 vertexGenerator().beginFragmentGeneration();
900 QSSGShaderStageGeneratorInterface &fragmentShader(fragmentGenerator());
901 QSSGDefaultMaterialVertexPipelineInterface &vertexShader(vertexGenerator());
902
903 // The fragment or vertex shaders may not use the material_properties or diffuse
904 // uniforms in all cases but it is simpler to just add them and let the linker strip them.
905 fragmentShader.addUniform("material_diffuse", "vec3");
906 fragmentShader.addUniform("base_color", "vec4");
907 fragmentShader.addUniform("material_properties", "vec4");
908
909 // !hasLighting does not mean 'no light source'
910 // it should be KHR_materials_unlit
911 // https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_materials_unlit
912 if (hasLighting) {
913 // All these are needed for SSAO
914 if (includeSSAOSSDOVars)
915 fragmentShader.addInclude("SSAOCustomMaterial.glsllib");
916
917 if (hasIblProbe)
918 fragmentShader.addInclude("sampleProbe.glsllib");
919
920 if (!m_lightsAsSeparateUniforms)
921 addFunction(fragmentShader, "sampleLightVars");
922 addFunction(fragmentShader, "diffuseReflectionBSDF");
923
924 if (hasLightmaps)
925 fragmentShader.addInclude("evalLightmaps.glsllib");
926
927 // view_vector, varWorldPos, world_normal are all used if there is a specular map
928 // in addition to if there is specular lighting. So they are lifted up here, always
929 // generated.
930 // we rely on the linker to strip out what isn't necessary instead of explicitly stripping
931 // it for code simplicity.
932 if (hasImage) {
933 fragmentShader.append(" vec3 uTransform;");
934 fragmentShader.append(" vec3 vTransform;");
935 }
936
937 vertexShader.generateViewVector();
938 vertexShader.generateWorldNormal(inKey);
939 vertexShader.generateWorldPosition();
940
941 if (includeSSAOSSDOVars || specularEnabled || metalnessEnabled || hasIblProbe || enableBumpNormal)
942 vertexShader.generateVarTangentAndBinormal(inKey);
943
944 // You do bump or normal mapping but not both
945 if (bumpImage != nullptr) {
946 generateImageUVCoordinates(bumpImageIdx, *bumpImage);
947 fragmentShader.addUniform("bumpAmount", "float");
948
949 fragmentShader.addUniform(m_imageSamplerSize, "vec2");
950 fragmentShader.addInclude("defaultMaterialBumpNoLod.glsllib");
951 fragmentShader << " world_normal = defaultMaterialBumpNoLod(" << m_imageSampler << ", bumpAmount, " << m_imageFragCoords << ", tangent, binormal, world_normal, " << m_imageSamplerSize << ");\n";
952 // Do gram schmidt
953 fragmentShader << " binormal = normalize(cross(world_normal, tangent));\n";
954 fragmentShader << " tangent = normalize(cross(binormal, world_normal));\n";
955
956 } else if (normalImage != nullptr) {
957 generateImageUVCoordinates(normalImageIdx, *normalImage);
958
959 fragmentShader.addFunction("sampleNormalTexture");
960 fragmentShader.addUniform("bumpAmount", "float");
961
962 fragmentShader << " world_normal = sampleNormalTexture(" << m_imageSampler << ", bumpAmount, " << m_imageFragCoords << ", tangent, binormal, world_normal);\n";
963 // Do gram schmidt
964 fragmentShader << " binormal = normalize(cross(world_normal, tangent));\n";
965 fragmentShader << " tangent = normalize(cross(binormal, world_normal));\n";
966 }
967
968 if (isDoubleSided) {
969 fragmentShader.addInclude("doubleSided.glsllib");
970 fragmentShader.append(" world_normal = adjustNormalForFace(world_normal, varWorldPos);\n");
971 }
972
973 if (includeSSAOSSDOVars || specularEnabled || metalnessEnabled || hasIblProbe || enableBumpNormal)
974 fragmentShader << " mat3 tanFrame = mat3(tangent, binormal, world_normal);\n";
975
976 if (hasEmissiveMap)
977 fragmentShader.append(" vec3 global_emission = material_diffuse.rgb;");
978
979 if (specularLightingEnabled)
980 fragmentShader.append(" vec3 specularBase;");
981 }
982
983 if (vertexColorsEnabled)
984 vertexShader.generateVertexColor(inKey);
985 else
986 fragmentShader.append(" vec4 vertColor = vec4(1.0);");
987
988 bool fragmentHasSpecularAmount = false;
989
990 fragmentShader << " vec4 diffuseColor = base_color * vertColor;\n";
991
992 if (baseImage) {
993 QByteArray texSwizzle;
994 QByteArray lookupSwizzle;
995
996 // NoLighting also needs to fetch baseImage
997 if (!hasLighting) {
998 fragmentShader.append(" vec3 uTransform;");
999 fragmentShader.append(" vec3 vTransform;");
1000 }
1001
1002 if (identityImages.contains(baseImage))
1003 generateImageUVSampler(baseImageIdx);
1004 else
1005 generateImageUVCoordinates(baseImageIdx, *baseImage);
1006 generateTextureSwizzle(baseImage->m_image.m_textureData.m_texture->textureSwizzleMode(), texSwizzle, lookupSwizzle);
1007
1008 fragmentShader << " vec4 base_texture_color" << texSwizzle << " = texture2D(" << m_imageSampler << ", " << m_imageFragCoords << ")" << lookupSwizzle << ";\n";
1009 fragmentShader << " diffuseColor *= base_texture_color;\n";
1010 }
1011
1012 if (hasLighting) {
1013 fragmentShader.addUniform("light_ambient_total", "vec3");
1014
1015 fragmentShader.append(" vec4 global_diffuse_light = vec4(light_ambient_total.rgb * diffuseColor.rgb, diffuseColor.a);");
1016 fragmentShader.append(" vec3 global_specular_light = vec3(0.0, 0.0, 0.0);");
1017 fragmentShader.append(" float shadow_map_occl = 1.0;");
1018
1019 if (specularLightingEnabled) {
1020 fragmentShader << " specularBase = diffuseColor.rgb;\n";
1021 vertexShader.generateViewVector();
1022 fragmentShader.addUniform("material_properties", "vec4");
1023 addSpecularAmount(fragmentShader, fragmentHasSpecularAmount);
1024 }
1025
1026 if (lightmapIndirectImage != nullptr) {
1027 if (identityImages.contains(lightmapIndirectImage))
1028 generateImageUVSampler(lightmapIndirectImageIdx, 1);
1029 else
1030 generateImageUVCoordinates(lightmapIndirectImageIdx, *lightmapIndirectImage, 1);
1031
1032
1033 fragmentShader << " vec4 indirect_light = texture2D(" << m_imageSampler << ", " << m_imageFragCoords << ");\n";
1034 fragmentShader << " global_diffuse_light += indirect_light;\n";
1035 if (specularLightingEnabled)
1036 fragmentShader << " global_specular_light += indirect_light.rgb * specularAmount;\n";
1037 }
1038
1039 if (lightmapRadiosityImage != nullptr) {
1040 if (identityImages.contains(lightmapRadiosityImage))
1041 generateImageUVSampler(lightmapRadiosityImageIdx, 1);
1042 else
1043 generateImageUVCoordinates(lightmapRadiosityImageIdx, *lightmapRadiosityImage, 1);
1044
1045 fragmentShader << " vec4 direct_light = texture2D(" << m_imageSampler << ", " << m_imageFragCoords << ");\n";
1046 fragmentShader << " global_diffuse_light += direct_light;\n";
1047 if (specularLightingEnabled)
1048 fragmentShader << " global_specular_light += direct_light.rgb * specularAmount;\n";
1049 }
1050
1051 if (translucencyImage != nullptr) {
1052 fragmentShader.addUniform("translucentFalloff", "float");
1053 fragmentShader.addUniform("diffuseLightWrap", "float");
1054
1055 if (identityImages.contains(translucencyImage))
1056 generateImageUVSampler(translucencyImageIdx);
1057 else
1058 generateImageUVCoordinates(translucencyImageIdx, *translucencyImage);
1059
1060 const auto &channelProps = keyProps.m_textureChannels[QSSGShaderDefaultMaterialKeyProperties::TranslucencyChannel];
1061 fragmentShader << " float translucent_depth_range = texture2D(" << m_imageSampler
1062 << ", " << m_imageFragCoords << ")" << channelStr(channelProps, inKey) << ";\n";
1063 fragmentShader << " float translucent_thickness = translucent_depth_range * translucent_depth_range;\n";
1064 fragmentShader << " float translucent_thickness_exp = exp(translucent_thickness * translucentFalloff);\n";
1065 }
1066
1067 fragmentShader.append(" float lightAttenuation = 1.0;");
1068
1069 addLocalVariable(fragmentShader, "aoFactor", "float");
1070
1071 if (enableSSAO)
1072 fragmentShader.append(" aoFactor = customMaterialAO();");
1073 else
1074 fragmentShader.append(" aoFactor = 1.0;");
1075
1076 addLocalVariable(fragmentShader, "shadowFac", "float");
1077
1078 // Fragment lighting means we can perhaps attenuate the specular amount by a texture
1079 // lookup.
1080 if (specularAmountImage) {
1081 addSpecularAmount(fragmentShader, fragmentHasSpecularAmount);
1082
1083 if (identityImages.contains(specularAmountImage))
1084 generateImageUVSampler(specularAmountImageIdx);
1085 else
1086 generateImageUVCoordinates(specularAmountImageIdx, *specularAmountImage);
1087 fragmentShader << " specularBase *= texture2D(" << m_imageSampler << ", " << m_imageFragCoords << ").rgb;\n";
1088 }
1089
1090 fragmentShader << " float roughnessAmount = material_properties.y;\n";
1091 if (specularLightingEnabled && roughnessImage) {
1092 const auto &channelProps = keyProps.m_textureChannels[QSSGShaderDefaultMaterialKeyProperties::RoughnessChannel];
1093 if (identityImages.contains(roughnessImage))
1094 generateImageUVSampler(roughnessImageIdx);
1095 else
1096 generateImageUVCoordinates(roughnessImageIdx, *roughnessImage);
1097 fragmentShader << " roughnessAmount *= texture2D(" << m_imageSampler << ", "
1098 << m_imageFragCoords << ")" << channelStr(channelProps, inKey) << ";\n";
1099 }
1100
1101 fragmentShader << " float metalnessAmount = material_properties.z;\n";
1102 if (specularLightingEnabled && metalnessImage) {
1103 const auto &channelProps = keyProps.m_textureChannels[QSSGShaderDefaultMaterialKeyProperties::MetalnessChannel];
1104 if (identityImages.contains(metalnessImage))
1105 generateImageUVSampler(metalnessImageIdx);
1106 else
1107 generateImageUVCoordinates(metalnessImageIdx, *metalnessImage);
1108 fragmentShader << " float sampledMetalness = texture2D(" << m_imageSampler << ", "
1109 << m_imageFragCoords << ")" << channelStr(channelProps, inKey) << ";\n";
1110 fragmentShader << " metalnessAmount = clamp(metalnessAmount * sampledMetalness, 0.0, 1.0);\n";
1111 addSpecularAmount(fragmentShader, fragmentHasSpecularAmount, true);
1112 }
1113 fragmentShader.addInclude("defaultMaterialFresnel.glsllib");
1114 fragmentShader << " float ds = dielectricSpecular(material_properties.w);\n";
1115 fragmentShader << " diffuseColor.rgb *= (1.0 - ds) * (1.0 - metalnessAmount);\n";
1116 if (specularLightingEnabled) {
1117 if (!hasBaseColorMap && material()->type == QSSGRenderGraphObject::Type::PrincipledMaterial) {
1118 fragmentShader << " float lum = dot(base_color.rgb, vec3(0.21, 0.72, 0.07));\n"
1119 " specularBase += (lum > 0.0) ? (base_color.rgb) / lum : vec3(1.0);\n";
1120 }
1121
1122 maybeAddMaterialFresnel(fragmentShader, inKey, fragmentHasSpecularAmount, metalnessEnabled);
1123 }
1124
1125
1126 // Iterate through all lights
1127 Q_ASSERT(m_lights.size() < INT32_MAX);
1128 for (qint32 lightIdx = 0; lightIdx < m_lights.size(); ++lightIdx) {
1129 QSSGRenderLight *lightNode = m_lights[lightIdx];
1130 setupLightVariableNames(lightIdx, *lightNode);
1131 bool isDirectional = lightNode->m_lightType == QSSGRenderLight::Type::Directional;
1132 bool isArea = lightNode->m_lightType == QSSGRenderLight::Type::Area;
1133 bool isSpot = lightNode->m_lightType == QSSGRenderLight::Type::Spot;
1134 bool isShadow = enableShadowMaps && lightNode->m_castShadow;
1135
1136 fragmentShader.append("");
1137 char buf[11];
1138 snprintf(buf, 11, "%d", lightIdx);
1139
1140 QByteArray tempStr = "light";
1141 tempStr.append(buf);
1142
1143 fragmentShader << " //Light " << buf << "\n"
1144 " lightAttenuation = 1.0;\n";
1145 if (isDirectional) {
1146 if (m_lightsAsSeparateUniforms) {
1147 fragmentShader.addUniform(m_lightDirection, "vec4");
1148 fragmentShader.addUniform(m_lightColor, "vec4");
1149 }
1150
1151 if (enableSSDO)
1152 fragmentShader << " shadowFac = customMaterialShadow(" << m_lightDirection << ".xyz, varWorldPos);\n";
1153 else
1154 fragmentShader << " shadowFac = 1.0;\n";
1155
1156 generateShadowMapOcclusion(lightIdx, enableShadowMaps && isShadow, lightNode->m_lightType);
1157
1158 if (specularLightingEnabled && enableShadowMaps && isShadow)
1159 fragmentShader << " lightAttenuation *= shadow_map_occl;\n";
1160
1161 fragmentShader << " global_diffuse_light.rgb += diffuseColor.rgb * shadowFac * shadow_map_occl * diffuseReflectionBSDF(world_normal, -" << m_lightDirection << ".xyz, " << m_lightColor << ".rgb).rgb;\n";
1162
1163 if (specularLightingEnabled) {
1164 if (m_lightsAsSeparateUniforms)
1165 fragmentShader.addUniform(m_lightSpecularColor, "vec4");
1166 outputSpecularEquation(material()->specularModel, fragmentShader, m_lightDirection, m_lightSpecularColor);
1167 }
1168 } else if (isArea) {
1169 if (m_lightsAsSeparateUniforms) {
1170 fragmentShader.addUniform(m_lightColor, "vec4");
1171 fragmentShader.addUniform(m_lightPos, "vec4");
1172 fragmentShader.addUniform(m_lightDirection, "vec4");
1173 fragmentShader.addUniform(m_lightUp, "vec4");
1174 fragmentShader.addUniform(m_lightRt, "vec4");
1175 } else {
1176 addFunction(fragmentShader, "areaLightVars");
1177 }
1178 addFunction(fragmentShader, "calculateDiffuseAreaOld");
1179 vertexShader.generateWorldPosition();
1180 generateShadowMapOcclusion(lightIdx, enableShadowMaps && isShadow, lightNode->m_lightType);
1181
1182 // Debug measure to make sure paraboloid sampling was projecting to the right
1183 // location
1184 // fragmentShader << " global_diffuse_light.rg += " << m_ShadowCoordStem << ";"
1185 // << "\n";
1186 m_normalizedDirection = tempStr;
1187 m_normalizedDirection.append("_Frame");
1188
1189 addLocalVariable(fragmentShader, m_normalizedDirection, "mat3");
1190 fragmentShader << " " << m_normalizedDirection << " = mat3(" << m_lightRt << ".xyz, " << m_lightUp << ".xyz, -" << m_lightDirection << ".xyz);\n";
1191
1192 if (enableSSDO)
1193 fragmentShader << " shadowFac = shadow_map_occl * customMaterialShadow(" << m_lightDirection << ".xyz, varWorldPos);\n";
1194 else
1195 fragmentShader << " shadowFac = shadow_map_occl;\n";
1196
1197 if (specularLightingEnabled) {
1198 vertexShader.generateViewVector();
1199 if (m_lightsAsSeparateUniforms)
1200 fragmentShader.addUniform(m_lightSpecularColor, "vec4");
1201 outputSpecularAreaLighting(fragmentShader, "varWorldPos", "view_vector", m_lightSpecularColor);
1202 }
1203
1204 outputDiffuseAreaLighting(fragmentShader, "varWorldPos", tempStr);
1205 fragmentShader << " lightAttenuation *= shadowFac;\n";
1206
1207 addTranslucencyIrradiance(fragmentShader, translucencyImage, true);
1208
1209 fragmentShader << " global_diffuse_light.rgb += diffuseColor.rgb * lightAttenuation * diffuseReflectionBSDF(world_normal, " << m_normalizedDirection << ", " << m_lightColor << ".rgb).rgb;\n";
1210 } else {
1211 vertexShader.generateWorldPosition();
1212
1213 if (m_lightsAsSeparateUniforms) {
1214 fragmentShader.addUniform(m_lightColor, "vec4");
1215 fragmentShader.addUniform(m_lightPos, "vec4");
1216 if (isSpot)
1217 fragmentShader.addUniform(m_lightDirection, "vec4");
1218 }
1219
1220 m_relativeDirection = tempStr;
1221 m_relativeDirection.append("_relativeDirection");
1222
1223 m_normalizedDirection = m_relativeDirection;
1224 m_normalizedDirection.append("_normalized");
1225
1226 m_relativeDistance = tempStr;
1227 m_relativeDistance.append("_distance");
1228
1229 fragmentShader << " vec3 " << m_relativeDirection << " = varWorldPos - " << m_lightPos << ".xyz;\n"
1230 " float " << m_relativeDistance << " = length(" << m_relativeDirection << ");\n"
1231 " vec3 " << m_normalizedDirection << " = " << m_relativeDirection << " / " << m_relativeDistance << ";\n";
1232
1233 if (isSpot) {
1234 m_spotAngle = tempStr;
1235 m_spotAngle.append("_spotAngle");
1236
1237 if (m_lightsAsSeparateUniforms) {
1238 fragmentShader.addUniform(m_lightConeAngle, "float");
1239 fragmentShader.addUniform(m_lightInnerConeAngle, "float");
1240 }
1241 fragmentShader << " float " << m_spotAngle << " = dot(" << m_normalizedDirection
1242 << ", normalize(vec3(" << m_lightDirection << ")));\n";
1243 fragmentShader << " if (" << m_spotAngle << " > " << m_lightConeAngle << ") {\n";
1244 }
1245
1246 generateShadowMapOcclusion(lightIdx, enableShadowMaps && isShadow, lightNode->m_lightType);
1247
1248 if (enableSSDO) {
1249 fragmentShader << " shadowFac = shadow_map_occl * customMaterialShadow(" << m_normalizedDirection << ", varWorldPos);\n";
1250 } else {
1251 fragmentShader << " shadowFac = shadow_map_occl;\n";
1252 }
1253
1254 addFunction(fragmentShader, "calculatePointLightAttenuation");
1255
1256 if (m_lightsAsSeparateUniforms) {
1257 fragmentShader.addUniform(m_lightAttenuation, "vec3");
1258 fragmentShader << " lightAttenuation = shadowFac * calculatePointLightAttenuation(vec3(" << m_lightAttenuation << ".x, " << m_lightAttenuation << ".y, " << m_lightAttenuation << ".z), " << m_relativeDistance << ");\n";
1259 } else {
1260 fragmentShader << " lightAttenuation = shadowFac * calculatePointLightAttenuation(vec3(" << m_lightConstantAttenuation << ", " << m_lightLinearAttenuation << ", " << m_lightQuadraticAttenuation << "), " << m_relativeDistance << ");\n";
1261 }
1262
1263 addTranslucencyIrradiance(fragmentShader, translucencyImage, false);
1264
1265 if (isSpot) {
1266 fragmentShader << " float spotFactor = smoothstep(" << m_lightConeAngle
1267 << ", " << m_lightInnerConeAngle << ", " << m_spotAngle
1268 << ");\n";
1269 fragmentShader << " global_diffuse_light.rgb += diffuseColor.rgb * spotFactor * ";
1270 } else {
1271 fragmentShader << " global_diffuse_light.rgb += diffuseColor.rgb * ";
1272 }
1273 fragmentShader << "lightAttenuation * diffuseReflectionBSDF(world_normal, -"
1274 << m_normalizedDirection << ", "
1275 << m_lightColor << ".rgb).rgb;\n";
1276
1277 if (specularLightingEnabled) {
1278 if (m_lightsAsSeparateUniforms)
1279 fragmentShader.addUniform(m_lightSpecularColor, "vec4");
1280 outputSpecularEquation(material()->specularModel, fragmentShader, m_normalizedDirection, m_lightSpecularColor);
1281 }
1282
1283 if (isSpot)
1284 fragmentShader << " }\n";
1285 }
1286 }
1287
1288 // This may be confusing but the light colors are already modulated by the base
1289 // material color.
1290 // Thus material color is the base material color * material emissive.
1291 // Except material_color.a *is* the actual opacity factor.
1292 // Furthermore objectOpacity is something that may come from the vertex pipeline or
1293 // somewhere else.
1294 // We leave it up to the vertex pipeline to figure it out.
1295 fragmentShader << " global_diffuse_light = vec4(global_diffuse_light.rgb * aoFactor, objectOpacity * diffuseColor.a);\n"
1296 " global_specular_light = vec3(global_specular_light.rgb);\n";
1297 if (!hasEmissiveMap)
1298 fragmentShader << " global_diffuse_light.rgb += diffuseColor.rgb * material_diffuse.rgb;\n";
1299
1300 // since we already modulate our material diffuse color
1301 // into the light color we will miss it entirely if no IBL
1302 // or light is used
1303 if (hasLightmaps && !(m_lights.size() || hasIblProbe))
1304 fragmentShader << " global_diffuse_light.rgb *= diffuseColor.rgb;\n";
1305
1306 if (hasIblProbe) {
1307 vertexShader.generateWorldNormal(inKey);
1308
1309 fragmentShader << " global_diffuse_light.rgb += diffuseColor.rgb * aoFactor * sampleDiffuse(tanFrame).rgb;\n";
1310
1311 if (specularLightingEnabled) {
1312 fragmentShader.addUniform("material_specular", "vec4");
1313 fragmentShader << " global_specular_light.rgb += specularAmount * vec3(material_specular.rgb) * sampleGlossy(tanFrame, view_vector, roughnessAmount).rgb;\n";
1314 }
1315 }
1316
1317 if (hasImage) {
1318 fragmentShader.append(" vec4 texture_color;");
1319 quint32 idx = 0;
1320 for (QSSGRenderableImage *image = m_firstImage; image; image = image->m_nextImage, ++idx) {
1321 // Various maps are handled on a different locations
1322 if (image->m_mapType == QSSGImageMapTypes::Bump || image->m_mapType == QSSGImageMapTypes::Normal
1323 || image->m_mapType == QSSGImageMapTypes::Displacement || image->m_mapType == QSSGImageMapTypes::SpecularAmountMap
1324 || image->m_mapType == QSSGImageMapTypes::Roughness || image->m_mapType == QSSGImageMapTypes::Translucency
1325 || image->m_mapType == QSSGImageMapTypes::Metalness || image->m_mapType == QSSGImageMapTypes::Occlusion
1326 || image->m_mapType == QSSGImageMapTypes::LightmapIndirect
1327 || image->m_mapType == QSSGImageMapTypes::LightmapRadiosity) {
1328 continue;
1329 }
1330
1331 QByteArray texSwizzle;
1332 QByteArray lookupSwizzle;
1333
1334 if (identityImages.contains(image))
1335 generateImageUVSampler(idx);
1336 else
1337 generateImageUVCoordinates(idx, *image);
1338 generateTextureSwizzle(image->m_image.m_textureData.m_texture->textureSwizzleMode(), texSwizzle, lookupSwizzle);
1339
1340 fragmentShader << " texture_color" << texSwizzle << " = texture2D(" << m_imageSampler << ", " << m_imageFragCoords << ")" << lookupSwizzle << ";\n";
1341
1342 if (image->m_image.m_textureData.m_textureFlags.isPreMultiplied())
1343 fragmentShader << " texture_color.rgb = texture_color.a > 0.0 ? texture_color.rgb / texture_color.a : vec3(0.0);\n";
1344
1345 // These mapping types honestly don't make a whole ton of sense to me.
1346 switch (image->m_mapType) {
1347 case QSSGImageMapTypes::BaseColor:
1348 // color already taken care of
1349 if (material()->alphaMode == QSSGRenderDefaultMaterial::MaterialAlphaMode::Mask) {
1350 // The rendered output is either fully opaque or fully transparent depending on the alpha
1351 // value and the specified alpha cutoff value.
1352 fragmentShader.addUniform("alphaCutoff", "float");
1353 fragmentShader << " if ((texture_color.a * base_color.a) < alphaCutoff) {\n"
1354 " fragOutput = vec4(0);\n"
1355 " return;\n"
1356 " }\n";
1357 }
1358 break;
1359 case QSSGImageMapTypes::Diffuse: // assume images are premultiplied.
1360 // color already taken care of
1361 fragmentShader.append(" global_diffuse_light.a *= base_color.a * texture_color.a;");
1362 break;
1363 case QSSGImageMapTypes::LightmapShadow:
1364 // We use image offsets.z to switch between incoming premultiplied textures or
1365 // not premultiplied textures.
1366 // If Z is 1, then we assume the incoming texture is already premultiplied, else
1367 // we just read the rgb value.
1368 fragmentShader.append(" global_diffuse_light *= texture_color;");
1369 break;
1370 case QSSGImageMapTypes::Specular:
1371 fragmentShader.addUniform("material_specular", "vec4");
1372 if (fragmentHasSpecularAmount) {
1373 fragmentShader.append(" global_specular_light.rgb += specularAmount * texture_color.rgb * material_specular.rgb;");
1374 } else {
1375 fragmentShader.append(" global_specular_light.rgb += texture_color.rgb * material_specular.rgb;");
1376 }
1377 fragmentShader.append(" global_diffuse_light.a *= texture_color.a;");
1378 break;
1379 case QSSGImageMapTypes::Opacity:
1380 {
1381 const auto &channelProps = keyProps.m_textureChannels[QSSGShaderDefaultMaterialKeyProperties::OpacityChannel];
1382 fragmentShader << " global_diffuse_light.a *= texture_color" << channelStr(channelProps, inKey) << ";\n";
1383 break;
1384 }
1385 case QSSGImageMapTypes::Emissive:
1386 fragmentShader.append(" global_emission *= texture_color.rgb * texture_color.a;");
1387 break;
1388 default:
1389 Q_ASSERT(false); // fallthrough intentional
1390 }
1391 }
1392 }
1393
1394 // Occlusion Map
1395 if (occlusionImage) {
1396 fragmentShader.addUniform("occlusionAmount", "float");
1397 const auto &channelProps = keyProps.m_textureChannels[QSSGShaderDefaultMaterialKeyProperties::OcclusionChannel];
1398 if (identityImages.contains(occlusionImage))
1399 generateImageUVSampler(occlusionImageIdx);
1400 else
1401 generateImageUVCoordinates(occlusionImageIdx, *occlusionImage);
1402 fragmentShader << " float ao = texture2D(" << m_imageSampler << ", "
1403 << m_imageFragCoords << ")" << channelStr(channelProps, inKey) << ";\n";
1404 fragmentShader << " global_diffuse_light.rgb = mix(global_diffuse_light.rgb, global_diffuse_light.rgb * ao, occlusionAmount);\n";
1405 }
1406
1407 if (hasEmissiveMap)
1408 fragmentShader.append(" global_diffuse_light.rgb += global_emission.rgb;");
1409
1410 if (hasBaseColorMap && specularLightingEnabled) {
1411 fragmentShader.addInclude("luminance.glsllib");
1412 fragmentShader << " float lum = luminance(specularBase);\n"
1413 " global_specular_light.rgb *= (lum > 0.0) ? specularBase / lum : vec3(1.0);\n";
1414 }
1415
1416 // Ensure the rgb colors are in range.
1417 fragmentShader.append(" fragOutput = vec4(clamp(global_diffuse_light.rgb + global_specular_light.rgb, 0.0, 1.0), global_diffuse_light.a);");
1418 } else {
1419 fragmentShader.append(" fragOutput = vec4(diffuseColor.rgb, diffuseColor.a * objectOpacity);");
1420 }
1421
1422 if (vertexGenerator().hasActiveWireframe()) {
1423 fragmentShader << " vec3 edgeDistance = varEdgeDistance * gl_FragCoord.w;\n"
1424 " float d = min(min(edgeDistance.x, edgeDistance.y), edgeDistance.z);\n"
1425 " float mixVal = smoothstep(0.0, 1.0, d);\n" // line width 1.0
1426 " fragOutput = mix(vec4(0.0, 1.0, 0.0, 1.0), fragOutput, mixVal);\n";
1427 }
1428 }
1429
generateMaterialShader__anon06cffe670111::QSSGShaderGenerator1430 QSSGRef<QSSGRenderShaderProgram> generateMaterialShader(const QByteArray &inShaderPrefix)
1431 {
1432 // build a string that allows us to print out the shader we are generating to the log.
1433 // This is time consuming but I feel like it doesn't happen all that often and is very
1434 // useful to users
1435 // looking at the log file.
1436
1437 QByteArray generatedShaderString;
1438 generatedShaderString = inShaderPrefix;
1439
1440 QSSGShaderDefaultMaterialKey theKey(key());
1441 theKey.toString(generatedShaderString, m_defaultMaterialShaderKeyProperties);
1442
1443 m_lightsAsSeparateUniforms = !m_renderContext->renderContext()->supportsConstantBuffer();
1444
1445 generateVertexShader(theKey);
1446 generateFragmentShader(theKey);
1447
1448 vertexGenerator().endVertexGeneration(false);
1449 vertexGenerator().endFragmentGeneration(false);
1450
1451 return programGenerator()->compileGeneratedShader(generatedShaderString, QSSGShaderCacheProgramFlags(), m_currentFeatureSet);
1452 }
1453
generateShader__anon06cffe670111::QSSGShaderGenerator1454 QSSGRef<QSSGRenderShaderProgram> generateShader(const QSSGRenderGraphObject &inMaterial,
1455 QSSGShaderDefaultMaterialKey inShaderDescription,
1456 QSSGShaderStageGeneratorInterface &inVertexPipeline,
1457 const ShaderFeatureSetList &inFeatureSet,
1458 const QVector<QSSGRenderLight *> &inLights,
1459 QSSGRenderableImage *inFirstImage,
1460 bool inHasTransparency,
1461 const QByteArray &inVertexPipelineName,
1462 const QByteArray &) override
1463 {
1464 Q_ASSERT(inMaterial.type == QSSGRenderGraphObject::Type::DefaultMaterial || inMaterial.type == QSSGRenderGraphObject::Type::PrincipledMaterial);
1465 m_currentMaterial = static_cast<const QSSGRenderDefaultMaterial *>(&inMaterial);
1466 m_currentKey = &inShaderDescription;
1467 m_currentPipeline = static_cast<QSSGDefaultMaterialVertexPipelineInterface *>(&inVertexPipeline);
1468 m_currentFeatureSet = inFeatureSet;
1469 m_lights = inLights;
1470 m_firstImage = inFirstImage;
1471 m_hasTransparency = inHasTransparency;
1472
1473 return generateMaterialShader(inVertexPipelineName);
1474 }
1475
getShaderForProgram__anon06cffe670111::QSSGShaderGenerator1476 const QSSGRef<QSSGShaderGeneratorGeneratedShader> &getShaderForProgram(const QSSGRef<QSSGRenderShaderProgram> &inProgram)
1477 {
1478 auto inserter = m_programToShaderMap.constFind(inProgram);
1479 if (inserter == m_programToShaderMap.constEnd())
1480 inserter = m_programToShaderMap.insert(inProgram,
1481 QSSGRef<QSSGShaderGeneratorGeneratedShader>(
1482 new QSSGShaderGeneratorGeneratedShader(inProgram,
1483 m_renderContext->renderContext())));
1484
1485 return inserter.value();
1486 }
1487
setGlobalProperties__anon06cffe670111::QSSGShaderGenerator1488 void setGlobalProperties(const QSSGRef<QSSGRenderShaderProgram> &inProgram,
1489 const QSSGRenderLayer & /*inLayer*/,
1490 QSSGRenderCamera &inCamera,
1491 const QVector3D &inCameraDirection,
1492 const QVector<QSSGRenderLight *> &inLights,
1493 const QVector<QVector3D> &inLightDirections,
1494 const QSSGRef<QSSGRenderShadowMap> &inShadowMapManager,
1495 bool receivesShadows = true)
1496 {
1497 const QSSGRef<QSSGShaderGeneratorGeneratedShader> &shader(getShaderForProgram(inProgram));
1498 m_renderContext->renderContext()->setActiveShader(inProgram);
1499
1500 m_shadowMapManager = inShadowMapManager;
1501
1502 QSSGRenderCamera &theCamera(inCamera);
1503 shader->m_cameraPosition.set(theCamera.getGlobalPos());
1504 shader->m_cameraDirection.set(inCameraDirection);
1505
1506 QMatrix4x4 viewProj;
1507 if (shader->m_viewProj.isValid()) {
1508 theCamera.calculateViewProjectionMatrix(viewProj);
1509 shader->m_viewProj.set(viewProj);
1510 }
1511
1512 if (shader->m_viewMatrix.isValid()) {
1513 viewProj = theCamera.globalTransform.inverted();
1514 shader->m_viewMatrix.set(viewProj);
1515 }
1516
1517 // update the constant buffer
1518 shader->m_aoShadowParams.set();
1519 // We can't cache light properties because they can change per object.
1520 QVector3D theLightAmbientTotal = QVector3D(0, 0, 0);
1521 size_t numShaderLights = shader->m_lights.size();
1522 size_t numShadowLights = shader->m_shadowMaps.size();
1523 for (quint32 lightIdx = 0, shadowMapIdx = 0, lightEnd = inLights.size(); lightIdx < lightEnd && lightIdx < QSSG_MAX_NUM_LIGHTS;
1524 ++lightIdx) {
1525 QSSGRenderLight *theLight(inLights[lightIdx]);
1526 if (lightIdx >= numShaderLights) {
1527 shader->m_lights.push_back(QSSGShaderLightProperties());
1528 ++numShaderLights;
1529 }
1530 if (shadowMapIdx >= numShadowLights && numShadowLights < QSSG_MAX_NUM_SHADOWS && receivesShadows) {
1531 if (theLight->m_scope == nullptr && theLight->m_castShadow) {
1532 // PKC TODO : Fix multiple shadow issues.
1533 // Need to know when the list of lights changes order, and clear shadow maps
1534 // when that happens.
1535 setupShadowMapVariableNames(lightIdx);
1536 shader->m_shadowMaps.push_back(
1537 QSSGShadowMapProperties(m_shadowMapStem, m_shadowCubeStem, m_shadowMatrixStem, m_shadowControlStem, inProgram));
1538 }
1539 }
1540 Q_ASSERT(lightIdx < numShaderLights);
1541 QSSGShaderLightProperties &theLightProperties(shader->m_lights[lightIdx]);
1542 float brightness = aux::translateBrightness(theLight->m_brightness);
1543
1544 // setup light data
1545 theLightProperties.lightColor = theLight->m_diffuseColor * brightness;
1546 theLightProperties.lightData.specular = QVector4D(theLight->m_specularColor * brightness, 1.0);
1547 theLightProperties.lightData.direction = QVector4D(inLightDirections[lightIdx], 1.0);
1548
1549 // TODO : This does potentially mean that we can create more shadow map entries than
1550 // we can actually use at once.
1551 if ((theLight->m_scope == nullptr) && (theLight->m_castShadow && receivesShadows && inShadowMapManager)) {
1552 QSSGShadowMapProperties &theShadowMapProperties(shader->m_shadowMaps[shadowMapIdx++]);
1553 QSSGShadowMapEntry *pEntry = inShadowMapManager->getShadowMapEntry(lightIdx);
1554 if (pEntry) {
1555 // add fixed scale bias matrix
1556 QMatrix4x4 bias = { 0.5, 0.0, 0.0, 0.5,
1557 0.0, 0.5, 0.0, 0.5,
1558 0.0, 0.0, 0.5, 0.5,
1559 0.0, 0.0, 0.0, 1.0 };
1560
1561 if (theLight->m_lightType != QSSGRenderLight::Type::Directional) {
1562 theShadowMapProperties.m_shadowCubeTexture.set(pEntry->m_depthCube.data());
1563 theShadowMapProperties.m_shadowmapMatrix.set(pEntry->m_lightView);
1564 } else {
1565 theShadowMapProperties.m_shadowmapTexture.set(pEntry->m_depthMap.data());
1566 theShadowMapProperties.m_shadowmapMatrix.set(bias * pEntry->m_lightVP);
1567 }
1568
1569 theShadowMapProperties.m_shadowmapSettings.set(
1570 QVector4D(theLight->m_shadowBias, theLight->m_shadowFactor, theLight->m_shadowMapFar, 0.0f));
1571 } else {
1572 // if we have a light casting shadow we should find an entry
1573 Q_ASSERT(false);
1574 }
1575 }
1576
1577 if (theLight->m_lightType == QSSGRenderLight::Type::Point
1578 || theLight->m_lightType == QSSGRenderLight::Type::Spot) {
1579 theLightProperties.lightData.position = QVector4D(theLight->getGlobalPos(), 1.0);
1580 theLightProperties.lightData.constantAttenuation = aux::translateConstantAttenuation(theLight->m_constantFade);
1581 theLightProperties.lightData.linearAttenuation = aux::translateLinearAttenuation(theLight->m_linearFade);
1582 theLightProperties.lightData.quadraticAttenuation = aux::translateQuadraticAttenuation(theLight->m_quadraticFade);
1583 theLightProperties.lightData.coneAngle = 180.0f;
1584 if (theLight->m_lightType == QSSGRenderLight::Type::Spot) {
1585 theLightProperties.lightData.coneAngle
1586 = qCos(qDegreesToRadians(theLight->m_coneAngle));
1587 float innerConeAngle = theLight->m_innerConeAngle;
1588 if (theLight->m_innerConeAngle > theLight->m_coneAngle)
1589 innerConeAngle = theLight->m_coneAngle;
1590 theLightProperties.lightData.innerConeAngle
1591 = qCos(qDegreesToRadians(innerConeAngle));
1592 }
1593 } else if (theLight->m_lightType == QSSGRenderLight::Type::Area) {
1594 theLightProperties.lightData.position = QVector4D(theLight->getGlobalPos(), 1.0);
1595
1596 QVector3D upDir = mat33::transform(mat44::getUpper3x3(theLight->globalTransform), QVector3D(0, 1, 0));
1597 QVector3D rtDir = mat33::transform(mat44::getUpper3x3(theLight->globalTransform), QVector3D(1, 0, 0));
1598
1599 theLightProperties.lightData.up = QVector4D(upDir, theLight->m_areaHeight);
1600 theLightProperties.lightData.right = QVector4D(rtDir, theLight->m_areaWidth);
1601 }
1602 theLightAmbientTotal += theLight->m_ambientColor;
1603 }
1604 shader->m_lightAmbientTotal = theLightAmbientTotal;
1605 }
1606
1607 // Also sets the blend function on the render context.
setMaterialProperties__anon06cffe670111::QSSGShaderGenerator1608 void setMaterialProperties(const QSSGRef<QSSGRenderShaderProgram> &inProgram,
1609 const QSSGRenderDefaultMaterial &inMaterial,
1610 const QVector2D &inCameraVec,
1611 const QMatrix4x4 &inModelViewProjection,
1612 const QMatrix3x3 &inNormalMatrix,
1613 const QMatrix4x4 &inGlobalTransform,
1614 QSSGRenderableImage *inFirstImage,
1615 float inOpacity,
1616 const QSSGRef<QSSGRenderTexture2D> &inDepthTexture,
1617 const QSSGRef<QSSGRenderTexture2D> &inSSaoTexture,
1618 QSSGRenderImage *inLightProbe,
1619 QSSGRenderImage *inLightProbe2,
1620 float inProbeHorizon,
1621 float inProbeBright,
1622 float inProbe2Window,
1623 float inProbe2Pos,
1624 float inProbe2Fade,
1625 float inProbeFOV)
1626 {
1627
1628 const QSSGRef<QSSGRenderContext> &context = m_renderContext->renderContext();
1629 const QSSGRef<QSSGShaderGeneratorGeneratedShader> &shader = getShaderForProgram(inProgram);
1630 shader->m_mvp.set(inModelViewProjection);
1631 shader->m_normalMatrix.set(inNormalMatrix);
1632 shader->m_globalTransform.set(inGlobalTransform);
1633 shader->m_depthTexture.set(inDepthTexture.data());
1634
1635 shader->m_aoTexture.set(inSSaoTexture.data());
1636
1637 QSSGRenderImage *theLightProbe = inLightProbe;
1638 QSSGRenderImage *theLightProbe2 = inLightProbe2;
1639
1640 // If the material has its own IBL Override, we should use that image instead.
1641 const bool hasIblProbe = inMaterial.iblProbe != nullptr;
1642 const bool useMaterialIbl = hasIblProbe ? (inMaterial.iblProbe->m_textureData.m_texture != nullptr) : false;
1643 if (useMaterialIbl)
1644 theLightProbe = inMaterial.iblProbe;
1645
1646 if (theLightProbe) {
1647 if (theLightProbe->m_textureData.m_texture) {
1648 QSSGRenderTextureCoordOp theHorzLightProbeTilingMode = QSSGRenderTextureCoordOp::Repeat;
1649 QSSGRenderTextureCoordOp theVertLightProbeTilingMode = theLightProbe->m_verticalTilingMode;
1650 theLightProbe->m_textureData.m_texture->setTextureWrapS(theHorzLightProbeTilingMode);
1651 theLightProbe->m_textureData.m_texture->setTextureWrapT(theVertLightProbeTilingMode);
1652 const QMatrix4x4 &textureTransform = theLightProbe->m_textureTransform;
1653 // We separate rotational information from offset information so that just maybe the
1654 // shader
1655 // will attempt to push less information to the card.
1656 const float *dataPtr(textureTransform.constData());
1657 // The third member of the offsets contains a flag indicating if the texture was
1658 // premultiplied or not.
1659 // We use this to mix the texture alpha.
1660 QVector4D offsets(dataPtr[12],
1661 dataPtr[13],
1662 theLightProbe->m_textureData.m_textureFlags.isPreMultiplied() ? 1.0f : 0.0f,
1663 (float)theLightProbe->m_textureData.m_texture->numMipmaps());
1664
1665 // Grab just the upper 2x2 rotation matrix from the larger matrix.
1666 QVector4D rotations(dataPtr[0], dataPtr[4], dataPtr[1], dataPtr[5]);
1667
1668 shader->m_lightProbeRot.set(rotations);
1669 shader->m_lightProbeOfs.set(offsets);
1670
1671 if ((!inMaterial.iblProbe) && (inProbeFOV < 180.f)) {
1672 shader->m_lightProbeOpts.set(QVector4D(0.01745329251994329547f * inProbeFOV, 0.0f, 0.0f, 0.0f));
1673 }
1674
1675 // Also make sure to add the secondary texture, but it should only be added if the
1676 // primary
1677 // (i.e. background) texture is also there.
1678 if (theLightProbe2 && theLightProbe2->m_textureData.m_texture) {
1679 theLightProbe2->m_textureData.m_texture->setTextureWrapS(theHorzLightProbeTilingMode);
1680 theLightProbe2->m_textureData.m_texture->setTextureWrapT(theVertLightProbeTilingMode);
1681 shader->m_lightProbe2.set(theLightProbe2->m_textureData.m_texture.data());
1682 shader->m_lightProbe2Props.set(QVector4D(inProbe2Window, inProbe2Pos, inProbe2Fade, 1.0f));
1683
1684 const QMatrix4x4 &xform2 = theLightProbe2->m_textureTransform;
1685 const float *dataPtr(xform2.constData());
1686 shader->m_lightProbeProps.set(QVector4D(dataPtr[12], dataPtr[13], inProbeHorizon, inProbeBright * 0.01f));
1687 } else {
1688 shader->m_lightProbe2Props.set(QVector4D(0.0f, 0.0f, 0.0f, 0.0f));
1689 shader->m_lightProbeProps.set(QVector4D(0.0f, 0.0f, inProbeHorizon, inProbeBright * 0.01f));
1690 }
1691 const QSSGRef<QSSGRenderTexture2D> &textureImage = theLightProbe->m_textureData.m_texture;
1692 shader->m_lightProbe.set(textureImage.data());
1693 shader->m_lightProbeSize.set(
1694 QVector2D(textureImage->textureDetails().width, textureImage->textureDetails().height));
1695 } else {
1696 shader->m_lightProbeProps.set(QVector4D(0.0f, 0.0f, -1.0f, 0.0f));
1697 shader->m_lightProbe2Props.set(QVector4D(0.0f, 0.0f, 0.0f, 0.0f));
1698 }
1699 } else {
1700 shader->m_lightProbeProps.set(QVector4D(0.0f, 0.0f, -1.0f, 0.0f));
1701 shader->m_lightProbe2Props.set(QVector4D(0.0f, 0.0f, 0.0f, 0.0f));
1702 }
1703
1704 const auto &color = inMaterial.color;
1705 shader->m_materialDiffuse.set(inMaterial.emissiveColor);
1706
1707 const auto qMix = [](float x, float y, float a) {
1708 return (x * (1.0f - a) + (y * a));
1709 };
1710
1711 const auto qMix3 = [&qMix](const QVector3D &x, const QVector3D &y, float a) {
1712 return QVector3D{qMix(x.x(), y.x(), a), qMix(x.y(), y.y(), a), qMix(x.z(), y.z(), a)};
1713 };
1714
1715 const auto &specularTint = (inMaterial.type == QSSGRenderGraphObject::Type::PrincipledMaterial) ? qMix3(QVector3D(1.0f, 1.0f, 1.0f), color.toVector3D(), inMaterial.specularTint.x())
1716 : inMaterial.specularTint;
1717
1718 shader->m_baseColor.set(color);
1719 shader->m_materialSpecular.set(QVector4D(specularTint, inMaterial.ior));
1720 shader->m_cameraProperties.set(inCameraVec);
1721 shader->m_fresnelPower.set(inMaterial.fresnelPower);
1722
1723 const bool hasLighting = inMaterial.lighting != QSSGRenderDefaultMaterial::MaterialLighting::NoLighting;
1724 if (hasLighting) {
1725 if (context->supportsConstantBuffer()) {
1726 const QSSGRef<QSSGRenderConstantBuffer> &pLightCb = getLightConstantBuffer(shader->m_lights.size());
1727 // if we have lights we need a light buffer
1728 Q_ASSERT(shader->m_lights.size() == 0 || pLightCb);
1729
1730 for (qint32 idx = 0, end = shader->m_lights.size(); idx < end && pLightCb; ++idx) {
1731 auto &lightProp = shader->m_lights[idx];
1732 lightProp.lightData.diffuse = QVector4D(lightProp.lightColor, 1.0);
1733
1734 // this is our final change update memory
1735 pLightCb->updateRaw(quint32(idx) * sizeof(QSSGLightSourceShader) + (4 * sizeof(qint32)), toByteView(lightProp.lightData));
1736 }
1737 // update light buffer to hardware
1738 if (pLightCb) {
1739 qint32 cgLights = shader->m_lights.size();
1740 pLightCb->updateRaw(0, toByteView(cgLights));
1741 shader->m_lightsBuffer.set();
1742 }
1743 } else {
1744 QSSGLightConstantProperties<QSSGShaderGeneratorGeneratedShader> *pLightConstants = getLightConstantProperties(shader);
1745
1746 // if we have lights we need a light buffer
1747 Q_ASSERT(shader->m_lights.size() == 0 || pLightConstants);
1748
1749 for (qint32 idx = 0, end = shader->m_lights.size(); idx < end && pLightConstants; ++idx) {
1750 auto &lightProp = shader->m_lights[idx];
1751 lightProp.lightData.diffuse = QVector4D(lightProp.lightColor, 1.0);
1752 }
1753 // update light buffer to hardware
1754 if (pLightConstants)
1755 pLightConstants->updateLights(shader);
1756 }
1757 }
1758
1759 shader->m_materialDiffuseLightAmbientTotal.set(shader->m_lightAmbientTotal);
1760 shader->m_materialProperties.set(QVector4D(inMaterial.specularAmount, inMaterial.specularRoughness, inMaterial.metalnessAmount, inOpacity));
1761 shader->m_bumpAmount.set(inMaterial.bumpAmount);
1762 shader->m_displaceAmount.set(inMaterial.displaceAmount);
1763 shader->m_translucentFalloff.set(inMaterial.translucentFalloff);
1764 shader->m_diffuseLightWrap.set(inMaterial.diffuseLightWrap);
1765 shader->m_occlusionAmount.set(inMaterial.occlusionAmount);
1766 shader->m_alphaCutoff.set(inMaterial.alphaCutoff);
1767
1768 quint32 imageIdx = 0;
1769 for (QSSGRenderableImage *theImage = inFirstImage; theImage; theImage = theImage->m_nextImage, ++imageIdx)
1770 setImageShaderVariables(shader, *theImage, imageIdx);
1771
1772 QSSGRenderBlendFunctionArgument blendFunc;
1773 QSSGRenderBlendEquationArgument blendEqua(QSSGRenderBlendEquation::Add, QSSGRenderBlendEquation::Add);
1774 // The blend function goes:
1775 // src op
1776 // dst op
1777 // src alpha op
1778 // dst alpha op
1779 // All of our shaders produce non-premultiplied values.
1780 switch (inMaterial.blendMode) {
1781 case QSSGRenderDefaultMaterial::MaterialBlendMode::Screen:
1782 blendFunc = QSSGRenderBlendFunctionArgument(QSSGRenderSrcBlendFunc::One,
1783 QSSGRenderDstBlendFunc::OneMinusSrcColor,
1784 QSSGRenderSrcBlendFunc::One,
1785 QSSGRenderDstBlendFunc::OneMinusSrcColor);
1786 break;
1787 case QSSGRenderDefaultMaterial::MaterialBlendMode::Multiply:
1788 blendFunc = QSSGRenderBlendFunctionArgument(QSSGRenderSrcBlendFunc::DstColor,
1789 QSSGRenderDstBlendFunc::Zero,
1790 QSSGRenderSrcBlendFunc::One,
1791 QSSGRenderDstBlendFunc::One);
1792 break;
1793 case QSSGRenderDefaultMaterial::MaterialBlendMode::Overlay:
1794 // SW fallback is not using blend equation
1795 // note blend func is not used here anymore
1796 if (context->supportsAdvancedBlendHW() || context->supportsAdvancedBlendHwKHR())
1797 blendEqua = QSSGRenderBlendEquationArgument(QSSGRenderBlendEquation::Overlay, QSSGRenderBlendEquation::Overlay);
1798 break;
1799 case QSSGRenderDefaultMaterial::MaterialBlendMode::ColorBurn:
1800 // SW fallback is not using blend equation
1801 // note blend func is not used here anymore
1802 if (context->supportsAdvancedBlendHW() || context->supportsAdvancedBlendHwKHR())
1803 blendEqua = QSSGRenderBlendEquationArgument(QSSGRenderBlendEquation::ColorBurn,
1804 QSSGRenderBlendEquation::ColorBurn);
1805 break;
1806 case QSSGRenderDefaultMaterial::MaterialBlendMode::ColorDodge:
1807 // SW fallback is not using blend equation
1808 // note blend func is not used here anymore
1809 if (context->supportsAdvancedBlendHW() || context->supportsAdvancedBlendHwKHR())
1810 blendEqua = QSSGRenderBlendEquationArgument(QSSGRenderBlendEquation::ColorDodge,
1811 QSSGRenderBlendEquation::ColorDodge);
1812 break;
1813 default:
1814 blendFunc = QSSGRenderBlendFunctionArgument(QSSGRenderSrcBlendFunc::SrcAlpha,
1815 QSSGRenderDstBlendFunc::OneMinusSrcAlpha,
1816 QSSGRenderSrcBlendFunc::One,
1817 QSSGRenderDstBlendFunc::OneMinusSrcAlpha);
1818 break;
1819 }
1820 context->setBlendFunction(blendFunc);
1821 context->setBlendEquation(blendEqua);
1822 }
setMaterialProperties__anon06cffe670111::QSSGShaderGenerator1823 void setMaterialProperties(const QSSGRef<QSSGRenderShaderProgram> &inProgram,
1824 const QSSGRenderGraphObject &inMaterial,
1825 const QVector2D &inCameraVec,
1826 const QMatrix4x4 &inModelViewProjection,
1827 const QMatrix3x3 &inNormalMatrix,
1828 const QMatrix4x4 &inGlobalTransform,
1829 QSSGRenderableImage *inFirstImage,
1830 float inOpacity,
1831 const QSSGLayerGlobalRenderProperties &inRenderProperties,
1832 bool receivesShadows) override
1833 {
1834 const QSSGRenderDefaultMaterial &theMaterial(static_cast<const QSSGRenderDefaultMaterial &>(inMaterial));
1835 Q_ASSERT(inMaterial.type == QSSGRenderGraphObject::Type::DefaultMaterial || inMaterial.type == QSSGRenderGraphObject::Type::PrincipledMaterial);
1836
1837
1838 setGlobalProperties(inProgram,
1839 inRenderProperties.layer,
1840 inRenderProperties.camera,
1841 inRenderProperties.cameraDirection,
1842 inRenderProperties.lights,
1843 inRenderProperties.lightDirections,
1844 inRenderProperties.shadowMapManager,
1845 receivesShadows);
1846 setMaterialProperties(inProgram,
1847 theMaterial,
1848 inCameraVec,
1849 inModelViewProjection,
1850 inNormalMatrix,
1851 inGlobalTransform,
1852 inFirstImage,
1853 inOpacity,
1854 inRenderProperties.depthTexture,
1855 inRenderProperties.ssaoTexture,
1856 inRenderProperties.lightProbe,
1857 inRenderProperties.lightProbe2,
1858 inRenderProperties.probeHorizon,
1859 inRenderProperties.probeBright,
1860 inRenderProperties.probe2Window,
1861 inRenderProperties.probe2Pos,
1862 inRenderProperties.probe2Fade,
1863 inRenderProperties.probeFOV);
1864 }
1865
getLightConstantProperties__anon06cffe670111::QSSGShaderGenerator1866 QSSGLightConstantProperties<QSSGShaderGeneratorGeneratedShader> *getLightConstantProperties(
1867 const QSSGRef<QSSGShaderGeneratorGeneratedShader> &shader)
1868 {
1869 if (!shader->m_lightConstantProperties
1870 || int(shader->m_lights.size()) > shader->m_lightConstantProperties->m_constants.size()) {
1871 if (shader->m_lightConstantProperties)
1872 delete shader->m_lightConstantProperties;
1873 shader->m_lightConstantProperties = new QSSGLightConstantProperties<QSSGShaderGeneratorGeneratedShader>(shader.data(), m_lightsAsSeparateUniforms);
1874 }
1875 return shader->m_lightConstantProperties;
1876 }
1877 };
1878 }
1879
createDefaultMaterialShaderGenerator(QSSGRenderContextInterface * inRc)1880 QSSGRef<QSSGDefaultMaterialShaderGeneratorInterface> QSSGDefaultMaterialShaderGeneratorInterface::createDefaultMaterialShaderGenerator(
1881 QSSGRenderContextInterface *inRc)
1882 {
1883 return QSSGRef<QSSGDefaultMaterialShaderGeneratorInterface>(new QSSGShaderGenerator(inRc));
1884 }
1885
1886 QSSGDefaultMaterialVertexPipelineInterface::~QSSGDefaultMaterialVertexPipelineInterface() = default;
1887
1888 QT_END_NAMESPACE
1889