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