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