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