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

source code of qtquick3d/src/runtimerender/rendererimpl/qssgvertexpipelineimpl.cpp