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
qssgvertexpipelineimpl.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
8
9#include <QtCore/qregularexpression.h>
10
11#include <QtQuick3DRuntimeRender/private/qssgrenderer_p.h>
12#include <QtQuick3DRuntimeRender/private/qssgrenderlight_p.h>
13#include "../qssgrendercontextcore.h"
14#include <QtQuick3DRuntimeRender/private/qssgrendershadercache_p.h>
15#include <QtQuick3DRuntimeRender/private/qssgrendershaderlibrarymanager_p.h>
16#include <QtQuick3DRuntimeRender/private/qssgrendershadercodegenerator_p.h>
17#include <QtQuick3DRuntimeRender/private/qssgrenderdefaultmaterialshadergenerator_p.h>
18#include <QtQuick3DRuntimeRender/private/qssgshadermaterialadapter_p.h>
19
21
22QSSGMaterialVertexPipeline::QSSGMaterialVertexPipeline(QSSGProgramGenerator &programGen,
25 : m_programGenerator(&programGen)
26 , defaultMaterialShaderKeyProperties(materialProperties)
27 , materialAdapter(materialAdapter)
28 , hasCustomShadedMain(false)
29 , skipCustomFragmentSnippet(false)
30{
31}
32
33static inline void insertProcessorArgsFragmentMain(QByteArray &snippet, const char *argKey, const char* (*argListFunc)(),
34 QSSGShaderMaterialAdapter *materialAdapter = nullptr, bool isSharedInout = false)
35{
36 const int argKeyLen = int(strlen(argKey));
37 const int argKeyPos = snippet.indexOf(argKey);
38 if (argKeyPos >= 0) {
39 QByteArray flexArgs;
40 if (materialAdapter) {
41 if (materialAdapter->isClearcoatEnabled()) {
42 flexArgs += QByteArrayLiteral(", inout float CLEARCOAT_AMOUNT, inout float CLEARCOAT_FRESNEL_POWER, inout float CLEARCOAT_ROUGHNESS, inout vec3 CLEARCOAT_NORMAL");
43 if (materialAdapter->isClearcoatFresnelScaleBiasEnabled())
44 flexArgs += QByteArrayLiteral(", inout float CLEARCOAT_FRESNEL_SCALE, inout float CLEARCOAT_FRESNEL_BIAS");
45 }
46 if (materialAdapter->isSheenEnabled())
47 flexArgs += QByteArrayLiteral(", inout vec3 SHEEN_COLOR, inout float SHEEN_ROUGHNESS");
48 if (materialAdapter->isAnisotropyEnabled())
49 flexArgs += QByteArrayLiteral(", inout float ANISOTROPY_STRENGTH, inout float ANISOTROPY_ROTATION");
50 if (materialAdapter->isIridescenceEnabled())
51 flexArgs += QByteArrayLiteral(", inout float IRIDESCENCE_FACTOR, inout float IRIDESCENCE_IOR, inout float IRIDESCENCE_THICKNESS");
52 if (materialAdapter->isFresnelScaleBiasEnabled())
53 flexArgs += QByteArrayLiteral(", inout float FRESNEL_SCALE, inout float FRESNEL_BIAS");
54 if (materialAdapter->isDispersionEnabled())
55 flexArgs += QByteArrayLiteral(", inout float DISPERSION");
56 if (materialAdapter->isTransmissionEnabled())
57 flexArgs += QByteArrayLiteral(", inout float TRANSMISSION_FACTOR, inout float THICKNESS_FACTOR, inout vec3 ATTENUATION_COLOR, inout float ATTENUATION_DISTANCE");
58 if (materialAdapter->usesSharedVariables()) {
59 const char *inoutString = isSharedInout ? ", inout " : ", in ";
60 flexArgs += inoutString + QByteArrayLiteral("QT_SHARED_VARS SHARED");
61 }
62 }
63 snippet = snippet.left(argKeyPos) + argListFunc() + flexArgs + snippet.mid(argKeyPos + argKeyLen);
64 }
65}
66
67static inline void insertProcessorArgs(QByteArray &snippet, const char *argKey, const char* (*argListFunc)(),
68 QSSGShaderMaterialAdapter *materialAdapter = nullptr, bool isSharedInout = false)
69{
70 const int argKeyLen = int(strlen(argKey));
71 const int argKeyPos = snippet.indexOf(argKey);
72 if (argKeyPos >= 0) {
73 QByteArray flexArgs;
74 if (materialAdapter && materialAdapter->usesSharedVariables()) {
75 const char *inoutString = isSharedInout ? ", inout " : ", in ";
76 flexArgs += inoutString + QByteArrayLiteral("QT_SHARED_VARS SHARED");
77 }
78 snippet = snippet.left(argKeyPos) + argListFunc() + flexArgs + snippet.mid(argKeyPos + argKeyLen);
79 }
80}
81
82static inline void insertDirectionalLightProcessorArgs(QByteArray &snippet, QSSGShaderMaterialAdapter *materialAdapter)
83{
84 insertProcessorArgs(snippet, "/*%QT_ARGS_DIRECTIONAL_LIGHT%*/", QSSGMaterialShaderGenerator::directionalLightProcessorArgumentList, materialAdapter, true);
85}
86
87static inline void insertPointLightProcessorArgs(QByteArray &snippet, QSSGShaderMaterialAdapter *materialAdapter)
88{
89 insertProcessorArgs(snippet, "/*%QT_ARGS_POINT_LIGHT%*/", QSSGMaterialShaderGenerator::pointLightProcessorArgumentList, materialAdapter, true);
90}
91
92static inline void insertSpotLightProcessorArgs(QByteArray &snippet, QSSGShaderMaterialAdapter *materialAdapter)
93{
94 insertProcessorArgs(snippet, "/*%QT_ARGS_SPOT_LIGHT%*/", QSSGMaterialShaderGenerator::spotLightProcessorArgumentList, materialAdapter, true);
95}
96
97static inline void insertAmbientLightProcessorArgs(QByteArray &snippet, QSSGShaderMaterialAdapter *materialAdapter)
98{
99 insertProcessorArgs(snippet, "/*%QT_ARGS_AMBIENT_LIGHT%*/", QSSGMaterialShaderGenerator::ambientLightProcessorArgumentList, materialAdapter, true);
100}
101
102static inline void insertIblProbeProcessorArgs(QByteArray &snippet, QSSGShaderMaterialAdapter *materialAdapter)
103{
104 insertProcessorArgs(snippet, "/*%QT_ARGS_IBL_PROBE%*/", QSSGMaterialShaderGenerator::iblProbeProcessorArgumentList, materialAdapter, true);
105}
106
107static inline void insertSpecularLightProcessorArgs(QByteArray &snippet, QSSGShaderMaterialAdapter *materialAdapter)
108{
109 insertProcessorArgs(snippet, "/*%QT_ARGS_SPECULAR_LIGHT%*/", QSSGMaterialShaderGenerator::specularLightProcessorArgumentList, materialAdapter, true);
110}
111
112static inline void insertFragmentMainArgs(QByteArray &snippet, QSSGShaderMaterialAdapter *materialAdapter)
113{
114 insertProcessorArgsFragmentMain(snippet, "/*%QT_ARGS_MAIN%*/", QSSGMaterialShaderGenerator::shadedFragmentMainArgumentList, materialAdapter, true);
115}
116
117static inline void insertPostProcessorArgs(QByteArray &snippet, QSSGShaderMaterialAdapter *materialAdapter)
118{
119 insertProcessorArgs(snippet, "/*%QT_ARGS_POST_PROCESS%*/", QSSGMaterialShaderGenerator::postProcessorArgumentList, materialAdapter, false);
120}
121
122static inline void insertVertexMainArgs(QByteArray &snippet)
123{
124 insertProcessorArgs(snippet, "/*%QT_ARGS_MAIN%*/", QSSGMaterialShaderGenerator::vertexMainArgumentList);
125}
126
127static inline void insertVertexInstancedMainArgs(QByteArray &snippet)
128{
129 insertProcessorArgs(snippet, "/*%QT_ARGS_MAIN%*/", QSSGMaterialShaderGenerator::vertexInstancedMainArgumentList);
130}
131
132static inline const char *customMainCallWithArguments(bool usesInstancing)
133{
134 if (usesInstancing)
135 return " qt_customMain(qt_vertPosition.xyz, qt_vertNormal, qt_vertUV0, qt_vertUV1, qt_vertTangent, qt_vertBinormal, qt_vertJoints, qt_vertWeights, qt_vertColor, qt_instancedModelMatrix, qt_instancedMVPMatrix);";
136 else
137 return " qt_customMain(qt_vertPosition.xyz, qt_vertNormal, qt_vertUV0, qt_vertUV1, qt_vertTangent, qt_vertBinormal, qt_vertJoints, qt_vertWeights, qt_vertColor);\n";
138}
139
140static inline QByteArray extractSharedVarsTypeDefinition(QByteArray &snippet, QSSGShaderMaterialAdapter *materialAdapter) {
141 if (materialAdapter->usesSharedVariables()) {
142 // Extract shared variables from the custom shader snippet
143 static QRegularExpression re(QString::fromLocal8Bit(R"(struct\s+QT_SHARED_VARS\s*\{[\s\S]*?\};)"), QRegularExpression::DotMatchesEverythingOption);
144 QRegularExpressionMatch match = re.match(QString::fromLocal8Bit(snippet));
145 if (!match.hasMatch())
146 return QByteArray();
147 QString typeDefinition = match.captured(0);
148 snippet.remove(match.capturedStart(0), match.capturedLength(0));
149 return typeDefinition.toLocal8Bit();
150 }
151 return QByteArray();
152}
153
154void QSSGMaterialVertexPipeline::beginVertexGeneration(const QSSGShaderDefaultMaterialKey &inKey,
155 const QSSGShaderFeatures &inFeatureSet,
156 QSSGShaderLibraryManager &shaderLibraryManager)
157{
158 QSSGShaderGeneratorStageFlags theStages(QSSGProgramGenerator::defaultFlags());
159 programGenerator()->beginProgram(theStages);
160
161 QSSGStageGeneratorBase &vertexShader(vertex());
162
163 const bool meshHasNormals = defaultMaterialShaderKeyProperties.m_vertexAttributes.getBitValue(
164 QSSGShaderKeyVertexAttribute::Normal, inKey);
165 const bool meshHasTexCoord0 = defaultMaterialShaderKeyProperties.m_vertexAttributes.getBitValue(
166 QSSGShaderKeyVertexAttribute::TexCoord0, inKey);
167 const bool meshHasTexCoord1 = defaultMaterialShaderKeyProperties.m_vertexAttributes.getBitValue(
168 QSSGShaderKeyVertexAttribute::TexCoord1, inKey);
169 const bool meshHasTexCoordLightmap = defaultMaterialShaderKeyProperties.m_vertexAttributes.getBitValue(
170 QSSGShaderKeyVertexAttribute::TexCoordLightmap, inKey);
171 const bool meshHasTangents = defaultMaterialShaderKeyProperties.m_vertexAttributes.getBitValue(
172 QSSGShaderKeyVertexAttribute::Tangent, inKey);
173 const bool meshHasBinormals = defaultMaterialShaderKeyProperties.m_vertexAttributes.getBitValue(
174 QSSGShaderKeyVertexAttribute::Binormal, inKey);
175 const bool meshHasColors = defaultMaterialShaderKeyProperties.m_vertexAttributes.getBitValue(
176 QSSGShaderKeyVertexAttribute::Color, inKey);
177 const bool meshHasJointsAndWeights = defaultMaterialShaderKeyProperties.m_vertexAttributes.getBitValue(
178 QSSGShaderKeyVertexAttribute::JointAndWeight, inKey);
179 const bool overridesPosition = defaultMaterialShaderKeyProperties.m_overridesPosition.getValue(inKey);
180 const bool usesProjectionMatrix = defaultMaterialShaderKeyProperties.m_usesProjectionMatrix.getValue(inKey);
181 const bool usesInvProjectionMatrix = defaultMaterialShaderKeyProperties.m_usesInverseProjectionMatrix.getValue(inKey);
182 const bool usesPointsTopology = defaultMaterialShaderKeyProperties.m_usesPointsTopology.getValue(inKey);
183 const bool usesFloatJointIndices = defaultMaterialShaderKeyProperties.m_usesFloatJointIndices.getValue(inKey);
184 const bool blendParticles = defaultMaterialShaderKeyProperties.m_blendParticles.getValue(inKey);
185 usesInstancing = defaultMaterialShaderKeyProperties.m_usesInstancing.getValue(inKey);
186 m_hasSkinning = defaultMaterialShaderKeyProperties.m_boneCount.getValue(inKey) > 0;
187 const auto morphSize = defaultMaterialShaderKeyProperties.m_targetCount.getValue(inKey);
188 m_hasMorphing = morphSize > 0;
189 m_viewCount = inFeatureSet.isSet(QSSGShaderFeatures::Feature::DisableMultiView)
190 ? 1 : defaultMaterialShaderKeyProperties.m_viewCount.getValue(inKey);
191 const bool usesViewIndex = defaultMaterialShaderKeyProperties.m_usesViewIndex.getValue(inKey);
192
193 vertexShader.addIncoming("attr_pos", "vec3");
194 if (usesInstancing) {
195 vertexShader.addIncoming("qt_instanceTransform0", "vec4");
196 vertexShader.addIncoming("qt_instanceTransform1", "vec4");
197 vertexShader.addIncoming("qt_instanceTransform2", "vec4");
198 vertexShader.addIncoming("qt_instanceColor", "vec4");
199 vertexShader.addIncoming("qt_instanceData", "vec4");
200 }
201 if (blendParticles) {
202 vertexShader.addInclude("particles.glsllib");
203 vertexShader.addUniform("qt_particleTexture", "sampler2D");
204 vertexShader.addUniform("qt_countPerSlice", "uint");
205 vertexShader.addUniform("qt_oneOverParticleImageSize", "vec2");
206 vertexShader.addUniform("qt_particleMatrix", "mat4");
207 vertexShader.addUniform("qt_particleIndexOffset", "uint");
208 }
209
210 if (m_hasSkinning && meshHasJointsAndWeights) {
211 vertexShader.addInclude("skinanim.glsllib");
212 if (usesFloatJointIndices)
213 vertexShader.addIncoming("attr_joints", "vec4");
214 else
215 vertexShader.addIncoming("attr_joints", "ivec4");
216 vertexShader.addIncoming("attr_weights", "vec4");
217
218 vertexShader.addUniform("qt_boneTexture", "sampler2D");
219 }
220 if (m_hasMorphing) {
221 vertexShader.addInclude("morphanim.glsllib");
222 vertexShader.addUniformArray("qt_morphWeights", "float", morphSize);
223 vertexShader.addUniform("qt_morphTargetTexture", "sampler2DArray");
224 }
225
226 const bool hasCustomVertexShader = materialAdapter->hasCustomShaderSnippet(QSSGShaderCache::ShaderType::Vertex);
227 const bool hasCustomFragmentShader = materialAdapter->hasCustomShaderSnippet(QSSGShaderCache::ShaderType::Fragment);
228 if (hasCustomVertexShader) {
229 QByteArray snippet = materialAdapter->customShaderSnippet(QSSGShaderCache::ShaderType::Vertex,
230 shaderLibraryManager,
231 m_viewCount >= 2);
232 if (materialAdapter->hasCustomShaderFunction(QSSGShaderCache::ShaderType::Vertex,
233 QByteArrayLiteral("qt_customMain"),
234 shaderLibraryManager))
235 {
236 if (usesInstancing)
237 insertVertexInstancedMainArgs(snippet);
238 else
239 insertVertexMainArgs(snippet);
240
241 if (materialAdapter->usesCustomSkinning()) {
242 vertexShader.addInclude("skinanim.glsllib");
243 vertexShader.addUniform("qt_boneTexture", "sampler2D");
244 }
245
246 if (materialAdapter->usesCustomMorphing()) {
247 vertexShader.addInclude("morphanim_custom.glsllib");
248 if (morphSize > 0)
249 vertexShader.addUniformArray("qt_morphWeights", "float", morphSize);
250 vertexShader.addUniform("qt_morphTargetTexture", "sampler2DArray");
251 m_hasMorphing = false;
252 }
253
254 if (!materialAdapter->isUnshaded()) {
255 hasCustomShadedMain = true;
256 }
257 }
258 vertexShader << snippet;
259 }
260
261 vertexShader << "void main()"
262 << "\n"
263 << "{"
264 << "\n";
265 // These local variables will be used for whole the pipeline
266 // instead of each attributes since it is more convenient
267 // for adding new routines.
268 vertexShader.append(" vec4 qt_vertPosition = vec4(attr_pos, 1.0);");
269 vertexShader.append(" vec3 qt_vertNormal = vec3(0.0);");
270 vertexShader.append(" vec3 qt_vertTangent = vec3(0.0);");
271 vertexShader.append(" vec3 qt_vertBinormal = vec3(0.0);");
272 if (meshHasTexCoord0 || hasCustomVertexShader)
273 vertexShader.append(" vec2 qt_vertUV0 = vec2(0.0);");
274 if (meshHasTexCoord1 || hasCustomVertexShader)
275 vertexShader.append(" vec2 qt_vertUV1 = vec2(0.0);");
276 if (m_hasSkinning || hasCustomVertexShader)
277 vertexShader.append(" ivec4 qt_vertJoints = ivec4(0);");
278 if (meshHasJointsAndWeights || m_hasSkinning || hasCustomVertexShader)
279 vertexShader.append(" vec4 qt_vertWeights = vec4(0.0);");
280 if (meshHasColors || usesInstancing || blendParticles || hasCustomVertexShader || hasCustomFragmentShader)
281 vertexShader.append(" vec4 qt_vertColor = vec4(1.0);"); // must be 1,1,1,1 to not alter when multiplying with it
282
283 if (!usesInstancing) {
284 if (m_viewCount < 2)
285 vertexShader.addUniform("qt_modelViewProjection", "mat4");
286 else
287 vertexShader.addUniformArray("qt_modelViewProjection", "mat4", m_viewCount);
288 } else {
289 // Must manualy calculate a MVP
290 vertexShader.addUniform("qt_modelMatrix", "mat4");
291 vertexShader.addUniform("qt_parentMatrix", "mat4");
292 if (m_viewCount < 2)
293 vertexShader.addUniform("qt_viewProjectionMatrix", "mat4");
294 else
295 vertexShader.addUniformArray("qt_viewProjectionMatrix", "mat4", m_viewCount);
296 }
297
298 // The custom fragment main should be skipped if this is a
299 // depth (or normal texture) pass, but not if it is also a OpaqueDepthPrePass
300 // because then we need to know the real alpha values
301 skipCustomFragmentSnippet = false;
302 const bool isDepthPass = inFeatureSet.isSet(QSSGShaderFeatures::Feature::DepthPass);
303 const bool isOpaqueDepthPrePass = inFeatureSet.isSet(QSSGShaderFeatures::Feature::OpaqueDepthPrePass);
304 skipCustomFragmentSnippet = (isDepthPass && !isOpaqueDepthPrePass);
305
306 if (hasCustomVertexShader || hasCustomFragmentShader) {
307 // This is both for unshaded and shaded. Regardless of any other
308 // condition we have to ensure the keywords (VIEW_MATRIX etc.) promised
309 // by the documentation are available in *both* the custom vertex and
310 // fragment shader snippets, even if only one of them is present.
311 if (m_viewCount < 2) {
312 vertexShader.addUniform("qt_viewProjectionMatrix", "mat4");
313 vertexShader.addUniform("qt_viewMatrix", "mat4");
314 vertexShader.addUniform("qt_cameraPosition", "vec3");
315 vertexShader.addUniform("qt_cameraDirection", "vec3");
316 if (usesProjectionMatrix)
317 vertexShader.addUniform("qt_projectionMatrix", "mat4");
318 if (usesInvProjectionMatrix)
319 vertexShader.addUniform("qt_inverseProjectionMatrix", "mat4");
320 } else {
321 vertexShader.addUniformArray("qt_viewProjectionMatrix", "mat4", m_viewCount);
322 vertexShader.addUniformArray("qt_viewMatrix", "mat4", m_viewCount);
323 vertexShader.addUniformArray("qt_cameraPosition", "vec3", m_viewCount);
324 vertexShader.addUniformArray("qt_cameraDirection", "vec3", m_viewCount);
325 if (usesProjectionMatrix)
326 vertexShader.addUniformArray("qt_projectionMatrix", "mat4", m_viewCount);
327 if (usesInvProjectionMatrix)
328 vertexShader.addUniformArray("qt_inverseProjectionMatrix", "mat4", m_viewCount);
329 }
330 vertexShader.addUniform("qt_modelMatrix", "mat4");
331 vertexShader.addUniform("qt_normalMatrix", "mat3");
332 vertexShader.addUniform("qt_cameraProperties", "vec2");
333 }
334
335 // With multiview, qt_viewIndex (aka VIEW_INDEX) is always present.
336 // Otherwise, we still make VIEW_INDEX functional (always 0) in custom
337 // materials, if the keyword is used.
338 if (m_viewCount >= 2) {
339 addFlatParameter("qt_viewIndex", "uint");
340 vertexShader.append(" qt_viewIndex = gl_ViewIndex;");
341 } else if (usesViewIndex) {
342 addFlatParameter("qt_viewIndex", "uint");
343 vertexShader.append(" qt_viewIndex = 0;");
344 }
345
346 if (meshHasNormals) {
347 vertexShader.append(" qt_vertNormal = attr_norm;");
348 vertexShader.addIncoming("attr_norm", "vec3");
349 }
350 if (meshHasTexCoord0) {
351 vertexShader.append(" qt_vertUV0 = attr_uv0;");
352 vertexShader.addIncoming("attr_uv0", "vec2");
353 }
354 if (meshHasTexCoord1) {
355 vertexShader.append(" qt_vertUV1 = attr_uv1;");
356 vertexShader.addIncoming("attr_uv1", "vec2");
357 }
358 if (meshHasTexCoordLightmap) {
359 vertexShader.append(" vec2 qt_vertLightmapUV = attr_lightmapuv;");
360 vertexShader.addIncoming("attr_lightmapuv", "vec2");
361 }
362 if (meshHasTangents) {
363 vertexShader.append(" qt_vertTangent = attr_textan;");
364 vertexShader.addIncoming("attr_textan", "vec3");
365 }
366 if (meshHasBinormals) {
367 vertexShader.append(" qt_vertBinormal = attr_binormal;");
368 vertexShader.addIncoming("attr_binormal", "vec3");
369 }
370 if (meshHasColors) {
371 vertexShader.append(" qt_vertColor = attr_color;");
372 vertexShader.addIncoming("attr_color", "vec4");
373 }
374
375 if (meshHasJointsAndWeights && (m_hasSkinning || hasCustomVertexShader)) {
376 if (usesFloatJointIndices) {
377 vertexShader.addIncoming("attr_joints", "vec4");
378 vertexShader.append(" qt_vertJoints = ivec4(attr_joints);");
379 } else {
380 vertexShader.addIncoming("attr_joints", "ivec4");
381 vertexShader.append(" qt_vertJoints = attr_joints;");
382 }
383 vertexShader.addIncoming("attr_weights", "vec4");
384 vertexShader.append(" qt_vertWeights = attr_weights;");
385 }
386
387 if (usesInstancing) {
388 vertexShader.append(" qt_vertColor *= qt_instanceColor;");
389 vertexShader.append(" mat4 qt_instanceMatrix = mat4(qt_instanceTransform0, qt_instanceTransform1, qt_instanceTransform2, vec4(0.0, 0.0, 0.0, 1.0));");
390 if (m_hasSkinning)
391 vertexShader.append(" mat4 qt_instancedModelMatrix = qt_parentMatrix * transpose(qt_instanceMatrix);");
392 else
393 vertexShader.append(" mat4 qt_instancedModelMatrix = qt_parentMatrix * transpose(qt_instanceMatrix) * qt_modelMatrix;");
394 vertexShader.append(" mat3 qt_instancedNormalMatrix = mat3(transpose(inverse(qt_instancedModelMatrix)));");
395 if (m_viewCount < 2)
396 vertexShader.append(" mat4 qt_instancedMVPMatrix = qt_viewProjectionMatrix * qt_instancedModelMatrix;");
397 else
398 vertexShader.append(" mat4 qt_instancedMVPMatrix = qt_viewProjectionMatrix[qt_viewIndex] * qt_instancedModelMatrix;");
399 }
400
401 if (!materialAdapter->isUnshaded() || !hasCustomVertexShader) {
402 vertexShader << " vec3 qt_uTransform;\n";
403 vertexShader << " vec3 qt_vTransform;\n";
404
405 if (hasCustomShadedMain)
406 vertexShader.append(customMainCallWithArguments(usesInstancing));
407
408 if (m_hasMorphing && !hasCustomVertexShader)
409 vertexShader.append(" qt_vertPosition.xyz = qt_getTargetPosition(qt_vertPosition.xyz);");
410
411 m_needsSkinning = m_hasSkinning && !materialAdapter->usesCustomSkinning();
412 if (m_needsSkinning) {
413 vertexShader.append(" mat4 skinMat = mat4(1);");
414 vertexShader.append(" if (qt_vertWeights != vec4(0.0)) {");
415 vertexShader.append(" skinMat = qt_getSkinMatrix(qt_vertJoints, qt_vertWeights);");
416 vertexShader.append(" qt_vertPosition = skinMat * qt_vertPosition;");
417 vertexShader.append(" }");
418 }
419 if (blendParticles) {
420 vertexShader.append(" qt_vertPosition.xyz = qt_applyParticle(qt_vertPosition.xyz, qt_vertNormal, qt_vertColor, qt_vertNormal, qt_vertColor, qt_particleMatrix);");
421 }
422
423 if (!hasCustomShadedMain || !overridesPosition) {
424 if (!usesInstancing) {
425 if (m_viewCount < 2)
426 vertexShader.append(" gl_Position = qt_modelViewProjection * qt_vertPosition;");
427 else
428 vertexShader.append(" gl_Position = qt_modelViewProjection[qt_viewIndex] * qt_vertPosition;");
429 } else {
430 vertexShader.append(" gl_Position = qt_instancedMVPMatrix * qt_vertPosition;");
431 }
432 }
433 }
434
435 if (usesPointsTopology && !hasCustomVertexShader) {
436 vertexShader.addUniform("qt_materialPointSize", "float");
437 vertexShader.append(" gl_PointSize = qt_materialPointSize;");
438 } // with a custom vertex shader it is up to it to set gl_PointSize (aka POINT_SIZE)
439}
440
441void QSSGMaterialVertexPipeline::beginFragmentGeneration(QSSGShaderLibraryManager &shaderLibraryManager, QSSGRenderLayer::OITMethod oitMethod)
442{
443 fragment().addUniform("qt_material_properties", "vec4");
444 fragment().addUniform("qt_rhi_properties", "vec4");
445
446 if (m_viewCount < 2) {
447 fragment().addUniform("qt_viewMatrix", "mat4");
448 } else {
449 fragment().addUniformArray("qt_viewMatrix", "mat4", m_viewCount);
450 }
451
452 if (!skipCustomFragmentSnippet && materialAdapter->hasCustomShaderSnippet(QSSGShaderCache::ShaderType::Fragment)) {
453 QByteArray snippet = materialAdapter->customShaderSnippet(QSSGShaderCache::ShaderType::Fragment,
454 shaderLibraryManager,
455 m_viewCount >= 2);
456 if (!materialAdapter->isUnshaded()) {
457 insertAmbientLightProcessorArgs(snippet, materialAdapter);
458 insertIblProbeProcessorArgs(snippet, materialAdapter);
459 insertSpecularLightProcessorArgs(snippet, materialAdapter);
460 insertSpotLightProcessorArgs(snippet, materialAdapter);
461 insertPointLightProcessorArgs(snippet, materialAdapter);
462 insertDirectionalLightProcessorArgs(snippet, materialAdapter);
463 insertFragmentMainArgs(snippet, materialAdapter);
464 insertPostProcessorArgs(snippet, materialAdapter);
465 auto sharedVars = extractSharedVarsTypeDefinition(snippet, materialAdapter);
466 fragment().addTypeDeclaration("QT_SHARED_VARS", sharedVars);
467 }
468 fragment() << snippet;
469 }
470
471 if (oitMethod != QSSGRenderLayer::OITMethod::None) {
472 if (oitMethod == QSSGRenderLayer::OITMethod::LinkedList) {
473 // Early tests are required since we can't undo modifications to
474 // the image data structures after running the fragment shader.
475 // Modifying depth in fragment shader is not possible then.
476 fragment() << "layout(early_fragment_tests) in;" << "\n";
477 }
478 if (oitMethod == QSSGRenderLayer::OITMethod::WeightedBlended) {
479 fragment().addDefinition("QSSG_OIT_METHOD", "QSSG_OIT_WEIGHTED_BLENDED");
480 fragment() << "layout(location = 1) out vec4 revealageOutput;" << "\n";
481 } else if (oitMethod == QSSGRenderLayer::OITMethod::LinkedList) {
482 fragment() << "#extension GL_ARB_shading_language_packing : enable" << "\n";
483 fragment().addDefinition("QSSG_OIT_METHOD", "QSSG_OIT_LINKED_LIST");
484 }
485 }
486 fragment() << "void main()"
487 << "\n"
488 << "{"
489 << "\n";
490
491 if (!materialAdapter->isUnshaded() || !materialAdapter->hasCustomShaderSnippet(QSSGShaderCache::ShaderType::Fragment))
492 fragment() << " float qt_objectOpacity = qt_material_properties.a;\n";
493}
494
495void QSSGMaterialVertexPipeline::assignOutput(const QByteArray &inVarName, const QByteArray &inVarValue)
496{
497 vertex() << " " << inVarName << " = " << inVarValue << ";\n";
498}
499
500void QSSGMaterialVertexPipeline::doGenerateWorldNormal(const QSSGShaderDefaultMaterialKey &inKey)
501{
502 QSSGStageGeneratorBase &vertexGenerator(vertex());
503 const bool usesInstancing = defaultMaterialShaderKeyProperties.m_usesInstancing.getValue(inKey);
504 if (!usesInstancing)
505 vertexGenerator.addUniform("qt_normalMatrix", "mat3");
506 if (m_hasMorphing)
507 vertexGenerator.append(" qt_vertNormal = qt_getTargetNormal(qt_vertNormal);");
508 if (m_hasSkinning) {
509 vertexGenerator.append(" if (qt_vertWeights != vec4(0.0))");
510 vertexGenerator.append(" qt_vertNormal = qt_getSkinNormalMatrix(qt_vertJoints, qt_vertWeights) * qt_vertNormal;");
511 }
512 // If new model->skin is used,
513 // both qt_normalMatrix and qt_modelMatrix are identity.
514 if (!usesInstancing) {
515 if (m_hasSkinning)
516 vertexGenerator.append(" vec3 qt_world_normal = normalize(qt_vertNormal);");
517 else
518 vertexGenerator.append(" vec3 qt_world_normal = normalize(qt_normalMatrix * qt_vertNormal);");
519 } else {
520 vertexGenerator.append(" vec3 qt_world_normal = normalize(qt_instancedNormalMatrix * qt_vertNormal);");
521 }
522 vertexGenerator.append(" qt_varNormal = qt_world_normal;");
523}
524
525void QSSGMaterialVertexPipeline::doGenerateVarTangent(const QSSGShaderDefaultMaterialKey &inKey)
526{
527 if (m_hasMorphing)
528 vertex() << " qt_vertTangent = qt_getTargetTangent(qt_vertTangent);\n";
529 if (m_needsSkinning) {
530 vertex() << " if (qt_vertWeights != vec4(0.0))\n"
531 << " qt_vertTangent = (skinMat * vec4(qt_vertTangent, 0.0)).xyz;\n";
532
533 }
534 const bool usesInstancing = defaultMaterialShaderKeyProperties.m_usesInstancing.getValue(inKey);
535 if (!usesInstancing) {
536 if (!m_hasSkinning)
537 vertex() << " qt_varTangent = (qt_modelMatrix * vec4(qt_vertTangent, 0.0)).xyz;\n";
538 else
539 vertex() << " qt_varTangent = qt_vertTangent;\n";
540 } else {
541 vertex() << " qt_varTangent = (qt_instancedModelMatrix * vec4(qt_vertTangent, 0.0)).xyz;\n";
542 }
543}
544
545void QSSGMaterialVertexPipeline::doGenerateVarBinormal(const QSSGShaderDefaultMaterialKey &inKey)
546{
547 if (m_hasMorphing)
548 vertex() << " qt_vertBinormal = qt_getTargetBinormal(qt_vertBinormal);\n";
549 if (m_needsSkinning) {
550 vertex() << " if (qt_vertWeights != vec4(0.0))\n"
551 << " qt_vertBinormal = (skinMat * vec4(qt_vertBinormal, 0.0)).xyz;\n";
552 }
553 const bool usesInstancing = defaultMaterialShaderKeyProperties.m_usesInstancing.getValue(inKey);
554 if (!usesInstancing) {
555 if (!m_hasSkinning)
556 vertex() << " qt_varBinormal = (qt_modelMatrix * vec4(qt_vertBinormal, 0.0)).xyz;\n";
557 else
558 vertex() << " qt_varBinormal = qt_vertBinormal;\n";
559 } else {
560 vertex() << " qt_varBinormal = (qt_instancedModelMatrix * vec4(qt_vertBinormal, 0.0)).xyz;\n";
561 }
562}
563
564bool QSSGMaterialVertexPipeline::hasAttributeInKey(QSSGShaderKeyVertexAttribute::VertexAttributeBits inAttr,
565 const QSSGShaderDefaultMaterialKey &inKey)
566{
567 return defaultMaterialShaderKeyProperties.m_vertexAttributes.getBitValue(inAttr, inKey);
568}
569
570void QSSGMaterialVertexPipeline::endVertexGeneration()
571{
572 if (materialAdapter->isUnshaded() && materialAdapter->hasCustomShaderSnippet(QSSGShaderCache::ShaderType::Vertex))
573 vertex() << customMainCallWithArguments(usesInstancing);
574 vertex().append("}");
575}
576
577void QSSGMaterialVertexPipeline::endFragmentGeneration()
578{
579 if (!skipCustomFragmentSnippet && materialAdapter->isUnshaded() && materialAdapter->hasCustomShaderSnippet(QSSGShaderCache::ShaderType::Fragment))
580 fragment() << " qt_customMain();\n";
581
582 fragment().append("}");
583}
584
585void QSSGMaterialVertexPipeline::addInterpolationParameter(const QByteArray &inName, const QByteArray &inType)
586{
587 vertex().addOutgoing(inName, inType);
588 fragment().addIncoming(inName, inType);
589}
590
591void QSSGMaterialVertexPipeline::addFlatParameter(const QByteArray &inName, const QByteArray &inType)
592{
593 vertex().addFlatOutgoing(inName, inType);
594 fragment().addFlatIncoming(inName, inType);
595}
596
597QSSGStageGeneratorBase &QSSGMaterialVertexPipeline::activeStage()
598{
599 return vertex();
600}
601
602QT_END_NAMESPACE
Combined button and popup list for selecting options.
static void insertDirectionalLightProcessorArgs(QByteArray &snippet, QSSGShaderMaterialAdapter *materialAdapter)
static void insertSpecularLightProcessorArgs(QByteArray &snippet, QSSGShaderMaterialAdapter *materialAdapter)
static void insertFragmentMainArgs(QByteArray &snippet, QSSGShaderMaterialAdapter *materialAdapter)
static const char * customMainCallWithArguments(bool usesInstancing)
static void insertProcessorArgs(QByteArray &snippet, const char *argKey, const char *(*argListFunc)(), QSSGShaderMaterialAdapter *materialAdapter=nullptr, bool isSharedInout=false)
static void insertPostProcessorArgs(QByteArray &snippet, QSSGShaderMaterialAdapter *materialAdapter)
static void insertIblProbeProcessorArgs(QByteArray &snippet, QSSGShaderMaterialAdapter *materialAdapter)
static void insertAmbientLightProcessorArgs(QByteArray &snippet, QSSGShaderMaterialAdapter *materialAdapter)
static void insertVertexInstancedMainArgs(QByteArray &snippet)
static void insertVertexMainArgs(QByteArray &snippet)
static void insertSpotLightProcessorArgs(QByteArray &snippet, QSSGShaderMaterialAdapter *materialAdapter)
static QByteArray extractSharedVarsTypeDefinition(QByteArray &snippet, QSSGShaderMaterialAdapter *materialAdapter)
static void insertProcessorArgsFragmentMain(QByteArray &snippet, const char *argKey, const char *(*argListFunc)(), QSSGShaderMaterialAdapter *materialAdapter=nullptr, bool isSharedInout=false)
static void insertPointLightProcessorArgs(QByteArray &snippet, QSSGShaderMaterialAdapter *materialAdapter)