1 | /**************************************************************************** |
2 | ** |
3 | ** Copyright (C) 2019 Klaralvdalens Datakonsult AB (KDAB). |
4 | ** Contact: https://www.qt.io/licensing/ |
5 | ** |
6 | ** This file is part of the Qt3D module of the Qt Toolkit. |
7 | ** |
8 | ** $QT_BEGIN_LICENSE:BSD$ |
9 | ** Commercial License Usage |
10 | ** Licensees holding valid commercial Qt licenses may use this file in |
11 | ** accordance with the commercial license agreement provided with the |
12 | ** Software or, alternatively, in accordance with the terms contained in |
13 | ** a written agreement between you and The Qt Company. For licensing terms |
14 | ** and conditions see https://www.qt.io/terms-conditions. For further |
15 | ** information use the contact form at https://www.qt.io/contact-us. |
16 | ** |
17 | ** BSD License Usage |
18 | ** Alternatively, you may use this file under the terms of the BSD license |
19 | ** as follows: |
20 | ** |
21 | ** "Redistribution and use in source and binary forms, with or without |
22 | ** modification, are permitted provided that the following conditions are |
23 | ** met: |
24 | ** * Redistributions of source code must retain the above copyright |
25 | ** notice, this list of conditions and the following disclaimer. |
26 | ** * Redistributions in binary form must reproduce the above copyright |
27 | ** notice, this list of conditions and the following disclaimer in |
28 | ** the documentation and/or other materials provided with the |
29 | ** distribution. |
30 | ** * Neither the name of The Qt Company Ltd nor the names of its |
31 | ** contributors may be used to endorse or promote products derived |
32 | ** from this software without specific prior written permission. |
33 | ** |
34 | ** |
35 | ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
36 | ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
37 | ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
38 | ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
39 | ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
40 | ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
41 | ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
42 | ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
43 | ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
44 | ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
45 | ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." |
46 | ** |
47 | ** $QT_END_LICENSE$ |
48 | ** |
49 | ****************************************************************************/ |
50 | |
51 | #include <QGuiApplication> |
52 | |
53 | #include <Qt3DCore/QEntity> |
54 | #include <Qt3DRender/QCamera> |
55 | #include <Qt3DRender/QCameraLens> |
56 | #include <Qt3DCore/QTransform> |
57 | #include <Qt3DCore/QAspectEngine> |
58 | |
59 | #include <Qt3DInput/QInputAspect> |
60 | |
61 | #include <Qt3DRender/QRenderStateSet> |
62 | #include <Qt3DRender/QRenderAspect> |
63 | #include <Qt3DExtras/QForwardRenderer> |
64 | #include <Qt3DExtras/QPerVertexColorMaterial> |
65 | |
66 | #include <Qt3DRender/QGeometryRenderer> |
67 | #include <Qt3DRender/QGeometry> |
68 | #include <Qt3DRender/QAttribute> |
69 | #include <Qt3DRender/QBuffer> |
70 | |
71 | #include <QPropertyAnimation> |
72 | #include <Qt3DExtras/qt3dwindow.h> |
73 | #include <Qt3DExtras/qorbitcameracontroller.h> |
74 | #include <Qt3DRender/QParameter> |
75 | #include <Qt3DRender/QEffect> |
76 | #include <Qt3DRender/QTechnique> |
77 | #include <Qt3DRender/QAbstractTexture> |
78 | #include <Qt3DRender/QShaderProgram> |
79 | #include <Qt3DRender/QRenderPass> |
80 | #include <Qt3DRender/QBlendEquation> |
81 | #include <Qt3DRender/QBlendEquationArguments> |
82 | #include <Qt3DRender/QFilterKey> |
83 | #include <Qt3DRender/QGraphicsApiFilter> |
84 | #include <Qt3DRender/QRenderSurfaceSelector> |
85 | #include <Qt3DRender/QViewport> |
86 | #include <Qt3DRender/QCameraSelector> |
87 | #include <Qt3DRender/QNoDraw> |
88 | #include <QColor> |
89 | #include <QVector2D> |
90 | #include <QUrl> |
91 | #include <QTimer> |
92 | #include <Qt3DRender/QMaterial> |
93 | #include <Qt3DRender/QFilterKey> |
94 | #include <Qt3DRender/QTechnique> |
95 | #include <Qt3DRender/QMaterial> |
96 | #include <Qt3DRender/QTexture> |
97 | #include <qmath.h> |
98 | |
99 | static const constexpr auto vertex_shader = R"_(#version 450 |
100 | |
101 | /** |
102 | * Unicode comment: Ѧ𝙱ƇᗞΣ |
103 | */ |
104 | |
105 | layout(location = 0) in vec3 vertexPosition; |
106 | layout(location = 1) in vec3 vertexColor; |
107 | layout(location = 0) out vec3 color; |
108 | |
109 | layout(std140, binding = 0) uniform qt3d_render_view_uniforms { |
110 | mat4 viewMatrix; |
111 | mat4 projectionMatrix; |
112 | mat4 viewProjectionMatrix; |
113 | mat4 inverseViewMatrix; |
114 | mat4 inverseProjectionMatrix; |
115 | mat4 inverseViewProjectionMatrix; |
116 | mat4 viewportMatrix; |
117 | mat4 inverseViewportMatrix; |
118 | vec4 textureTransformMatrix; |
119 | vec3 eyePosition; |
120 | float aspectRatio; |
121 | float gamma; |
122 | float exposure; |
123 | float time; |
124 | }; |
125 | layout(std140, binding = 1) uniform qt3d_command_uniforms { |
126 | mat4 modelMatrix; |
127 | mat4 inverseModelMatrix; |
128 | mat4 modelViewMatrix; |
129 | mat3 modelNormalMatrix; |
130 | mat4 inverseModelViewMatrix; |
131 | mat4 mvp; |
132 | mat4 inverseModelViewProjectionMatrix; |
133 | }; |
134 | void main() |
135 | { |
136 | color = vertexColor; |
137 | gl_Position = mvp * vec4(vertexPosition, 1.0); |
138 | } |
139 | )_" ; |
140 | |
141 | static const constexpr auto fragment_shader = R"_(#version 450 |
142 | |
143 | /** |
144 | * Unicode comment: Ѧ𝙱ƇᗞΣ |
145 | */ |
146 | |
147 | layout(location = 0) out vec4 fragColor; |
148 | layout(location = 0) in vec3 color; |
149 | |
150 | layout(std140, binding = 0) uniform qt3d_render_view_uniforms { |
151 | mat4 viewMatrix; |
152 | mat4 projectionMatrix; |
153 | mat4 viewProjectionMatrix; |
154 | mat4 inverseViewMatrix; |
155 | mat4 inverseProjectionMatrix; |
156 | mat4 inverseViewProjectionMatrix; |
157 | mat4 viewportMatrix; |
158 | mat4 inverseViewportMatrix; |
159 | vec4 textureTransformMatrix; |
160 | vec3 eyePosition; |
161 | float aspectRatio; |
162 | float gamma; |
163 | float exposure; |
164 | float time; |
165 | }; |
166 | layout(std140, binding = 1) uniform qt3d_command_uniforms { |
167 | mat4 modelMatrix; |
168 | mat4 inverseModelMatrix; |
169 | mat4 modelViewMatrix; |
170 | mat3 modelNormalMatrix; |
171 | mat4 inverseModelViewMatrix; |
172 | mat4 mvp; |
173 | mat4 inverseModelViewProjectionMatrix; |
174 | }; |
175 | layout(std140, binding = 2) uniform custom_ubo { |
176 | vec3 colorFactor; |
177 | }; |
178 | |
179 | layout(binding = 3) uniform sampler2D myTexture; |
180 | void main() |
181 | { |
182 | vec2 texCoord = color.xz; |
183 | vec2 rhiTexCoord = textureTransformMatrix.xy * texCoord+ textureTransformMatrix.zw; |
184 | fragColor = vec4(color * colorFactor, 1.0); |
185 | |
186 | fragColor *= texture(myTexture, rhiTexCoord); |
187 | } |
188 | |
189 | )_" ; |
190 | |
191 | class Material : public Qt3DRender::QMaterial |
192 | { |
193 | public: |
194 | explicit Material(Qt3DCore::QNode *parent = nullptr) |
195 | : QMaterial(parent) |
196 | , m_effect(new Qt3DRender::QEffect(this)) |
197 | { |
198 | setEffect(m_effect); |
199 | |
200 | m_testParam = new Qt3DRender::QParameter(QStringLiteral("example" ), float(0.5)); |
201 | |
202 | m_effect->addParameter(parameter: m_testParam); |
203 | |
204 | m_filter = new Qt3DRender::QFilterKey(this); |
205 | m_filter->setName(QStringLiteral("renderingStyle" )); |
206 | m_filter->setValue(QStringLiteral("forward" )); |
207 | |
208 | m_technique = new Qt3DRender::QTechnique(m_effect); |
209 | m_technique->addFilterKey(filterKey: m_filter); |
210 | |
211 | m_effect->addTechnique(t: m_technique); |
212 | |
213 | m_program = new Qt3DRender::QShaderProgram(m_effect); |
214 | m_program->setVertexShaderCode(vertex_shader); |
215 | m_program->setFragmentShaderCode(fragment_shader); |
216 | |
217 | m_renderPass = new Qt3DRender::QRenderPass(m_effect); |
218 | |
219 | m_renderPass->setShaderProgram(m_program); |
220 | |
221 | m_technique->addRenderPass(pass: m_renderPass); |
222 | |
223 | m_technique->graphicsApiFilter()->setApi(Qt3DRender::QGraphicsApiFilter::RHI); |
224 | } |
225 | private: |
226 | Qt3DRender::QEffect *m_effect{}; |
227 | Qt3DRender::QParameter *m_testParam{}; |
228 | Qt3DRender::QFilterKey *m_filter{}; |
229 | Qt3DRender::QTechnique *m_technique{}; |
230 | Qt3DRender::QShaderProgram *m_program{}; |
231 | Qt3DRender::QRenderPass *m_renderPass{}; |
232 | }; |
233 | |
234 | int main(int argc, char* argv[]) |
235 | { |
236 | qputenv(varName: "QT3D_RENDERER" , value: "rhi" ); |
237 | QGuiApplication app(argc, argv); |
238 | |
239 | auto api = Qt3DRender::API::OpenGL; |
240 | if (argc >= 2) { |
241 | |
242 | #ifdef Q_OS_WIN |
243 | if (argv[1] == QByteArrayLiteral("--d3d11" )) api = Qt3DRender::API::DirectX; |
244 | #endif |
245 | |
246 | #if QT_CONFIG(vulkan) |
247 | if (argv[1] == QByteArrayLiteral("--vulkan" )) api = Qt3DRender::API::Vulkan; |
248 | #endif |
249 | |
250 | #if defined(Q_OS_MACOS) || defined(Q_OS_IOS) |
251 | if (argv[1] == QByteArrayLiteral("--metal" )) api = Qt3DRender::API::Metal; |
252 | #endif |
253 | } |
254 | |
255 | Qt3DExtras::Qt3DWindow view{nullptr, api}; |
256 | |
257 | // Root entity |
258 | Qt3DCore::QEntity *rootEntity = new Qt3DCore::QEntity(); |
259 | |
260 | // Camera |
261 | Qt3DRender::QCamera *topViewCamera = new Qt3DRender::QCamera(rootEntity); |
262 | topViewCamera->setPosition(QVector3D(0, 40, 0)); |
263 | topViewCamera->setViewCenter(QVector3D(0, 0, 0)); |
264 | topViewCamera->setUpVector(QVector3D(0, 0, 1)); |
265 | topViewCamera->lens()->setPerspectiveProjection(fieldOfView: 45.0f, aspect: 16.0f/9.0f, nearPlane: 0.1f, farPlane: 1000.0f); |
266 | |
267 | Qt3DRender::QCamera *cameraEntity = view.camera(); |
268 | cameraEntity->lens()->setPerspectiveProjection(fieldOfView: 45.0f, aspect: 16.0f/9.0f, nearPlane: 0.1f, farPlane: 1000.0f); |
269 | cameraEntity->setPosition(QVector3D(0, 0, 40.0f)); |
270 | cameraEntity->setUpVector(QVector3D(0, 1, 0)); |
271 | cameraEntity->setViewCenter(QVector3D(0, 0, 0)); |
272 | |
273 | { |
274 | // Custom FG |
275 | auto *surfaceSelector = new Qt3DRender::QRenderSurfaceSelector(); |
276 | surfaceSelector->setSurface(&view); |
277 | |
278 | // RV 1 |
279 | auto *clearBuffer = new Qt3DRender::QClearBuffers(surfaceSelector); |
280 | clearBuffer->setBuffers(Qt3DRender::QClearBuffers::ColorDepthBuffer); |
281 | clearBuffer->setClearColor(QColor::fromRgbF(r: 0.1, g: 0.5, b: 0.0, a: 1.0)); |
282 | auto *noDraw = new Qt3DRender::QNoDraw(clearBuffer); |
283 | |
284 | // RV 2 |
285 | auto *cameraSelector1 = new Qt3DRender::QCameraSelector(surfaceSelector); |
286 | cameraSelector1->setCamera(view.camera()); |
287 | auto *viewport1 = new Qt3DRender::QViewport(cameraSelector1); |
288 | viewport1->setNormalizedRect(QRectF(0.0f, 0.0f, 0.5f, 0.5f)); |
289 | |
290 | // RV3 |
291 | auto *cameraSelector2 = new Qt3DRender::QCameraSelector(surfaceSelector); |
292 | cameraSelector2->setCamera(topViewCamera); |
293 | auto *viewport2 = new Qt3DRender::QViewport(cameraSelector2); |
294 | viewport2->setNormalizedRect(QRectF(0.5f, 0.5f, 0.5f, 0.5f)); |
295 | |
296 | view.setActiveFrameGraph(surfaceSelector); |
297 | } |
298 | |
299 | QTimer *cameraAnimationTimer = new QTimer(&view); |
300 | QObject::connect(sender: cameraAnimationTimer, signal: &QTimer::timeout, |
301 | slot: [cameraEntity] { |
302 | static int angle = 0; |
303 | const float radius = 40.0f; |
304 | const float anglef = qDegreesToRadians(degrees: float(angle)); |
305 | cameraEntity->setPosition(QVector3D(qSin(v: anglef), 0.0f, qCos(v: anglef)) * radius); |
306 | angle += 1; |
307 | }); |
308 | cameraAnimationTimer->start(msec: 16); |
309 | |
310 | // For camera controls |
311 | Qt3DExtras::QOrbitCameraController *camController = new Qt3DExtras::QOrbitCameraController(rootEntity); |
312 | camController->setCamera(cameraEntity); |
313 | |
314 | // Material |
315 | Qt3DRender::QMaterial *material = new Material(rootEntity); |
316 | Qt3DRender::QParameter *parameter = new Qt3DRender::QParameter(QStringLiteral("colorFactor" ), QColor(Qt::white)); |
317 | material->addParameter(parameter); |
318 | |
319 | Qt3DRender::QTextureLoader *textureLoader = new Qt3DRender::QTextureLoader{}; |
320 | textureLoader->setSource(QUrl{QStringLiteral("qrc:///qtlogo.png" )}); |
321 | Qt3DRender::QParameter *texture = new Qt3DRender::QParameter(QStringLiteral("myTexture" ), textureLoader); |
322 | material->addParameter(parameter: texture); |
323 | |
324 | QTimer *parameterAnimationTimer = new QTimer(&view); |
325 | QObject::connect(sender: parameterAnimationTimer, signal: &QTimer::timeout, |
326 | slot: [parameter] { |
327 | static int angle = 0; |
328 | const float anglef = qDegreesToRadians(degrees: float(angle)); |
329 | parameter->setValue(QColor::fromRgbF(r: fabs(x: qCos(v: anglef)), g: fabs(x: qSin(v: anglef)), b: 1.0f)); |
330 | angle += 10; |
331 | }); |
332 | parameterAnimationTimer->start(msec: 16); |
333 | |
334 | // Torus |
335 | Qt3DCore::QEntity *customMeshEntity = new Qt3DCore::QEntity(rootEntity); |
336 | |
337 | // Transform |
338 | Qt3DCore::QTransform *transform = new Qt3DCore::QTransform; |
339 | transform->setScale(8.0f); |
340 | |
341 | // Custom Mesh (TetraHedron) |
342 | Qt3DRender::QGeometryRenderer *customMeshRenderer = new Qt3DRender::QGeometryRenderer; |
343 | Qt3DRender::QGeometry *customGeometry = new Qt3DRender::QGeometry(customMeshRenderer); |
344 | |
345 | Qt3DRender::QBuffer *vertexDataBuffer = new Qt3DRender::QBuffer(customGeometry); |
346 | Qt3DRender::QBuffer *indexDataBuffer = new Qt3DRender::QBuffer(customGeometry); |
347 | |
348 | // 5 vertices of 3 vertices + 3 colors |
349 | QByteArray vertexBufferData; |
350 | vertexBufferData.resize(size: 5 * (3 + 3) * sizeof(float)); |
351 | |
352 | // Vertices |
353 | QVector3D v0(-1.0f, 0.0f, -1.0f); |
354 | QVector3D v1(1.0f, 0.0f, -1.0f); |
355 | QVector3D v2(-1.0f, 0.0f, 1.0f); |
356 | QVector3D v3(1.0f, 0.0f, 1.0f); |
357 | QVector3D v4(0.0f, 2.0f, 0.0f); |
358 | |
359 | QVector3D red(1.0f, 0.0f, 0.0f); |
360 | QVector3D green(0.0f, 1.0f, 0.0f); |
361 | QVector3D blue(0.0f, 0.0f, 1.0f); |
362 | QVector3D white(1.0f, 1.0f, 1.0f); |
363 | QVector3D grey(0.5f, 0.5f, 0.5f); |
364 | |
365 | const QVector<QVector3D> vertices = QVector<QVector3D>() |
366 | << v0 << red |
367 | << v1 << green |
368 | << v2 << blue |
369 | << v3 << grey |
370 | << v4 << white; |
371 | |
372 | memcpy(dest: vertexBufferData.data(), src: vertices.constData(), n: vertices.size() * sizeof(QVector3D)); |
373 | vertexDataBuffer->setData(vertexBufferData); |
374 | |
375 | QByteArray indexBufferData; |
376 | // 6 triangle faces |
377 | indexBufferData.resize(size: 6 * 3 * sizeof(ushort)); |
378 | ushort *rawIndexArray = reinterpret_cast<ushort *>(indexBufferData.data()); |
379 | |
380 | rawIndexArray[0] = 0; |
381 | rawIndexArray[1] = 1; |
382 | rawIndexArray[2] = 2; |
383 | |
384 | rawIndexArray[3] = 2; |
385 | rawIndexArray[4] = 1; |
386 | rawIndexArray[5] = 3; |
387 | |
388 | rawIndexArray[6] = 2; |
389 | rawIndexArray[7] = 3; |
390 | rawIndexArray[8] = 4; |
391 | |
392 | rawIndexArray[9] = 3; |
393 | rawIndexArray[10] = 1; |
394 | rawIndexArray[11] = 4; |
395 | |
396 | rawIndexArray[12] = 1; |
397 | rawIndexArray[13] = 0; |
398 | rawIndexArray[14] = 4; |
399 | |
400 | rawIndexArray[15] = 0; |
401 | rawIndexArray[16] = 2; |
402 | rawIndexArray[17] = 4; |
403 | |
404 | indexDataBuffer->setData(indexBufferData); |
405 | |
406 | // Attributes |
407 | Qt3DRender::QAttribute *positionAttribute = new Qt3DRender::QAttribute(); |
408 | positionAttribute->setAttributeType(Qt3DRender::QAttribute::VertexAttribute); |
409 | positionAttribute->setBuffer(vertexDataBuffer); |
410 | positionAttribute->setVertexBaseType(Qt3DRender::QAttribute::Float); |
411 | positionAttribute->setVertexSize(3); |
412 | positionAttribute->setByteOffset(0); |
413 | positionAttribute->setByteStride(6 * sizeof(float)); |
414 | positionAttribute->setCount(5); |
415 | positionAttribute->setName(Qt3DRender::QAttribute::defaultPositionAttributeName()); |
416 | |
417 | Qt3DRender::QAttribute *colorAttribute = new Qt3DRender::QAttribute(); |
418 | colorAttribute->setAttributeType(Qt3DRender::QAttribute::VertexAttribute); |
419 | colorAttribute->setBuffer(vertexDataBuffer); |
420 | colorAttribute->setVertexBaseType(Qt3DRender::QAttribute::Float); |
421 | colorAttribute->setVertexSize(3); |
422 | colorAttribute->setByteOffset(3 * sizeof(float)); |
423 | colorAttribute->setByteStride(6 * sizeof(float)); |
424 | colorAttribute->setCount(5); |
425 | colorAttribute->setName(Qt3DRender::QAttribute::defaultColorAttributeName()); |
426 | |
427 | Qt3DRender::QAttribute *indexAttribute = new Qt3DRender::QAttribute(); |
428 | indexAttribute->setAttributeType(Qt3DRender::QAttribute::IndexAttribute); |
429 | indexAttribute->setBuffer(indexDataBuffer); |
430 | indexAttribute->setVertexBaseType(Qt3DRender::QAttribute::UnsignedShort); |
431 | indexAttribute->setVertexSize(1); |
432 | indexAttribute->setByteOffset(0); |
433 | indexAttribute->setByteStride(0); |
434 | indexAttribute->setCount(18); |
435 | |
436 | customGeometry->addAttribute(attribute: positionAttribute); |
437 | customGeometry->addAttribute(attribute: colorAttribute); |
438 | customGeometry->addAttribute(attribute: indexAttribute); |
439 | |
440 | customMeshRenderer->setPrimitiveType(Qt3DRender::QGeometryRenderer::Triangles); |
441 | customMeshRenderer->setGeometry(customGeometry); |
442 | |
443 | customMeshEntity->addComponent(comp: customMeshRenderer); |
444 | customMeshEntity->addComponent(comp: transform); |
445 | customMeshEntity->addComponent(comp: material); |
446 | |
447 | view.setRootEntity(rootEntity); |
448 | view.show(); |
449 | |
450 | return app.exec(); |
451 | } |
452 | |