Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qssgvertexpipelineimpl_p.h
Go to the documentation of this file.
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// Qt-Security score:significant reason:default
5
6
7#ifndef QSSG_VERTEX_PIPELINE_IMPL_H
8#define QSSG_VERTEX_PIPELINE_IMPL_H
9
10//
11// W A R N I N G
12// -------------
13//
14// This file is not part of the Qt API. It exists purely as an
15// implementation detail. This header file may change from version to
16// version without notice, or even be removed.
17//
18// We mean it.
19//
20
21#include <QtQuick3DRuntimeRender/private/qssgrenderdefaultmaterialshadergenerator_p.h>
22#include <QtQuick3DRuntimeRender/private/qssgrendershaderkeys_p.h>
23
24#include <QtCore/QSharedPointer>
25
26QT_BEGIN_NAMESPACE
27
28struct QSSGMaterialVertexPipeline
29{
30 enum class GenerationFlag
31 {
32 UVCoords = 1,
33 EnvMapReflection = 1 << 1,
34 ViewVector = 1 << 2,
35 WorldNormal = 1 << 3,
36 ObjectNormal = 1 << 4,
37 WorldPosition = 1 << 5,
38 TangentBinormal = 1 << 6,
39 UVCoords1 = 1 << 7,
40 VertexColor = 1 << 8,
41 PerspDivDepth = 1 << 9,
42 PerspDivWorldPos = 1 << 10
43 };
44
45 typedef QHash<QByteArray, QByteArray> TStrTableStrMap;
46 typedef TStrTableStrMap::const_iterator TParamIter;
47 typedef QFlags<GenerationFlag> GenerationFlags;
48
49 QSSGProgramGenerator *m_programGenerator = nullptr;
50 QString m_tempString;
51
52 GenerationFlags m_generationFlags;
53 bool m_hasSkinning;
54 bool m_needsSkinning;
55 bool m_hasMorphing;
56 QList<QByteArray> m_addedFunctions;
57 int m_viewCount = 1;
58
59 const QSSGShaderDefaultMaterialKeyProperties &defaultMaterialShaderKeyProperties;
60 QSSGShaderMaterialAdapter *materialAdapter;
61 bool useFloatJointIndices;
62 bool hasCustomShadedMain;
63 bool usesInstancing;
64 bool skipCustomFragmentSnippet;
65
66 QSSGMaterialVertexPipeline(QSSGProgramGenerator &inProgram,
67 const QSSGShaderDefaultMaterialKeyProperties &materialProperties,
68 QSSGShaderMaterialAdapter *materialAdapter);
69
70 ~QSSGMaterialVertexPipeline() = default;
71
72 // Trues true if the code was *not* set.
73 bool setCode(GenerationFlag inCode)
74 {
75 if (m_generationFlags & inCode)
76 return true;
77 m_generationFlags |= inCode;
78 return false;
79 }
80 bool hasCode(GenerationFlag inCode) { return (m_generationFlags & inCode); }
81 QSSGProgramGenerator *programGenerator() const { return m_programGenerator; }
82
83 QSSGStageGeneratorBase &vertex()
84 {
85 return *programGenerator()->getStage(QSSGShaderGeneratorStage::Vertex);
86 }
87 QSSGStageGeneratorBase &fragment()
88 {
89 return *programGenerator()->getStage(QSSGShaderGeneratorStage::Fragment);
90 }
91
92 /**
93 * @brief Generates UV coordinates in shader code
94 *
95 * @param[in] inUVSet index of UV data set
96 *
97 * @return no return
98 */
99 void generateUVCoords(quint32 inUVSet, const QSSGShaderDefaultMaterialKey &inKey)
100 {
101 if (inUVSet == 0 && setCode(GenerationFlag::UVCoords))
102 return;
103 if (inUVSet == 1 && setCode(GenerationFlag::UVCoords1))
104 return;
105
106 const bool meshHasUV0 = hasAttributeInKey(QSSGShaderKeyVertexAttribute::TexCoord0, inKey);
107 const bool meshHasUV1 = hasAttributeInKey(QSSGShaderKeyVertexAttribute::TexCoord1, inKey);
108
109 Q_ASSERT(inUVSet == 0 || inUVSet == 1);
110
111 if (inUVSet == 0) {
112 if (hasCustomShadedMain || meshHasUV0) {
113 addInterpolationParameter("qt_varTexCoord0", "vec2");
114 if (m_hasMorphing)
115 vertex().append(" qt_vertUV0 = qt_getTargetTex0(qt_vertUV0);");
116 vertex() << " qt_varTexCoord0 = qt_vertUV0;\n";
117 fragment() <<" vec2 qt_texCoord0 = qt_varTexCoord0;\n";
118 } else {
119 vertex() << " vec2 qt_varTexCoord0 = vec2(0.0);\n";
120 fragment() << " vec2 qt_texCoord0 = vec2(0.0);\n";
121 }
122 } else if (inUVSet == 1) {
123 if (hasCustomShadedMain || meshHasUV1) {
124 addInterpolationParameter("qt_varTexCoord1", "vec2");
125 if (m_hasMorphing)
126 vertex().append(" qt_vertUV1 = qt_getTargetTex0(qt_vertUV1);");
127 vertex() << " qt_varTexCoord1 = qt_vertUV1;\n";
128 fragment() <<" vec2 qt_texCoord1 = qt_varTexCoord1;\n";
129 } else {
130 vertex() << " vec2 qt_varTexCoord1 = vec2(0.0);\n";
131 fragment() << " vec2 qt_texCoord1 = vec2(0.0);\n";
132 }
133 }
134 }
135
136 void generateLightmapUVCoords(const QSSGShaderDefaultMaterialKey &inKey)
137 {
138 if (hasAttributeInKey(QSSGShaderKeyVertexAttribute::TexCoordLightmap, inKey)) {
139 addInterpolationParameter("qt_varTexCoordLightmap", "vec2");
140 vertex() << " qt_varTexCoordLightmap = qt_vertLightmapUV;\n";
141 fragment() <<" vec2 qt_texCoordLightmap = qt_varTexCoordLightmap;\n";
142 } else {
143 vertex() << " vec2 qt_varTexCoordLightmap = vec2(0.0);\n";
144 fragment() << " vec2 qt_texCoordLightmap = vec2(0.0);\n";
145 }
146 }
147
148 void generateEnvMapReflection(const QSSGShaderDefaultMaterialKey &inKey)
149 {
150 if (setCode(GenerationFlag::EnvMapReflection))
151 return;
152
153 generateWorldPosition(inKey);
154 generateWorldNormal(inKey);
155 QSSGStageGeneratorBase &activeGenerator(activeStage());
156 addInterpolationParameter("qt_var_object_to_camera", "vec3");
157
158 if (m_viewCount < 2) {
159 activeGenerator.addUniform("qt_cameraPosition", "vec3");
160 activeGenerator.append(" qt_var_object_to_camera = normalize( qt_local_model_world_position - qt_cameraPosition );");
161 } else {
162 activeGenerator.addUniformArray("qt_cameraPosition", "vec3", m_viewCount);
163 activeGenerator.append(" qt_var_object_to_camera = normalize( qt_local_model_world_position - qt_cameraPosition[qt_viewIndex] );");
164 }
165
166 // World normal cannot be relied upon in the vertex shader because of bump maps.
167 fragment().append(" vec3 environment_map_reflection = reflect( "
168 "normalize(qt_var_object_to_camera), qt_world_normal.xyz );");
169 fragment().append(" environment_map_reflection *= vec3( 0.5, 0.5, 0 );");
170 fragment().append(" environment_map_reflection += vec3( 0.5, 0.5, 1.0 );");
171 }
172
173 void generateViewVector(const QSSGShaderDefaultMaterialKey &inKey)
174 {
175 if (setCode(GenerationFlag::ViewVector))
176 return;
177
178 generateWorldPosition(inKey);
179
180 if (m_viewCount < 2) {
181 activeStage().addUniform("qt_cameraPosition", "vec3");
182 fragment() << " vec3 qt_view_vector = normalize(qt_cameraPosition - qt_varWorldPos);\n";
183 } else {
184 activeStage().addUniformArray("qt_cameraPosition", "vec3", m_viewCount);
185 fragment() << " vec3 qt_view_vector = normalize(qt_cameraPosition[qt_viewIndex] - qt_varWorldPos);\n";
186 }
187 }
188
189 // fragment shader expects varying vertex normal
190 // lighting in vertex pipeline expects qt_world_normal
191
192 // qt_world_normal in both vert and frag shader
193 void generateWorldNormal(const QSSGShaderDefaultMaterialKey &inKey)
194 {
195 if (setCode(GenerationFlag::WorldNormal))
196 return;
197
198 const bool meshHasNormal = hasAttributeInKey(QSSGShaderKeyVertexAttribute::Normal, inKey);
199
200 if (hasCustomShadedMain || meshHasNormal) {
201 addInterpolationParameter("qt_varNormal", "vec3");
202 doGenerateWorldNormal(inKey);
203 } else {
204 generateWorldPosition(inKey);
205 // qt_rhi_properties.x is used to correct for Y inversion for non OpenGL backends
206 fragment().append(" vec3 qt_varNormal = cross(dFdx(qt_varWorldPos), qt_rhi_properties.x * dFdy(qt_varWorldPos));");
207 }
208 fragment().append(" vec3 qt_world_normal = normalize(qt_varNormal);");
209 }
210
211 void generateObjectNormal()
212 {
213 if (setCode(GenerationFlag::ObjectNormal))
214 return;
215
216 addInterpolationParameter("qt_varObjectNormal", "vec3");
217 vertex().append(" qt_varObjectNormal = qt_vertNormal;");
218 fragment().append(" vec3 object_normal = normalize(qt_varObjectNormal);");
219 }
220
221 void generateWorldPosition(const QSSGShaderDefaultMaterialKey &inKey)
222 {
223 if (setCode(GenerationFlag::WorldPosition))
224 return;
225
226 activeStage().addUniform("qt_modelMatrix", "mat4");
227 addInterpolationParameter("qt_varWorldPos", "vec3");
228 const bool usesInstancing = defaultMaterialShaderKeyProperties.m_usesInstancing.getValue(inKey);
229 if (!usesInstancing) {
230 if (m_hasSkinning)
231 vertex().append(" vec3 qt_local_model_world_position = qt_vertPosition.xyz;");
232 else
233 vertex().append(" vec3 qt_local_model_world_position = (qt_modelMatrix * qt_vertPosition).xyz;");
234 } else {
235 vertex().append(" vec3 qt_local_model_world_position = (qt_instancedModelMatrix * qt_vertPosition).xyz;");
236 }
237
238 assignOutput("qt_varWorldPos", "qt_local_model_world_position");
239 }
240
241 void generateDepth()
242 {
243 if (setCode(GenerationFlag::PerspDivDepth))
244 return;
245
246 addInterpolationParameter("qt_varDepth", "float");
247 vertex().append(" qt_varDepth = gl_Position.z / gl_Position.w;");
248 }
249
250 void generateShadowWorldPosition(const QSSGShaderDefaultMaterialKey &inKey)
251 {
252 if (setCode(GenerationFlag::PerspDivWorldPos))
253 return;
254
255 activeStage().addUniform("qt_modelMatrix", "mat4");
256 addInterpolationParameter("qt_varShadowWorldPos", "vec3");
257
258 const bool usesInstancing = defaultMaterialShaderKeyProperties.m_usesInstancing.getValue(inKey);
259 if (!usesInstancing) {
260 if (m_hasSkinning)
261 vertex().append(" vec4 qt_shadow_world_tmp = qt_vertPosition;");
262 else
263 vertex().append(" vec4 qt_shadow_world_tmp = qt_modelMatrix * qt_vertPosition;");
264 } else {
265 vertex().append(" vec4 qt_shadow_world_tmp = qt_instancedModelMatrix * qt_vertPosition;");
266 }
267 vertex().append(" qt_varShadowWorldPos = qt_shadow_world_tmp.xyz / qt_shadow_world_tmp.w;");
268 }
269
270 void generateVarTangentAndBinormal(const QSSGShaderDefaultMaterialKey &inKey, bool &genTangent, bool &genBinormal)
271 {
272 if (setCode(GenerationFlag::TangentBinormal))
273 return;
274
275 const bool meshHasTangent = hasAttributeInKey(QSSGShaderKeyVertexAttribute::Tangent, inKey);
276 const bool meshHasBinormal = hasAttributeInKey(QSSGShaderKeyVertexAttribute::Binormal, inKey);
277
278 // I assume that there is no mesh having only binormal without tangent
279 // since it is an abnormal case
280 if (hasCustomShadedMain || meshHasTangent) {
281 addInterpolationParameter("qt_varTangent", "vec3");
282 doGenerateVarTangent(inKey);
283 fragment() << " vec3 qt_tangent = normalize(qt_varTangent);\n";
284
285 if (hasCustomShadedMain || meshHasBinormal) {
286 addInterpolationParameter("qt_varBinormal", "vec3");
287 doGenerateVarBinormal(inKey);
288 fragment() << " vec3 qt_binormal = normalize(qt_varBinormal);\n";
289 genBinormal = true;
290 } else {
291 fragment() << " vec3 qt_binormal = vec3(0.0);\n";
292 }
293 genTangent = true;
294 } else {
295 fragment() << " vec3 qt_tangent = vec3(0.0);\n"
296 << " vec3 qt_binormal = vec3(0.0);\n";
297 }
298 }
299 void generateVertexColor(const QSSGShaderDefaultMaterialKey &inKey)
300 {
301 if (setCode(GenerationFlag::VertexColor))
302 return;
303
304 const bool meshHasColor = hasAttributeInKey(QSSGShaderKeyVertexAttribute::Color, inKey);
305
306 const bool vColorEnabled = defaultMaterialShaderKeyProperties.m_vertexColorsEnabled.getValue(inKey);
307 const bool vColorMaskEnabled = defaultMaterialShaderKeyProperties.m_vertexColorsMaskEnabled.getValue(inKey);
308 const bool usesVarColor = defaultMaterialShaderKeyProperties.m_usesVarColor.getValue(inKey);
309 const bool usesInstancing = defaultMaterialShaderKeyProperties.m_usesInstancing.getValue(inKey);
310 const bool usesBlendParticles = defaultMaterialShaderKeyProperties.m_blendParticles.getValue(inKey);
311
312 const bool vertexColorsEnabled = (vColorEnabled && meshHasColor) || usesInstancing || usesBlendParticles || usesVarColor;
313 const bool vertexColorsMaskEnabled = (vColorMaskEnabled && meshHasColor);
314
315 if (vertexColorsEnabled || vertexColorsMaskEnabled) {
316 addInterpolationParameter("qt_varColor", "vec4");
317 if (m_hasMorphing)
318 vertex().append(" qt_vertColor = qt_getTargetColor(qt_vertColor);");
319 vertex().append(" qt_varColor = qt_vertColor;");
320
321 fragment().append(" vec4 qt_vertColorMask = qt_varColor;\n");
322 if (vertexColorsEnabled)
323 fragment().append(" vec4 qt_vertColor = qt_varColor;\n");
324 else
325 fragment().append(" vec4 qt_vertColor = vec4(1.0);\n");
326 }else {
327 fragment().append(" vec4 qt_vertColorMask = vec4(1.0);\n");
328 fragment().append(" vec4 qt_vertColor = vec4(1.0);\n"); // must be 1,1,1,1 to not alter when multiplying with it
329 }
330 }
331
332 void addIncoming(const QByteArray &name, const QByteArray &type) { activeStage().addIncoming(name, type); }
333
334 void addOutgoing(const QByteArray &name, const QByteArray &type) { addInterpolationParameter(name, type); }
335
336 void addUniform(const QByteArray &name, const QByteArray &type) { activeStage().addUniform(name, type); }
337
338 void addUniformArray(const QByteArray &name, const QByteArray &type, quint32 size) { activeStage().addUniformArray(name, type, size); }
339
340 void addInclude(const QByteArray &name) { activeStage().addInclude(name); }
341
342 void addFunction(const QByteArray &functionName)
343 {
344 if (!m_addedFunctions.contains(functionName)) {
345 m_addedFunctions.push_back(functionName);
346 QByteArray includeName = "func" + functionName + ".glsllib";
347 addInclude(includeName);
348 }
349 }
350
351 void addConstantBuffer(const QByteArray &name, const QByteArray &layout)
352 {
353 activeStage().addConstantBuffer(name, layout);
354 }
355
356 void addConstantBufferParam(const QByteArray &cbName, const QByteArray &paramName, const QByteArray &type)
357 {
358 activeStage().addConstantBufferParam(cbName, paramName, type);
359 }
360
361 void addDefinition(const QByteArray &name, const QByteArray &value = QByteArray())
362 {
363 activeStage().addDefinition(name, value);
364 }
365
366 QSSGStageGeneratorBase &operator<<(const QByteArray &data)
367 {
368 activeStage() << data;
369 return activeStage();
370 }
371
372 void append(const QByteArray &data) { activeStage().append(data); }
373
374 QSSGShaderGeneratorStage stage() const
375 {
376 return const_cast<QSSGMaterialVertexPipeline *>(this)->activeStage().stage();
377 }
378
379 // Responsible for beginning all vertex and fragment generation (void main() { etc).
380 void beginVertexGeneration(const QSSGShaderDefaultMaterialKey &inKey,
381 const QSSGShaderFeatures &inFeatureSet,
382 QSSGShaderLibraryManager &shaderLibraryManager);
383 // The fragment shader expects a floating point constant, qt_objectOpacity to be defined
384 // post this method.
385 void beginFragmentGeneration(QSSGShaderLibraryManager &shaderLibraryManager, QSSGRenderLayer::OITMethod oitMethod);
386 // Output variables may be mangled in some circumstances so the shader generation system
387 // needs an abstraction
388 // mechanism around this.
389 void assignOutput(const QByteArray &inVarName, const QByteArray &inVarValueExpr);
390
391 // responsible for closing all vertex and fragment generation
392 void endVertexGeneration();
393 void endFragmentGeneration();
394
395 QSSGStageGeneratorBase &activeStage();
396 void addInterpolationParameter(const QByteArray &inParamName, const QByteArray &inParamType);
397 void addFlatParameter(const QByteArray &inParamName, const QByteArray &inParamType);
398
399 void doGenerateWorldNormal(const QSSGShaderDefaultMaterialKey &inKey);
400 void doGenerateVarTangent(const QSSGShaderDefaultMaterialKey &inKey);
401 void doGenerateVarBinormal(const QSSGShaderDefaultMaterialKey &inKey);
402 bool hasAttributeInKey(QSSGShaderKeyVertexAttribute::VertexAttributeBits inAttr, const QSSGShaderDefaultMaterialKey &inKey);
403};
404
405QT_END_NAMESPACE
406
407#endif
Combined button and popup list for selecting options.
static void insertDirectionalLightProcessorArgs(QByteArray &snippet, QSSGShaderMaterialAdapter *materialAdapter)
static void insertSpecularLightProcessorArgs(QByteArray &snippet, QSSGShaderMaterialAdapter *materialAdapter)
static void insertFragmentMainArgs(QByteArray &snippet, QSSGShaderMaterialAdapter *materialAdapter)
static const char * customMainCallWithArguments(bool usesInstancing)
static void insertProcessorArgs(QByteArray &snippet, const char *argKey, const char *(*argListFunc)(), QSSGShaderMaterialAdapter *materialAdapter=nullptr, bool isSharedInout=false)
static void insertPostProcessorArgs(QByteArray &snippet, QSSGShaderMaterialAdapter *materialAdapter)
static void insertIblProbeProcessorArgs(QByteArray &snippet, QSSGShaderMaterialAdapter *materialAdapter)
static void insertAmbientLightProcessorArgs(QByteArray &snippet, QSSGShaderMaterialAdapter *materialAdapter)
static void insertVertexInstancedMainArgs(QByteArray &snippet)
static void insertVertexMainArgs(QByteArray &snippet)
static void insertSpotLightProcessorArgs(QByteArray &snippet, QSSGShaderMaterialAdapter *materialAdapter)
static QByteArray extractSharedVarsTypeDefinition(QByteArray &snippet, QSSGShaderMaterialAdapter *materialAdapter)
static void insertProcessorArgsFragmentMain(QByteArray &snippet, const char *argKey, const char *(*argListFunc)(), QSSGShaderMaterialAdapter *materialAdapter=nullptr, bool isSharedInout=false)
static void insertPointLightProcessorArgs(QByteArray &snippet, QSSGShaderMaterialAdapter *materialAdapter)