1/****************************************************************************
2**
3** Copyright (C) 2015 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:GPL-EXCEPT$
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** GNU General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU
19** General Public License version 3 as published by the Free Software
20** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
21** included in the packaging of this file. Please review the following
22** information to ensure the GNU General Public License requirements will
23** be met: https://www.gnu.org/licenses/gpl-3.0.html.
24**
25** $QT_END_LICENSE$
26**
27****************************************************************************/
28
29#include <QtTest/QTest>
30#include <Qt3DRender/private/shader_p.h>
31#include <Qt3DRender/qshaderprogram.h>
32#include <Qt3DRender/private/nodemanagers_p.h>
33#include <Qt3DRender/private/qrenderaspect_p.h>
34#include <Qt3DRender/qrenderaspect.h>
35#include <Qt3DRender/private/geometryrenderermanager_p.h>
36#include <Qt3DRender/private/buffermanager_p.h>
37#include <Qt3DRender/private/geometryrenderer_p.h>
38#include <Qt3DRender/private/geometry_p.h>
39#include <Qt3DRender/private/buffer_p.h>
40#include <Qt3DRender/private/attribute_p.h>
41#include <Qt3DRender/private/triangleboundingvolume_p.h>
42#include <Qt3DRender/private/trianglesextractor_p.h>
43#include <Qt3DRender/qattribute.h>
44#include <Qt3DRender/qbuffer.h>
45#include <Qt3DRender/qgeometry.h>
46#include <Qt3DRender/qgeometryrenderer.h>
47#include <Qt3DCore/private/qnodevisitor_p.h>
48#include <Qt3DCore/private/qnode_p.h>
49
50Qt3DRender::QGeometryRenderer *customIndexedGeometryRenderer()
51{
52 Qt3DRender::QGeometryRenderer *customMeshRenderer = new Qt3DRender::QGeometryRenderer;
53 Qt3DRender::QGeometry *customGeometry = new Qt3DRender::QGeometry(customMeshRenderer);
54
55 auto vertexDataBuffer = new Qt3DRender::QBuffer(customGeometry);
56 auto indexDataBuffer = new Qt3DRender::QBuffer(customGeometry);
57
58 // vec3 for position
59 // vec3 for colors
60 // vec3 for normals
61
62 /* 2
63 /|\
64 / | \
65 / /3\ \
66 0/___\ 1
67 */
68
69 // 4 distinct vertices
70 QByteArray vertexBufferData;
71 vertexBufferData.resize(size: 4 * (3 + 3 + 3) * sizeof(float));
72
73 // Vertices
74 QVector3D v0(-1.0f, 0.0f, -1.0f);
75 QVector3D v1(1.0f, 0.0f, -1.0f);
76 QVector3D v2(0.0f, 1.0f, 0.0f);
77 QVector3D v3(0.0f, 0.0f, 1.0f);
78
79 // Faces Normals
80 QVector3D n023 = QVector3D::normal(v1: v0, v2, v3);
81 QVector3D n012 = QVector3D::normal(v1: v0, v2: v1, v3: v2);
82 QVector3D n310 = QVector3D::normal(v1: v3, v2: v1, v3: v0);
83 QVector3D n132 = QVector3D::normal(v1, v2: v3, v3: v2);
84
85 // Vector Normals
86 QVector3D n0 = QVector3D(n023 + n012 + n310).normalized();
87 QVector3D n1 = QVector3D(n132 + n012 + n310).normalized();
88 QVector3D n2 = QVector3D(n132 + n012 + n023).normalized();
89 QVector3D n3 = QVector3D(n132 + n310 + n023).normalized();
90
91 // Colors
92 QVector3D red(1.0f, 0.0f, 0.0f);
93 QVector3D green(0.0f, 1.0f, 0.0f);
94 QVector3D blue(0.0f, 0.0f, 1.0f);
95 QVector3D white(1.0f, 1.0f, 1.0f);
96
97 const QVector<QVector3D> vertices = QVector<QVector3D>()
98 << v0 << n0 << red
99 << v1 << n1 << blue
100 << v2 << n2 << green
101 << v3 << n3 << white;
102
103 float *rawVertexArray = reinterpret_cast<float *>(vertexBufferData.data());
104 int idx = 0;
105
106 for (const QVector3D &v : vertices) {
107 rawVertexArray[idx++] = v.x();
108 rawVertexArray[idx++] = v.y();
109 rawVertexArray[idx++] = v.z();
110 }
111
112 // Indices (12)
113 QByteArray indexBufferData;
114 indexBufferData.resize(size: 4 * 3 * sizeof(ushort));
115 ushort *rawIndexArray = reinterpret_cast<ushort *>(indexBufferData.data());
116
117 // Front
118 rawIndexArray[0] = 0;
119 rawIndexArray[1] = 1;
120 rawIndexArray[2] = 2;
121 // Bottom
122 rawIndexArray[3] = 3;
123 rawIndexArray[4] = 1;
124 rawIndexArray[5] = 0;
125 // Left
126 rawIndexArray[6] = 0;
127 rawIndexArray[7] = 2;
128 rawIndexArray[8] = 3;
129 // Right
130 rawIndexArray[9] = 1;
131 rawIndexArray[10] = 3;
132 rawIndexArray[11] = 2;
133
134 vertexDataBuffer->setData(vertexBufferData);
135 indexDataBuffer->setData(indexBufferData);
136
137 // Attributes
138 Qt3DRender::QAttribute *positionAttribute = new Qt3DRender::QAttribute();
139 positionAttribute->setAttributeType(Qt3DRender::QAttribute::VertexAttribute);
140 positionAttribute->setBuffer(vertexDataBuffer);
141 positionAttribute->setVertexBaseType(Qt3DRender::QAttribute::Float);
142 positionAttribute->setVertexSize(3);
143 positionAttribute->setByteOffset(0);
144 positionAttribute->setByteStride(9 * sizeof(float));
145 positionAttribute->setCount(4);
146 positionAttribute->setName(Qt3DRender::QAttribute::defaultPositionAttributeName());
147
148 Qt3DRender::QAttribute *normalAttribute = new Qt3DRender::QAttribute();
149 normalAttribute->setAttributeType(Qt3DRender::QAttribute::VertexAttribute);
150 normalAttribute->setBuffer(vertexDataBuffer);
151 normalAttribute->setVertexBaseType(Qt3DRender::QAttribute::Float);
152 normalAttribute->setVertexSize(3);
153 normalAttribute->setByteOffset(3 * sizeof(float));
154 normalAttribute->setByteStride(9 * sizeof(float));
155 normalAttribute->setCount(4);
156 normalAttribute->setName(Qt3DRender::QAttribute::defaultNormalAttributeName());
157
158 Qt3DRender::QAttribute *colorAttribute = new Qt3DRender::QAttribute();
159 colorAttribute->setAttributeType(Qt3DRender::QAttribute::VertexAttribute);
160 colorAttribute->setBuffer(vertexDataBuffer);
161 colorAttribute->setVertexBaseType(Qt3DRender::QAttribute::Float);
162 colorAttribute->setVertexSize(3);
163 colorAttribute->setByteOffset(6 * sizeof(float));
164 colorAttribute->setByteStride(9 * sizeof(float));
165 colorAttribute->setCount(4);
166 colorAttribute->setName(Qt3DRender::QAttribute::defaultColorAttributeName());
167
168 Qt3DRender::QAttribute *indexAttribute = new Qt3DRender::QAttribute();
169 indexAttribute->setAttributeType(Qt3DRender::QAttribute::IndexAttribute);
170 indexAttribute->setBuffer(indexDataBuffer);
171 indexAttribute->setVertexBaseType(Qt3DRender::QAttribute::UnsignedShort);
172 indexAttribute->setVertexSize(1);
173 indexAttribute->setByteOffset(0);
174 indexAttribute->setByteStride(0);
175 indexAttribute->setCount(12);
176
177 customGeometry->addAttribute(attribute: positionAttribute);
178 customGeometry->addAttribute(attribute: normalAttribute);
179 customGeometry->addAttribute(attribute: colorAttribute);
180 customGeometry->addAttribute(attribute: indexAttribute);
181
182 customMeshRenderer->setInstanceCount(1);
183 customMeshRenderer->setIndexOffset(0);
184 customMeshRenderer->setFirstInstance(0);
185 customMeshRenderer->setPrimitiveType(Qt3DRender::QGeometryRenderer::Triangles);
186 customMeshRenderer->setGeometry(customGeometry);
187 // 4 faces of 3 points
188 customMeshRenderer->setVertexCount(12);
189
190 return customMeshRenderer;
191}
192
193Qt3DRender::QGeometryRenderer *customNonIndexedGeometryRenderer()
194{
195 Qt3DRender::QGeometryRenderer *customMeshRenderer = new Qt3DRender::QGeometryRenderer;
196 Qt3DRender::QGeometry *customGeometry = new Qt3DRender::QGeometry(customMeshRenderer);
197
198 auto vertexDataBuffer = new Qt3DRender::QBuffer(customGeometry);
199
200 // vec3 for position
201 // vec3 for colors
202 // vec3 for normals
203
204 /* 2
205 /|\
206 / | \
207 / /3\ \
208 0/___\ 1
209 */
210
211 // 12 distinct vertices formaing 4 triangles
212 QByteArray vertexBufferData;
213 vertexBufferData.resize(size: 4 * 3 * (3 + 3 + 3) * sizeof(float));
214
215 // Vertices
216 QVector3D v0(-1.0f, 0.0f, -1.0f);
217 QVector3D v1(1.0f, 0.0f, -1.0f);
218 QVector3D v2(0.0f, 1.0f, 0.0f);
219 QVector3D v3(0.0f, 0.0f, 1.0f);
220
221 // Faces Normals
222 QVector3D n023 = QVector3D::normal(v1: v0, v2, v3);
223 QVector3D n012 = QVector3D::normal(v1: v0, v2: v1, v3: v2);
224 QVector3D n310 = QVector3D::normal(v1: v3, v2: v1, v3: v0);
225 QVector3D n132 = QVector3D::normal(v1, v2: v3, v3: v2);
226
227 // Vector Normals
228 QVector3D n0 = QVector3D(n023 + n012 + n310).normalized();
229 QVector3D n1 = QVector3D(n132 + n012 + n310).normalized();
230 QVector3D n2 = QVector3D(n132 + n012 + n023).normalized();
231 QVector3D n3 = QVector3D(n132 + n310 + n023).normalized();
232
233 // Colors
234 QVector3D red(1.0f, 0.0f, 0.0f);
235 QVector3D green(0.0f, 1.0f, 0.0f);
236 QVector3D blue(0.0f, 0.0f, 1.0f);
237 QVector3D white(1.0f, 1.0f, 1.0f);
238
239 const QVector<QVector3D> vertices = QVector<QVector3D>()
240 << v0 << n0 << red
241 << v1 << n1 << blue
242 << v2 << n2 << green
243
244 << v3 << n3 << white
245 << v1 << n1 << blue
246 << v0 << n0 << red
247
248 << v0 << n0 << red
249 << v2 << n2 << green
250 << v3 << n3 << white
251
252 << v1 << n1 << blue
253 << v3 << n3 << white
254 << v2 << n2 << green;
255
256
257 float *rawVertexArray = reinterpret_cast<float *>(vertexBufferData.data());
258 int idx = 0;
259
260 for (const QVector3D &v : vertices) {
261 rawVertexArray[idx++] = v.x();
262 rawVertexArray[idx++] = v.y();
263 rawVertexArray[idx++] = v.z();
264 }
265
266 vertexDataBuffer->setData(vertexBufferData);
267
268 // Attributes
269 Qt3DRender::QAttribute *positionAttribute = new Qt3DRender::QAttribute();
270 positionAttribute->setAttributeType(Qt3DRender::QAttribute::VertexAttribute);
271 positionAttribute->setBuffer(vertexDataBuffer);
272 positionAttribute->setVertexBaseType(Qt3DRender::QAttribute::Float);
273 positionAttribute->setVertexSize(3);
274 positionAttribute->setByteOffset(0);
275 positionAttribute->setByteStride(9 * sizeof(float));
276 positionAttribute->setCount(12);
277 positionAttribute->setName(Qt3DRender::QAttribute::defaultPositionAttributeName());
278
279 Qt3DRender::QAttribute *normalAttribute = new Qt3DRender::QAttribute();
280 normalAttribute->setAttributeType(Qt3DRender::QAttribute::VertexAttribute);
281 normalAttribute->setBuffer(vertexDataBuffer);
282 normalAttribute->setVertexBaseType(Qt3DRender::QAttribute::Float);
283 normalAttribute->setVertexSize(3);
284 normalAttribute->setByteOffset(3 * sizeof(float));
285 normalAttribute->setByteStride(9 * sizeof(float));
286 normalAttribute->setCount(12);
287 normalAttribute->setName(Qt3DRender::QAttribute::defaultNormalAttributeName());
288
289 Qt3DRender::QAttribute *colorAttribute = new Qt3DRender::QAttribute();
290 colorAttribute->setAttributeType(Qt3DRender::QAttribute::VertexAttribute);
291 colorAttribute->setBuffer(vertexDataBuffer);
292 colorAttribute->setVertexBaseType(Qt3DRender::QAttribute::Float);
293 colorAttribute->setVertexSize(3);
294 colorAttribute->setByteOffset(6 * sizeof(float));
295 colorAttribute->setByteStride(9 * sizeof(float));
296 colorAttribute->setCount(12);
297 colorAttribute->setName(Qt3DRender::QAttribute::defaultColorAttributeName());
298
299 customGeometry->addAttribute(attribute: positionAttribute);
300 customGeometry->addAttribute(attribute: normalAttribute);
301 customGeometry->addAttribute(attribute: colorAttribute);
302
303 customMeshRenderer->setInstanceCount(1);
304 customMeshRenderer->setIndexOffset(0);
305 customMeshRenderer->setFirstInstance(0);
306 customMeshRenderer->setPrimitiveType(Qt3DRender::QGeometryRenderer::Triangles);
307 customMeshRenderer->setGeometry(customGeometry);
308 // 4 faces of 3 points
309 customMeshRenderer->setVertexCount(12);
310
311 return customMeshRenderer;
312}
313
314QT_BEGIN_NAMESPACE
315
316class TestAspect : public Qt3DRender::QRenderAspect
317{
318public:
319 TestAspect(Qt3DCore::QNode *root)
320 : Qt3DRender::QRenderAspect()
321 {
322 QVector<Qt3DCore::NodeTreeChange> nodes;
323 Qt3DCore::QNodeVisitor v;
324 v.traverse(rootNode_: root, fN: [&nodes](Qt3DCore::QNode *node) {
325 Qt3DCore::QNodePrivate *d = Qt3DCore::QNodePrivate::get(q: node);
326 d->m_typeInfo = const_cast<QMetaObject*>(Qt3DCore::QNodePrivate::findStaticMetaObject(metaObject: node->metaObject()));
327 d->m_hasBackendNode = true;
328 nodes.push_back(t: {
329 .id: node->id(),
330 .metaObj: Qt3DCore::QNodePrivate::get(q: node)->m_typeInfo,
331 .type: Qt3DCore::NodeTreeChange::Added,
332 .node: node
333 });
334 });
335
336 for (const auto &node: nodes)
337 d_func()->createBackendNode(change: node);
338 }
339
340 ~TestAspect();
341
342 Qt3DRender::Render::NodeManagers *nodeManagers() const
343 {
344 return d_func()->m_renderer->nodeManagers();
345 }
346};
347
348TestAspect::~TestAspect()
349{
350
351}
352
353QT_END_NAMESPACE
354
355class tst_TrianglesExtractor : public QObject
356{
357 Q_OBJECT
358public:
359 tst_TrianglesExtractor()
360 {
361 qRegisterMetaType<Qt3DCore::QNode*>();
362 }
363
364private Q_SLOTS:
365
366 void triangles_data()
367 {
368 QTest::addColumn<Qt3DRender::QGeometryRenderer *>(name: "geomRenderer");
369 QTest::addColumn<QVector<Qt3DRender::Render::TriangleBoundingVolume *> >(name: "expectedVolumes");
370
371 QVector<Qt3DRender::Render::TriangleBoundingVolume *> v =
372 QVector<Qt3DRender::Render::TriangleBoundingVolume *>()
373 << new Qt3DRender::Render::TriangleBoundingVolume(Qt3DCore::QNodeId(), Vector3D(0, 1, 0), Vector3D(1, 0, -1), Vector3D(-1, 0, -1))
374 << new Qt3DRender::Render::TriangleBoundingVolume(Qt3DCore::QNodeId(), Vector3D(-1, 0, -1), Vector3D(1, 0, -1), Vector3D(0, 0, 1))
375 << new Qt3DRender::Render::TriangleBoundingVolume(Qt3DCore::QNodeId(), Vector3D(0, 0, 1), Vector3D(0, 1, 0), Vector3D(-1, 0, -1))
376 << new Qt3DRender::Render::TriangleBoundingVolume(Qt3DCore::QNodeId(), Vector3D(0, 1, 0), Vector3D(0, 0, 1), Vector3D(1, 0, -1));
377
378 QTest::newRow(dataTag: "indexedMesh") << customIndexedGeometryRenderer() << v;
379 QTest::newRow(dataTag: "nonIndexedMesh") << customNonIndexedGeometryRenderer() << v;
380 }
381
382 void triangles()
383 {
384 QSKIP("Deadlocks in QRenderAspect, should be fixed");
385 // GIVEN
386 QFETCH(Qt3DRender::QGeometryRenderer *, geomRenderer);
387 QFETCH(QVector<Qt3DRender::Render::TriangleBoundingVolume *>, expectedVolumes);
388 TestAspect *aspect = new TestAspect(geomRenderer);
389 Qt3DRender::Render::NodeManagers *manager = aspect->nodeManagers();
390
391 // WHEN
392 Qt3DRender::Render::GeometryRenderer *bGeomRenderer =
393 manager->lookupResource
394 <Qt3DRender::Render::GeometryRenderer,
395 Qt3DRender::Render::GeometryRendererManager>
396 (id: geomRenderer->id());
397 // THEN
398 QVERIFY(bGeomRenderer);
399
400 // WHEN
401 Qt3DRender::Render::TrianglesExtractor extractor(bGeomRenderer, manager);
402 QVector<Qt3DRender::RayCasting::QBoundingVolume *> volumes = extractor.extract(id: Qt3DCore::QNodeId());
403
404 // THEN
405 QVERIFY(!volumes.empty());
406 QCOMPARE(volumes.size(), expectedVolumes.size());
407 for (int i = 0, m = volumes.size(); i < m; ++i) {
408 const auto *expectedVolume = expectedVolumes.at(i);
409 const auto *actualVolume = static_cast<Qt3DRender::Render::TriangleBoundingVolume *>(volumes.at(i));
410
411 QCOMPARE(expectedVolume->id(), actualVolume->id());
412 QCOMPARE(expectedVolume->a(), actualVolume->a());
413 QCOMPARE(expectedVolume->b(), actualVolume->b());
414 QCOMPARE(expectedVolume->c(), actualVolume->c());
415 }
416 }
417};
418
419QTEST_MAIN(tst_TrianglesExtractor)
420
421#include "tst_trianglesextractor.moc"
422

source code of qt3d/tests/auto/render/trianglesextractor/tst_trianglesextractor.cpp