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 | |
16 | QT_BEGIN_NAMESPACE |
17 | |
18 | QSSGMaterialVertexPipeline::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 | |
29 | static 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 | |
55 | static 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 | |
70 | static inline void insertDirectionalLightProcessorArgs(QByteArray &snippet, QSSGShaderMaterialAdapter *materialAdapter) |
71 | { |
72 | insertProcessorArgs(snippet, argKey: "/*%QT_ARGS_DIRECTIONAL_LIGHT%*/", argListFunc: QSSGMaterialShaderGenerator::directionalLightProcessorArgumentList, materialAdapter, isSharedInout: true); |
73 | } |
74 | |
75 | static inline void insertPointLightProcessorArgs(QByteArray &snippet, QSSGShaderMaterialAdapter *materialAdapter) |
76 | { |
77 | insertProcessorArgs(snippet, argKey: "/*%QT_ARGS_POINT_LIGHT%*/", argListFunc: QSSGMaterialShaderGenerator::pointLightProcessorArgumentList, materialAdapter, isSharedInout: true); |
78 | } |
79 | |
80 | static inline void insertSpotLightProcessorArgs(QByteArray &snippet, QSSGShaderMaterialAdapter *materialAdapter) |
81 | { |
82 | insertProcessorArgs(snippet, argKey: "/*%QT_ARGS_SPOT_LIGHT%*/", argListFunc: QSSGMaterialShaderGenerator::spotLightProcessorArgumentList, materialAdapter, isSharedInout: true); |
83 | } |
84 | |
85 | static inline void insertAmbientLightProcessorArgs(QByteArray &snippet, QSSGShaderMaterialAdapter *materialAdapter) |
86 | { |
87 | insertProcessorArgs(snippet, argKey: "/*%QT_ARGS_AMBIENT_LIGHT%*/", argListFunc: QSSGMaterialShaderGenerator::ambientLightProcessorArgumentList, materialAdapter, isSharedInout: true); |
88 | } |
89 | |
90 | static inline void insertIblProbeProcessorArgs(QByteArray &snippet, QSSGShaderMaterialAdapter *materialAdapter) |
91 | { |
92 | insertProcessorArgs(snippet, argKey: "/*%QT_ARGS_IBL_PROBE%*/", argListFunc: QSSGMaterialShaderGenerator::iblProbeProcessorArgumentList, materialAdapter, isSharedInout: true); |
93 | } |
94 | |
95 | static inline void insertSpecularLightProcessorArgs(QByteArray &snippet, QSSGShaderMaterialAdapter *materialAdapter) |
96 | { |
97 | insertProcessorArgs(snippet, argKey: "/*%QT_ARGS_SPECULAR_LIGHT%*/", argListFunc: QSSGMaterialShaderGenerator::specularLightProcessorArgumentList, materialAdapter, isSharedInout: true); |
98 | } |
99 | |
100 | static inline void insertFragmentMainArgs(QByteArray &snippet, QSSGShaderMaterialAdapter *materialAdapter) |
101 | { |
102 | insertProcessorArgsFragmentMain(snippet, argKey: "/*%QT_ARGS_MAIN%*/", argListFunc: QSSGMaterialShaderGenerator::shadedFragmentMainArgumentList, materialAdapter, isSharedInout: true); |
103 | } |
104 | |
105 | static inline void insertPostProcessorArgs(QByteArray &snippet, QSSGShaderMaterialAdapter *materialAdapter) |
106 | { |
107 | insertProcessorArgs(snippet, argKey: "/*%QT_ARGS_POST_PROCESS%*/", argListFunc: QSSGMaterialShaderGenerator::postProcessorArgumentList, materialAdapter, isSharedInout: false); |
108 | } |
109 | |
110 | static inline void insertVertexMainArgs(QByteArray &snippet) |
111 | { |
112 | insertProcessorArgs(snippet, argKey: "/*%QT_ARGS_MAIN%*/", argListFunc: QSSGMaterialShaderGenerator::vertexMainArgumentList); |
113 | } |
114 | |
115 | static inline void insertVertexInstancedMainArgs(QByteArray &snippet) |
116 | { |
117 | insertProcessorArgs(snippet, argKey: "/*%QT_ARGS_MAIN%*/", argListFunc: QSSGMaterialShaderGenerator::vertexInstancedMainArgumentList); |
118 | } |
119 | |
120 | static 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 | |
128 | void 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 | |
415 | void 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 | |
452 | void QSSGMaterialVertexPipeline::assignOutput(const QByteArray &inVarName, const QByteArray &inVarValue) |
453 | { |
454 | vertex() << " "<< inVarName << " = "<< inVarValue << ";\n"; |
455 | } |
456 | |
457 | void 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 | |
482 | void 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 | |
502 | void 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 | |
521 | bool QSSGMaterialVertexPipeline::hasAttributeInKey(QSSGShaderKeyVertexAttribute::VertexAttributeBits inAttr, |
522 | const QSSGShaderDefaultMaterialKey &inKey) |
523 | { |
524 | return defaultMaterialShaderKeyProperties.m_vertexAttributes.getBitValue(bit: inAttr, inKeySet: inKey); |
525 | } |
526 | |
527 | void QSSGMaterialVertexPipeline::endVertexGeneration() |
528 | { |
529 | if (materialAdapter->isUnshaded() && materialAdapter->hasCustomShaderSnippet(type: QSSGShaderCache::ShaderType::Vertex)) |
530 | vertex() << customMainCallWithArguments(usesInstancing); |
531 | vertex().append(data: "}"); |
532 | } |
533 | |
534 | void 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 | |
542 | void 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 | |
548 | void 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 | |
554 | QSSGStageGeneratorBase &QSSGMaterialVertexPipeline::activeStage() |
555 | { |
556 | return vertex(); |
557 | } |
558 | |
559 | QT_END_NAMESPACE |
560 |
Definitions
- QSSGMaterialVertexPipeline
- insertProcessorArgsFragmentMain
- insertProcessorArgs
- insertDirectionalLightProcessorArgs
- insertPointLightProcessorArgs
- insertSpotLightProcessorArgs
- insertAmbientLightProcessorArgs
- insertIblProbeProcessorArgs
- insertSpecularLightProcessorArgs
- insertFragmentMainArgs
- insertPostProcessorArgs
- insertVertexMainArgs
- insertVertexInstancedMainArgs
- customMainCallWithArguments
- beginVertexGeneration
- beginFragmentGeneration
- assignOutput
- doGenerateWorldNormal
- doGenerateVarTangent
- doGenerateVarBinormal
- hasAttributeInKey
- endVertexGeneration
- endFragmentGeneration
- addInterpolationParameter
- addFlatParameter
Learn to use CMake with our Intro Training
Find out more