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
qcapsulegeometry.cpp
Go to the documentation of this file.
1// Copyright (C) 2022 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
3
4// Based on:
5// https://behreajj.medium.com/making-a-capsule-mesh-via-script-in-five-3d-environments-c2214abf02db
6// Qt-Security score:significant reason:default
7
9
10#include <QVector3D>
11
13
14/*!
15 \qmltype CapsuleGeometry
16 \inqmlmodule QtQuick3D.Physics.Helpers
17 \inherits Geometry
18 \since 6.4
19 \brief A geometry for generating a capsule model.
20 \deprecated [6.10]
21
22 Deprecated, use \l{QtQuick3D.Helpers::CapsuleGeometry}
23 {QtQuick3D.Helpers.CapsuleGeometry} instead.
24
25 A geometry for generating a capsule model.
26*/
27
28/*! \qmlproperty bool CapsuleGeometry::enableNormals
29 \default true
30
31 Generate mesh face normals.
32*/
33
34/*! \qmlproperty bool CapsuleGeometry::enableUV
35 \default false
36
37 Generate mesh uv coordinates.
38*/
39
40/*! \qmlproperty int CapsuleGeometry::longitudes
41 \default 32
42
43 Number of longitudes, or meridians, distributed by azimuth.
44*/
45
46/*! \qmlproperty int CapsuleGeometry::latitudes
47 \default 16
48
49 Number of latitudes, distributed by inclination. Must be even.
50*/
51
52/*! \qmlproperty int CapsuleGeometry::rings
53 \default 1
54
55 Number of sections in cylinder between hemispheres.
56*/
57
58/*! \qmlproperty real CapsuleGeometry::height
59 \default 100
60
61 Height of the middle cylinder on the y axis, excluding the hemispheres.
62*/
63
64/*! \qmlproperty real CapsuleGeometry::diameter
65 \default 100
66
67 Diameter on the xz plane.
68*/
69
70CapsuleGeometryPhysics::CapsuleGeometryPhysics()
71{
72 updateData();
73}
74
75void CapsuleGeometryPhysics::setEnableNormals(bool enable)
76{
77 if (m_enableNormals == enable)
78 return;
79
80 m_enableNormals = enable;
81 emit enableNormalsChanged();
82 updateData();
83 update();
84}
85
86void CapsuleGeometryPhysics::setEnableUV(bool enable)
87{
88 if (m_enableUV == enable)
89 return;
90
91 m_enableUV = enable;
92 emit enableUVChanged();
93 updateData();
94 update();
95}
96
97void CapsuleGeometryPhysics::setLongitudes(int longitudes)
98{
99 if (m_longitudes == longitudes)
100 return;
101
102 m_longitudes = longitudes;
103 emit longitudesChanged();
104 updateData();
105 update();
106}
107
108void CapsuleGeometryPhysics::setLatitudes(int latitudes)
109{
110 if (m_latitudes == latitudes)
111 return;
112
113 m_latitudes = latitudes;
114 emit latitudesChanged();
115 updateData();
116 update();
117}
118
119void CapsuleGeometryPhysics::setRings(int rings)
120{
121 if (m_rings == rings)
122 return;
123
124 m_rings = rings;
125 emit ringsChanged();
126 updateData();
127 update();
128}
129
130void CapsuleGeometryPhysics::setHeight(float height)
131{
132 if (m_height == height)
133 return;
134
135 m_height = height;
136 emit heightChanged();
137 updateData();
138 update();
139}
140
141void CapsuleGeometryPhysics::setDiameter(float diameter)
142{
143 if (m_diameter == diameter)
144 return;
145
146 m_diameter = diameter;
147 emit diameterChanged();
148 updateData();
149 update();
150}
151
152struct Face
153{
154 // Coordinate index.
156 // Texture coordinate index.
158 // Normal index.
160};
161
162void CapsuleGeometryPhysics::updateData()
163{
164 clear();
165
166 constexpr float EPSILON = 0.001f;
167 const float radius = m_diameter * 0.5f;
168
169 // m_latitudes must be even for symmetry.
170 int verifLats = qMax(2, m_latitudes);
171 if (verifLats % 2 != 0) {
172 verifLats += 1;
173 }
174
175 // Validate input arguments.
176 uint32_t verifLons = qMax(3, m_longitudes);
177 uint32_t verifRings = qMax(0, m_rings);
178 float verifDepth = qMax(EPSILON, m_height);
179 float verifRad = qMax(EPSILON, radius);
180
181 // Intermediary calculations.
182 bool calcMiddle = verifRings > 0;
183 uint32_t halfLats = verifLats / 2;
184 uint32_t halfLatsn1 = halfLats - 1;
185 uint32_t halfLatsn2 = halfLats - 2;
186 uint32_t verifRingsp1 = verifRings + 1;
187 uint32_t verifLonsp1 = verifLons + 1;
188 uint32_t lonsHalfLatn1 = halfLatsn1 * verifLons;
189 uint32_t lonsRingsp1 = verifRingsp1 * verifLons;
190 float halfDepth = verifDepth * 0.5f;
191 float summit = halfDepth + verifRad;
192
193 // Index offsets for coordinates.
194 uint32_t idxVNEquator = verifLonsp1 + verifLons * halfLatsn2;
195 uint32_t idxVCyl = idxVNEquator + verifLons;
196 uint32_t idxVSEquator = idxVCyl;
197 if (calcMiddle) {
198 idxVSEquator += verifLons * verifRings;
199 }
200 uint32_t idxVSouth = idxVSEquator + verifLons;
201 uint32_t idxVSouthCap = idxVSouth + verifLons * halfLatsn2;
202 uint32_t idxVSouthPole = idxVSouthCap + verifLons;
203
204 // Index offsets for texture coordinates.
205 uint32_t idxVtNEquator = verifLons + verifLonsp1 * halfLatsn1;
206 uint32_t idxVtCyl = idxVtNEquator + verifLonsp1;
207 uint32_t idxVtSEquator = idxVtCyl;
208 if (calcMiddle) {
209 idxVtSEquator += verifLonsp1 * verifRings;
210 }
211 uint32_t idxVtSHemi = idxVtSEquator + verifLonsp1;
212 uint32_t idxVtSPolar = idxVtSHemi + verifLonsp1 * halfLatsn2;
213 uint32_t idxVtSCap = idxVtSPolar + verifLonsp1;
214
215 // Index offsets for normals.
216 uint32_t idxVnSouth = idxVNEquator + verifLons;
217 uint32_t idxVnSouthCap = idxVnSouth + verifLons * halfLatsn2;
218 uint32_t idxVnSouthPole = idxVnSouthCap + verifLons;
219
220 // Find index offsets for face indices.
221 uint32_t idxFsCyl = verifLons + lonsHalfLatn1 * 2;
222 uint32_t idxFsSouthEquat = idxFsCyl + lonsRingsp1 * 2;
223 uint32_t idxFsSouthHemi = idxFsSouthEquat + lonsHalfLatn1 * 2;
224
225 // Array lengths.
226 uint32_t verticesLen = idxVSouthPole + 1;
227 uint32_t texturesLen = idxVtSCap + verifLons;
228 uint32_t normalsLen = idxVnSouthPole + 1;
229 uint32_t facesLen = idxFsSouthHemi + verifLons;
230
231 // Initialize arrays.
232 auto vertices = QList<QVector3D>(verticesLen);
233 auto vertexTextures = QList<QVector2D>(texturesLen);
234 auto vertexNormals = QList<QVector3D>(normalsLen);
235
236 // If we plan to use only triangles, we can initialize
237 // the inner array to 3.
238 auto faces = QList<std::array<Face, 3>>(facesLen);
239
240 // North pole.
241 vertices[0] = QVector3D(-summit, 0.f, 0.f);
242 vertexNormals[0] = QVector3D(-1.f, 0.f, 0.f);
243
244 // South pole.
245 vertices[idxVSouthPole] = QVector3D(summit, 0.f, 0.f);
246 vertexNormals[idxVnSouthPole] = QVector3D(1.f, 0.f, 0.f);
247
248 // Calculate polar texture coordinates, equatorial coordinates.
249 QList<float> sinThetaCache = QList<float>(verifLons);
250 QList<float> cosThetaCache = QList<float>(verifLons);
251 float toTheta = 2 * M_PI / verifLons;
252 float toPhi = M_PI / verifLats;
253 float toTexHorizontal = 1.f / verifLons;
254 float toTexVertical = 1.f / halfLats;
255
256 for (uint32_t j = 0; j < verifLons; ++j) {
257
258 // Coordinates.
259 float theta = j * toTheta;
260 float sinTheta = sin(theta);
261 float cosTheta = cos(theta);
262 sinThetaCache[j] = sinTheta;
263 cosThetaCache[j] = cosTheta;
264
265 // Texture coordinates at North and South pole.
266 float sTex = (j + 0.5f) * toTexHorizontal;
267 vertexTextures[j] = QVector2D(sTex, 1.f);
268 vertexTextures[idxVtSCap + j] = QVector2D(sTex, 0.f);
269
270 // Multiply by radius to get equatorial x and y.
271 float x = verifRad * cosTheta;
272 float z = verifRad * sinTheta;
273
274 // Set equatorial coordinates. Offset by cylinder depth.
275 vertices[idxVNEquator + j] = QVector3D(-halfDepth, x, -z);
276 vertices[idxVSEquator + j] = QVector3D(halfDepth, x, -z);
277
278 // Set equatorial normals.
279 vertexNormals[idxVNEquator + j] = QVector3D(0.f, cosTheta, -sinTheta);
280
281 // Set polar indices.
282 uint32_t jNextVt = j + 1;
283 uint32_t jNextV = jNextVt % verifLons;
284
285 // North triangle.
286 faces[j] = { Face { 0, j, 0 }, Face { jNextVt, verifLons + j, jNextVt },
287 Face { 1 + jNextV, verifLons + jNextVt, 1 + jNextV } };
288
289 // South triangle.
290 faces[idxFsSouthHemi + j] = {
291 Face { idxVSouthPole, idxVtSCap + j, idxVnSouthPole },
292 Face { idxVSouthCap + jNextV, idxVtSPolar + jNextVt, idxVnSouthCap + jNextV },
293 Face { idxVSouthCap + j, idxVtSPolar + j, idxVnSouthCap + j }
294 };
295 }
296
297 // Determine UV aspect ratio from the profile.
298 float vtAspectRatio = 0.f;
299 switch (m_uvProfile) {
300 case CapsuleGeometryPhysics::UvProfile::Fixed:
301 vtAspectRatio = 0.33333333f;
302 break;
303 case CapsuleGeometryPhysics::UvProfile::Aspect:
304 vtAspectRatio = verifRad / (verifDepth + verifRad + verifRad);
305 break;
306 case CapsuleGeometryPhysics::UvProfile::Uniform:
307 vtAspectRatio = (float)halfLats / (verifRingsp1 + verifLats);
308 break;
309 }
310 float vtAspectSouth = vtAspectRatio;
311 float vtAspectNorth = 1.f - vtAspectRatio;
312
313 // Cache horizontal measure.
314 QList<float> sTexCache = QList<float>(verifLonsp1);
315
316 // Calculate equatorial texture coordinates.
317 for (uint32_t j = 0; j < verifLonsp1; ++j) {
318 float sTex = j * toTexHorizontal;
319 sTexCache[j] = sTex;
320 vertexTextures[idxVtNEquator + j] = QVector2D(sTex, vtAspectNorth);
321 vertexTextures[idxVtSEquator + j] = QVector2D(sTex, vtAspectSouth);
322 }
323
324 // Divide m_latitudes into hemispheres. Start at i = 1 due to the poles.
325 uint32_t vHemiOffsetNorth = 1;
326 uint32_t vHemiOffsetSouth = idxVSouth;
327 uint32_t vtHemiOffsetNorth = verifLons;
328 uint32_t vtHemiOffsetSouth = idxVtSHemi;
329 uint32_t vnHemiOffsetSouth = idxVnSouth;
330 uint32_t fHemiOffsetNorth = verifLons;
331 uint32_t fHemiOffsetSouth = idxFsSouthEquat;
332
333 for (uint32_t i = 0; i < halfLatsn1; ++i) {
334 uint32_t iLonsCurr = i * verifLons;
335 float ip1f = i + 1.f;
336 float phi = ip1f * toPhi;
337 float sinPhiSouth = sin(phi);
338 float cosPhiSouth = cos(phi);
339
340 // Use trigonometric symmetries to avoid calculating another
341 // sine and cosine for phi North.
342 float cosPhiNorth = sinPhiSouth;
343 float sinPhiNorth = -cosPhiSouth;
344
345 // For North coordinates, multiply by radius and offset.
346 float rhoCosPhiNorth = verifRad * cosPhiNorth;
347 float rhoSinPhiNorth = verifRad * sinPhiNorth;
348 float yOffsetNorth = halfDepth - rhoSinPhiNorth;
349
350 // For South coordinates, multiply by radius and offset.
351 float rhoCosPhiSouth = verifRad * cosPhiSouth;
352 float rhoSinPhiSouth = verifRad * sinPhiSouth;
353 float yOffsetSouth = -halfDepth - rhoSinPhiSouth;
354
355 // North coordinate index offset.
356 uint32_t vCurrLatN = 1 + iLonsCurr;
357 uint32_t vNextLatN = vCurrLatN + verifLons;
358
359 // South coordinate index offset.
360 uint32_t vCurrLatS = idxVSEquator + iLonsCurr;
361 uint32_t vNextLatS = vCurrLatS + verifLons;
362
363 // North texture coordinate index offset.
364 uint32_t vtCurrLatN = verifLons + i * verifLonsp1;
365 uint32_t vtNextLatN = vtCurrLatN + verifLonsp1;
366
367 // South texture coordinate index offset.
368 uint32_t vtCurrLatS = idxVtSEquator + i * verifLonsp1;
369 uint32_t vtNextLatS = vtCurrLatS + verifLonsp1;
370
371 // North normal index offset.
372 uint32_t vnCurrLatN = 1 + iLonsCurr;
373 uint32_t vnNextLatN = vnCurrLatN + verifLons;
374
375 // South normal index offset.
376 uint32_t vnCurrLatS = idxVNEquator + iLonsCurr;
377 uint32_t vnNextLatS = vnCurrLatS + verifLons;
378
379 // Coordinates, normals and face indices.
380 for (uint32_t j = 0; j < verifLons; ++j) {
381 float sinTheta = sinThetaCache[j];
382 float cosTheta = cosThetaCache[j];
383
384 // North coordinate.
385 vertices[vHemiOffsetNorth] =
386 QVector3D(-yOffsetNorth, rhoCosPhiNorth * cosTheta, -rhoCosPhiNorth * sinTheta);
387
388 // North normal.
389 vertexNormals[vHemiOffsetNorth] =
390 QVector3D(sinPhiNorth, cosPhiNorth * cosTheta, -cosPhiNorth * sinTheta);
391
392 // South coordinate.
393 vertices[vHemiOffsetSouth] =
394 QVector3D(-yOffsetSouth, rhoCosPhiSouth * cosTheta, -rhoCosPhiSouth * sinTheta);
395
396 // South normal.
397 vertexNormals[vnHemiOffsetSouth] =
398 QVector3D(sinPhiSouth, cosPhiSouth * cosTheta, -cosPhiSouth * sinTheta);
399
400 ++vHemiOffsetNorth;
401 ++vHemiOffsetSouth;
402 ++vnHemiOffsetSouth;
403
404 uint32_t jNextVt = j + 1;
405 uint32_t jNextV = jNextVt % verifLons;
406
407 // North coordinate indices.
408 uint32_t vn00 = vCurrLatN + j;
409 uint32_t vn01 = vNextLatN + j;
410 uint32_t vn11 = vNextLatN + jNextV;
411 uint32_t vn10 = vCurrLatN + jNextV;
412
413 // South coordinate indices.
414 uint32_t vs00 = vCurrLatS + j;
415 uint32_t vs01 = vNextLatS + j;
416 uint32_t vs11 = vNextLatS + jNextV;
417 uint32_t vs10 = vCurrLatS + jNextV;
418
419 // North texture coordinate indices.
420 uint32_t vtn00 = vtCurrLatN + j;
421 uint32_t vtn01 = vtNextLatN + j;
422 uint32_t vtn11 = vtNextLatN + jNextVt;
423 uint32_t vtn10 = vtCurrLatN + jNextVt;
424
425 // South texture coordinate indices.
426 uint32_t vts00 = vtCurrLatS + j;
427 uint32_t vts01 = vtNextLatS + j;
428 uint32_t vts11 = vtNextLatS + jNextVt;
429 uint32_t vts10 = vtCurrLatS + jNextVt;
430
431 // North normal indices.
432 uint32_t vnn00 = vnCurrLatN + j;
433 uint32_t vnn01 = vnNextLatN + j;
434 uint32_t vnn11 = vnNextLatN + jNextV;
435 uint32_t vnn10 = vnCurrLatN + jNextV;
436
437 // South normal indices.
438 uint32_t vns00 = vnCurrLatS + j;
439 uint32_t vns01 = vnNextLatS + j;
440 uint32_t vns11 = vnNextLatS + jNextV;
441 uint32_t vns10 = vnCurrLatS + jNextV;
442
443 // North triangles.
444 faces[fHemiOffsetNorth] = { Face { vn00, vtn00, vnn00 }, Face { vn11, vtn11, vnn11 },
445 Face { vn10, vtn10, vnn10 } };
446
447 faces[fHemiOffsetNorth + 1] = { Face { vn00, vtn00, vnn00 },
448 Face { vn01, vtn01, vnn01 },
449 Face { vn11, vtn11, vnn11 } };
450
451 // South triangles.
452 faces[fHemiOffsetSouth] = { Face { vs00, vts00, vns00 }, Face { vs11, vts11, vns11 },
453 Face { vs10, vts10, vns10 } };
454
455 faces[fHemiOffsetSouth + 1] = { Face { vs00, vts00, vns00 },
456 Face { vs01, vts01, vns01 },
457 Face { vs11, vts11, vns11 } };
458
459 fHemiOffsetNorth += 2;
460 fHemiOffsetSouth += 2;
461 }
462
463 // For UVs, linear interpolation from North pole to
464 // North aspect ratio; and from South pole to South
465 // aspect ratio.
466 float tTexFac = ip1f * toTexVertical;
467 float tTexNorth = 1.f - tTexFac + tTexFac * vtAspectNorth;
468 float tTexSouth = vtAspectSouth * (1.f - tTexFac);
469
470 // Texture coordinates.
471 for (uint32_t j = 0; j < verifLonsp1; ++j) {
472 float sTex = sTexCache[j];
473
474 vertexTextures[vtHemiOffsetNorth] = QVector2D(sTex, tTexNorth);
475 vertexTextures[vtHemiOffsetSouth] = QVector2D(sTex, tTexSouth);
476
477 ++vtHemiOffsetNorth;
478 ++vtHemiOffsetSouth;
479 }
480 }
481
482 // Calculate sections of cylinder in middle.
483 if (calcMiddle) {
484
485 // Linear interpolation must exclude the origin (North equator)
486 // and the destination (South equator), so step must never equal
487 // 0.0 or 1.0 .
488 float toFac = 1.f / verifRingsp1;
489 uint32_t vCylOffset = idxVCyl;
490 uint32_t vtCylOffset = idxVtCyl;
491 for (uint32_t m = 1; m < verifRingsp1; ++m) {
492 float fac = m * toFac;
493 float cmplFac = 1.f - fac;
494
495 // Coordinates.
496 for (uint32_t j = 0; j < verifLons; ++j) {
497 QVector3D vEquatorNorth = vertices[idxVNEquator + j];
498 QVector3D vEquatorSouth = vertices[idxVSEquator + j];
499
500 // xy should be the same for both North and South.
501 // North z should equal half_depth while South z
502 // should equal -half_depth. However this is kept as
503 // a linear interpolation for clarity.
504 vertices[vCylOffset] =
505 QVector3D(cmplFac * vEquatorNorth.x() + fac * vEquatorSouth.x(),
506 cmplFac * vEquatorNorth.y() + fac * vEquatorSouth.y(),
507 cmplFac * vEquatorNorth.z() + fac * vEquatorSouth.z());
508
509 ++vCylOffset;
510 }
511
512 // Texture coordinates.
513 float tTex = cmplFac * vtAspectNorth + fac * vtAspectSouth;
514 for (uint32_t j = 0; j < verifLonsp1; ++j) {
515 float sTex = sTexCache[j];
516 vertexTextures[vtCylOffset] = QVector2D(sTex, tTex);
517 ++vtCylOffset;
518 }
519 }
520 }
521
522 // Cylinder face indices.
523 uint32_t fCylOffset = idxFsCyl;
524 for (uint32_t m = 0; m < verifRingsp1; ++m) {
525 uint32_t vCurrRing = idxVNEquator + m * verifLons;
526 uint32_t vNextRing = vCurrRing + verifLons;
527
528 uint32_t vtCurrRing = idxVtNEquator + m * verifLonsp1;
529 uint32_t vtNextRing = vtCurrRing + verifLonsp1;
530
531 for (uint32_t j = 0; j < verifLons; ++j) {
532 uint32_t jNextVt = j + 1;
533 uint32_t jNextV = jNextVt % verifLons;
534
535 // Coordinate corners.
536 uint32_t v00 = vCurrRing + j;
537 uint32_t v01 = vNextRing + j;
538 uint32_t v11 = vNextRing + jNextV;
539 uint32_t v10 = vCurrRing + jNextV;
540
541 // Texture coordinate corners.
542 uint32_t vt00 = vtCurrRing + j;
543 uint32_t vt01 = vtNextRing + j;
544 uint32_t vt11 = vtNextRing + jNextVt;
545 uint32_t vt10 = vtCurrRing + jNextVt;
546
547 // Normal corners.
548 uint32_t vn0 = idxVNEquator + j;
549 uint32_t vn1 = idxVNEquator + jNextV;
550
551 faces[fCylOffset] = { Face { v00, vt00, vn0 }, Face { v11, vt11, vn1 },
552 Face { v10, vt10, vn1 } };
553
554 faces[fCylOffset + 1] = { Face { v00, vt00, vn0 }, Face { v01, vt01, vn0 },
555 Face { v11, vt11, vn1 } };
556
557 fCylOffset += 2;
558 }
559 }
560
561 uint32_t stride = 3 * sizeof(float);
562 uint32_t strideNormal = 0;
563 uint32_t strideUV = 0;
564
565 if (m_enableNormals) {
566 strideNormal = stride;
567 stride += 3 * sizeof(float);
568 }
569 if (m_enableUV) {
570 strideUV = stride;
571 stride += 2 * sizeof(float);
572 }
573
574 QByteArray vertexData(vertices.length() * stride, Qt::Initialization::Uninitialized);
575 QByteArray indexData(faces.length() * 3 * sizeof(quint32), Qt::Initialization::Uninitialized);
576
577 const auto getVertexPtr = [&](const int vertexIdx) {
578 return reinterpret_cast<QVector3D *>(vertexData.data() + stride * vertexIdx);
579 };
580 const auto getNormalPtr = [&](const int vertexIdx) {
581 return reinterpret_cast<QVector3D *>(vertexData.data() + stride * vertexIdx + strideNormal);
582 };
583 const auto getTexturePtr = [&](const int vertexIdx) {
584 return reinterpret_cast<QVector2D *>(vertexData.data() + stride * vertexIdx + strideUV);
585 };
586
587 uint32_t *indexPtr = reinterpret_cast<uint32_t *>(indexData.data());
588
589 for (qsizetype i = 0; i < vertices.length(); i++) {
590 *getVertexPtr(i) = vertices[i];
591 }
592
593 for (qsizetype i = 0; i < faces.length(); i++) {
594 const auto vertexIndices =
595 std::array<uint32_t, 3> { faces[i][0].vertexIdx, faces[i][1].vertexIdx,
596 faces[i][2].vertexIdx };
597 *indexPtr = vertexIndices[0];
598 indexPtr++;
599 *indexPtr = vertexIndices[1];
600 indexPtr++;
601 *indexPtr = vertexIndices[2];
602 indexPtr++;
603
604 if (m_enableNormals) {
605 const auto normalIndices =
606 std::array<uint32_t, 3> { faces[i][0].normalIdx, faces[i][1].normalIdx,
607 faces[i][2].normalIdx };
608 *getNormalPtr(vertexIndices[0]) = vertexNormals[normalIndices[0]];
609 *getNormalPtr(vertexIndices[1]) = vertexNormals[normalIndices[1]];
610 *getNormalPtr(vertexIndices[2]) = vertexNormals[normalIndices[2]];
611 }
612
613 if (m_enableUV) {
614 const auto textureIndices =
615 std::array<uint32_t, 3> { faces[i][0].textureIdx, faces[i][1].textureIdx,
616 faces[i][2].textureIdx };
617 *getTexturePtr(vertexIndices[0]) = vertexTextures[textureIndices[0]];
618 *getTexturePtr(vertexIndices[1]) = vertexTextures[textureIndices[1]];
619 *getTexturePtr(vertexIndices[2]) = vertexTextures[textureIndices[2]];
620 }
621 }
622
623 addAttribute(QQuick3DGeometry::Attribute::PositionSemantic, 0,
624 QQuick3DGeometry::Attribute::ComponentType::F32Type);
625 if (m_enableNormals) {
626 addAttribute(QQuick3DGeometry::Attribute::NormalSemantic, strideNormal,
627 QQuick3DGeometry::Attribute::ComponentType::F32Type);
628 }
629 if (m_enableUV) {
630 addAttribute(QQuick3DGeometry::Attribute::TexCoordSemantic, strideUV,
631 QQuick3DGeometry::Attribute::ComponentType::F32Type);
632 }
633 addAttribute(QQuick3DGeometry::Attribute::IndexSemantic, 0,
634 QQuick3DGeometry::Attribute::ComponentType::U32Type);
635
636 setStride(stride);
637 setVertexData(vertexData);
638 setIndexData(indexData);
639
640 setBounds(QVector3D(-radius - 0.5f * m_height, -radius, -radius),
641 QVector3D(radius + 0.5f * m_height, radius, radius));
642}
643
644QT_END_NAMESPACE
Combined button and popup list for selecting options.
uint32_t normalIdx
uint32_t vertexIdx
uint32_t textureIdx