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

Provided by KDAB

Privacy Policy
Learn to use CMake with our Intro Training
Find out more

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