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

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