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