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

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