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 | |
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 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 | |
43 | static inline void insertDirectionalLightProcessorArgs(QByteArray &snippet, bool usesShared) |
44 | { |
45 | insertProcessorArgs(snippet, argKey: "/*%QT_ARGS_DIRECTIONAL_LIGHT%*/" , argListFunc: QSSGMaterialShaderGenerator::directionalLightProcessorArgumentList, usesShared, isSharedInout: true); |
46 | } |
47 | |
48 | static inline void insertPointLightProcessorArgs(QByteArray &snippet, bool usesShared) |
49 | { |
50 | insertProcessorArgs(snippet, argKey: "/*%QT_ARGS_POINT_LIGHT%*/" , argListFunc: QSSGMaterialShaderGenerator::pointLightProcessorArgumentList, usesShared, isSharedInout: true); |
51 | } |
52 | |
53 | static inline void insertSpotLightProcessorArgs(QByteArray &snippet, bool usesShared) |
54 | { |
55 | insertProcessorArgs(snippet, argKey: "/*%QT_ARGS_SPOT_LIGHT%*/" , argListFunc: QSSGMaterialShaderGenerator::spotLightProcessorArgumentList, usesShared, isSharedInout: true); |
56 | } |
57 | |
58 | static inline void insertAmbientLightProcessorArgs(QByteArray &snippet, bool usesShared) |
59 | { |
60 | insertProcessorArgs(snippet, argKey: "/*%QT_ARGS_AMBIENT_LIGHT%*/" , argListFunc: QSSGMaterialShaderGenerator::ambientLightProcessorArgumentList, usesShared, isSharedInout: true); |
61 | } |
62 | |
63 | static inline void insertIblProbeProcessorArgs(QByteArray &snippet, bool usesShared) |
64 | { |
65 | insertProcessorArgs(snippet, argKey: "/*%QT_ARGS_IBL_PROBE%*/" , argListFunc: QSSGMaterialShaderGenerator::iblProbeProcessorArgumentList, usesShared, isSharedInout: true); |
66 | } |
67 | |
68 | static inline void insertSpecularLightProcessorArgs(QByteArray &snippet, bool usesShared) |
69 | { |
70 | insertProcessorArgs(snippet, argKey: "/*%QT_ARGS_SPECULAR_LIGHT%*/" , argListFunc: QSSGMaterialShaderGenerator::specularLightProcessorArgumentList, usesShared, isSharedInout: true); |
71 | } |
72 | |
73 | static inline void insertFragmentMainArgs(QByteArray &snippet, bool usesShared = false) |
74 | { |
75 | insertProcessorArgs(snippet, argKey: "/*%QT_ARGS_MAIN%*/" , argListFunc: QSSGMaterialShaderGenerator::shadedFragmentMainArgumentList, usesShared, isSharedInout: true); |
76 | } |
77 | |
78 | static inline void insertPostProcessorArgs(QByteArray &snippet, bool usesShared) |
79 | { |
80 | insertProcessorArgs(snippet, argKey: "/*%QT_ARGS_POST_PROCESS%*/" , argListFunc: QSSGMaterialShaderGenerator::postProcessorArgumentList, usesShared, isSharedInout: false); |
81 | } |
82 | |
83 | static inline void insertVertexMainArgs(QByteArray &snippet) |
84 | { |
85 | insertProcessorArgs(snippet, argKey: "/*%QT_ARGS_MAIN%*/" , argListFunc: QSSGMaterialShaderGenerator::vertexMainArgumentList); |
86 | } |
87 | |
88 | static inline void insertVertexInstancedMainArgs(QByteArray &snippet) |
89 | { |
90 | insertProcessorArgs(snippet, argKey: "/*%QT_ARGS_MAIN%*/" , argListFunc: QSSGMaterialShaderGenerator::vertexInstancedMainArgumentList); |
91 | } |
92 | |
93 | static 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 | |
101 | void 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 | |
349 | void 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 | |
380 | void QSSGMaterialVertexPipeline::assignOutput(const QByteArray &inVarName, const QByteArray &inVarValue) |
381 | { |
382 | vertex() << " " << inVarName << " = " << inVarValue << ";\n" ; |
383 | } |
384 | |
385 | void 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 | |
410 | void 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 | |
430 | void 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 | |
449 | bool QSSGMaterialVertexPipeline::hasAttributeInKey(QSSGShaderKeyVertexAttribute::VertexAttributeBits inAttr, |
450 | const QSSGShaderDefaultMaterialKey &inKey) |
451 | { |
452 | return defaultMaterialShaderKeyProperties.m_vertexAttributes.getBitValue(bit: inAttr, inKeySet: inKey); |
453 | } |
454 | |
455 | void QSSGMaterialVertexPipeline::endVertexGeneration() |
456 | { |
457 | if (materialAdapter->isUnshaded() && materialAdapter->hasCustomShaderSnippet(type: QSSGShaderCache::ShaderType::Vertex)) |
458 | vertex() << customMainCallWithArguments(usesInstancing); |
459 | vertex().append(data: "}" ); |
460 | } |
461 | |
462 | void 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 | |
470 | void 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 | |
477 | QSSGStageGeneratorBase &QSSGMaterialVertexPipeline::activeStage() |
478 | { |
479 | return vertex(); |
480 | } |
481 | |
482 | QT_END_NAMESPACE |
483 | |