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
capsulegeometry.cpp
Go to the documentation of this file.
1// Copyright (C) 2025 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#if QT_CONFIG(concurrent)
10#include <QtConcurrentRun>
11#endif
12#include <QQuaternion>
13
14#include <cmath>
15
16QT_BEGIN_NAMESPACE
17
18/*!
19 \qmltype CapsuleGeometry
20 \inqmlmodule QtQuick3D.Helpers
21 \inherits Geometry
22 \since 6.10
23 \brief Provides geometry for a capsule.
24
25 A geometry for generating a capsule model. The capsule is centered
26 at \c{(0, 0, 0)} with the height of the capsule extending in the x
27 direction and the diameter on the yz plane.
28*/
29
30/*! \qmlproperty bool CapsuleGeometry::enableNormals
31 \default true
32
33 Generate mesh face normals.
34*/
35
36/*! \qmlproperty bool CapsuleGeometry::enableUV
37 \default false
38
39 Generate mesh uv coordinates.
40*/
41
42/*! \qmlproperty int CapsuleGeometry::longitudes
43 \default 32
44
45 Number of longitudes, or meridians, distributed by azimuth.
46*/
47
48/*! \qmlproperty int CapsuleGeometry::latitudes
49 \default 16
50
51 Number of latitudes, distributed by inclination. Will always be snapped to an even number.
52*/
53
54/*! \qmlproperty int CapsuleGeometry::rings
55 \default 1
56
57 Number of sections in cylinder between hemispheres.
58*/
59
60/*! \qmlproperty real CapsuleGeometry::height
61 \default 100
62
63 Height of the middle cylinder on the x axis, excluding the hemispheres.
64*/
65
66/*! \qmlproperty real CapsuleGeometry::diameter
67 \default 100
68
69 Diameter on the yz plane.
70*/
71
72/*!
73 \qmlproperty UVProfile CapsuleGeometry::uvProfile
74 \default CapsuleGeometry.Fixed
75
76 Manner in which UV coordinates are distributed along the length of the capsule.
77
78 \value CapsuleGeometry.Fixed The upper third of the UV texture is the North
79 hemisphere, the middle third is the cylinder and the last third is the
80 South hemisphere.
81 \value CapsuleGeometry.Aspect UVs match the height to radius ratio.
82 \value CapsuleGeometry.Uniform Uniform proportion for all UV cells,
83 according to the ratio of latitudes to rings.
84*/
85
86/*!
87 \qmlproperty bool CapsuleGeometry::asynchronous
88 \default true
89
90 This property holds whether the geometry generation should be asynchronous.
91*/
92
93/*!
94 \qmlproperty bool CapsuleGeometry::status
95 \readonly
96
97 This property holds the status of the geometry generation when asynchronous is true.
98
99 \value CapsuleGeometry.Null The geometry generation has not started
100 \value CapsuleGeometry.Ready The geometry generation is complete.
101 \value CapsuleGeometry.Loading The geometry generation is in progress.
102 \value CapsuleGeometry.Error The geometry generation failed.
103*/
104
105CapsuleGeometry::CapsuleGeometry(QQuick3DObject *parent) : QQuick3DGeometry(parent)
106{
107#if QT_CONFIG(concurrent)
108 connect(&m_geometryDataWatcher, &QFutureWatcher<GeometryData>::finished, this, &CapsuleGeometry::requestFinished);
109#endif
110 scheduleGeometryUpdate();
111}
112
113CapsuleGeometry::~CapsuleGeometry() = default;
114
115void CapsuleGeometry::setEnableNormals(bool enable)
116{
117 if (m_enableNormals == enable)
118 return;
119
120 m_enableNormals = enable;
121 emit enableNormalsChanged();
122 scheduleGeometryUpdate();
123}
124
125void CapsuleGeometry::setEnableUV(bool enable)
126{
127 if (m_enableUV == enable)
128 return;
129
130 m_enableUV = enable;
131 emit enableUVChanged();
132 scheduleGeometryUpdate();
133}
134
135void CapsuleGeometry::setLongitudes(int longitudes)
136{
137 if (m_longitudes == longitudes)
138 return;
139
140 m_longitudes = longitudes;
141 emit longitudesChanged();
142 scheduleGeometryUpdate();
143}
144
145void CapsuleGeometry::setLatitudes(int latitudes)
146{
147 if (m_latitudes == latitudes)
148 return;
149
150 m_latitudes = latitudes;
151 emit latitudesChanged();
152 scheduleGeometryUpdate();
153}
154
155void CapsuleGeometry::setRings(int rings)
156{
157 if (m_rings == rings)
158 return;
159
160 m_rings = rings;
161 emit ringsChanged();
162 scheduleGeometryUpdate();
163}
164
165void CapsuleGeometry::setHeight(float height)
166{
167 if (m_height == height)
168 return;
169
170 m_height = height;
171 emit heightChanged();
172 scheduleGeometryUpdate();
173}
174
175void CapsuleGeometry::setDiameter(float diameter)
176{
177 if (m_diameter == diameter)
178 return;
179
180 m_diameter = diameter;
181 emit diameterChanged();
182 scheduleGeometryUpdate();
183}
184
185CapsuleGeometry::UVProfile CapsuleGeometry::uvProfile() const
186{
187 return m_uvProfile;
188}
189
190void CapsuleGeometry::setUVProfile(UVProfile newUVProfile)
191{
192 if (m_uvProfile == newUVProfile)
193 return;
194 m_uvProfile = newUVProfile;
195 emit uvProfileChanged();
196 scheduleGeometryUpdate();
197}
198
199bool CapsuleGeometry::asynchronous() const
200{
201 return m_asynchronous;
202}
203
204void CapsuleGeometry::setAsynchronous(bool newAsynchronous)
205{
206 if (m_asynchronous == newAsynchronous)
207 return;
208 m_asynchronous = newAsynchronous;
209 emit asynchronousChanged();
210}
211
212CapsuleGeometry::Status CapsuleGeometry::status() const
213{
214 return m_status;
215}
216
217void CapsuleGeometry::doUpdateGeometry()
218{
219 // reset the flag since we are processing the update
220 m_geometryUpdateRequested = false;
221
222#if QT_CONFIG(concurrent)
223 if (m_geometryDataFuture.isRunning()) {
224 m_pendingAsyncUpdate = true;
225 return;
226 }
227#endif
228
229#if QT_CONFIG(concurrent)
230 if (m_asynchronous) {
231 m_geometryDataFuture = QtConcurrent::run(generateCapsuleGeometryAsync,
232 m_enableNormals,
233 m_enableUV,
234 m_longitudes,
235 m_latitudes,
236 m_rings,
237 m_height,
238 m_diameter,
239 m_uvProfile);
240 m_geometryDataWatcher.setFuture(m_geometryDataFuture);
241 m_status = Status::Loading;
242 Q_EMIT statusChanged();
243 } else {
244#else
245 {
246#endif // QT_CONFIG(concurrent)
247 updateGeometry(generateCapsuleGeometry(m_enableNormals, m_enableUV, m_longitudes, m_latitudes, m_rings, m_height, m_diameter, m_uvProfile));
248 }
249}
250
251void CapsuleGeometry::requestFinished()
252{
253#if QT_CONFIG(concurrent)
254 const auto output = m_geometryDataFuture.takeResult();
255 updateGeometry(output);
256#endif
257}
258
259void CapsuleGeometry::scheduleGeometryUpdate()
260{
261 if (!m_geometryUpdateRequested) {
262 QMetaObject::invokeMethod(this, "doUpdateGeometry", Qt::QueuedConnection);
263 m_geometryUpdateRequested = true;
264 }
265}
266
267void CapsuleGeometry::updateGeometry(const GeometryData &geometryData)
268{
269 clear();
270 setStride(geometryData.stride);
271 setPrimitiveType(QQuick3DGeometry::PrimitiveType::Triangles);
272 addAttribute(QQuick3DGeometry::Attribute::PositionSemantic, 0, QQuick3DGeometry::Attribute::ComponentType::F32Type);
273 if (geometryData.enableNormals) {
274 addAttribute(QQuick3DGeometry::Attribute::NormalSemantic,
275 geometryData.strideNormal,
276 QQuick3DGeometry::Attribute::ComponentType::F32Type);
277 }
278 if (geometryData.enableUV) {
279 addAttribute(QQuick3DGeometry::Attribute::TexCoordSemantic, geometryData.strideUV, QQuick3DGeometry::Attribute::ComponentType::F32Type);
280 }
281 addAttribute(QQuick3DGeometry::Attribute::IndexSemantic, 0, QQuick3DGeometry::Attribute::ComponentType::U32Type);
282
283 setBounds(geometryData.boundsMin, geometryData.boundsMax);
284 setVertexData(geometryData.vertexData);
285 setIndexData(geometryData.indexData);
286
287 // If the geometry update was requested while the geometry was being generated asynchronously,
288 // we need to schedule another geometry update now that the geometry is ready.
289 if (m_pendingAsyncUpdate) {
290 m_pendingAsyncUpdate = false;
291 scheduleGeometryUpdate();
292 } else {
293 m_status = Status::Ready;
294 Q_EMIT statusChanged();
295 }
296 update();
297}
298
299CapsuleGeometry::GeometryData CapsuleGeometry::generateCapsuleGeometry(bool enableNormals,
300 bool enableUV,
301 int longitudes,
302 int latitudes,
303 int rings,
304 float height,
305 float diameter,
306 UVProfile uvProfile)
307{
308 longitudes = qMax(3, longitudes);
309 latitudes = qMax(2, latitudes + (latitudes % 2)); // make even
310 rings = qMax(1, rings);
311 height = qMax(0.00001f, height);
312 diameter = qMax(0.00001f, diameter);
313
314 const UVProfile profile = uvProfile;
315 const float radius = diameter / 2;
316 const float depth = height;
317
318 bool calcMiddle = rings > 0;
319 int halfLats = latitudes / 2;
320 int halfLatsn1 = halfLats - 1;
321 int halfLatsn2 = halfLats - 2;
322 int ringsp1 = rings + 1;
323 int lonsp1 = longitudes + 1;
324 float halfDepth = depth * 0.5f;
325 float summit = halfDepth + radius;
326
327 // Vertex index offsets.
328 int vertOffsetNorthHemi = longitudes;
329 int vertOffsetNorthEquator = vertOffsetNorthHemi + lonsp1 * halfLatsn1;
330 int vertOffsetCylinder = vertOffsetNorthEquator + lonsp1;
331 int vertOffsetSouthEquator = calcMiddle ?
332 vertOffsetCylinder + lonsp1 * rings :
333 vertOffsetCylinder;
334 int vertOffsetSouthHemi = vertOffsetSouthEquator + lonsp1;
335 int vertOffsetSouthPolar = vertOffsetSouthHemi + lonsp1 * halfLatsn2;
336 int vertOffsetSouthCap = vertOffsetSouthPolar + lonsp1;
337
338 // Initialize arrays.
339 int vertLen = vertOffsetSouthCap + longitudes;
340 QList<QVector3D> vs = QList<QVector3D>(vertLen);
341 QList<QVector2D> vts = QList<QVector2D>(vertLen);
342 QList<QVector3D> vns = QList<QVector3D>(vertLen);
343
344 float toTheta = 2.0f * M_PI / longitudes;
345 float toPhi = M_PI / latitudes;
346 float toTexHorizontal = 1.0f / longitudes;
347 float toTexVertical = 1.0f / halfLats;
348
349 // Calculate positions for texture coordinates vertical.
350 float vtAspectRatio = 1.0f;
351 switch (profile)
352 {
353 case UVProfile::Aspect:
354 vtAspectRatio = radius / (depth + radius + radius);
355 break;
356
357 case UVProfile::Uniform:
358 vtAspectRatio = (float) halfLats / (ringsp1 + latitudes);
359 break;
360
361 case UVProfile::Fixed:
362 default:
363 vtAspectRatio = 1.0f / 3.0f;
364 break;
365 }
366
367 float vtAspectNorth = 1.0f - vtAspectRatio;
368 float vtAspectSouth = vtAspectRatio;
369
370 QList<QVector2D> thetaCartesian = QList<QVector2D>(longitudes);
371 QList<QVector2D> rhoThetaCartesian = QList<QVector2D>(longitudes);
372 QList<float> sTextureCache = QList<float>(lonsp1);
373
374 // Polar vertices.
375 for (int j = 0; j < longitudes; ++j)
376 {
377 float jf = j;
378 float sTexturePolar = 1.0f - ((jf + 0.5f) * toTexHorizontal);
379 float theta = jf * toTheta;
380
381 float cosTheta = std::cos(theta);
382 float sinTheta = std::sin(theta);
383
384 thetaCartesian[j] = QVector2D(cosTheta, sinTheta);
385 rhoThetaCartesian[j] = QVector2D(
386 radius * cosTheta,
387 radius * sinTheta);
388
389 // North.
390 vs[j] = QVector3D(0.0f, summit, 0.0f);
391 vts[j] = QVector2D(sTexturePolar, 1.0f);
392 vns[j] = QVector3D(0.0f, 1.0f, 0.0f);
393
394 // South.
395 int idx = vertOffsetSouthCap + j;
396 vs[idx] = QVector3D(0.0f, -summit, 0.0f);
397 vts[idx] = QVector2D(sTexturePolar, 0.0f);
398 vns[idx] = QVector3D(0.0f, -1.0f, 0.0f);
399 }
400
401 // Equatorial vertices.
402 for (int j = 0; j < lonsp1; ++j)
403 {
404 float sTexture = 1.0f - j * toTexHorizontal;
405 sTextureCache[j] = sTexture;
406
407 // Wrap to first element upon reaching last.
408 int jMod = j % longitudes;
409 QVector2D tc = thetaCartesian[jMod];
410 QVector2D rtc = rhoThetaCartesian[jMod];
411
412 // North equator.
413 int idxn = vertOffsetNorthEquator + j;
414 vs[idxn] = QVector3D(rtc.x(), halfDepth, -rtc.y());
415 vts[idxn] = QVector2D(sTexture, vtAspectNorth);
416 vns[idxn] = QVector3D(tc.x(), 0.0f, -tc.y());
417
418 // South equator.
419 int idxs = vertOffsetSouthEquator + j;
420 vs[idxs] = QVector3D(rtc.x(), -halfDepth, -rtc.y());
421 vts[idxs] = QVector2D(sTexture, vtAspectSouth);
422 vns[idxs] = QVector3D(tc.x(), 0.0f, -tc.y());
423 }
424
425 // Hemisphere vertices.
426 for (int i = 0; i < halfLatsn1; ++i)
427 {
428 float ip1f = i + 1.0f;
429 float phi = ip1f * toPhi;
430
431 // For coordinates.
432 float cosPhiSouth = std::cos(phi);
433 float sinPhiSouth = std::sin(phi);
434
435 // Symmetrical hemispheres mean cosine and sine only needs
436 // to be calculated once.
437 float cosPhiNorth = sinPhiSouth;
438 float sinPhiNorth = -cosPhiSouth;
439
440 float rhoCosPhiNorth = radius * cosPhiNorth;
441 float rhoSinPhiNorth = radius * sinPhiNorth;
442 float zOffsetNorth = halfDepth - rhoSinPhiNorth;
443
444 float rhoCosPhiSouth = radius * cosPhiSouth;
445 float rhoSinPhiSouth = radius * sinPhiSouth;
446 float zOffsetSouth = -halfDepth - rhoSinPhiSouth;
447
448 // For texture coordinates.
449 float tTexFac = ip1f * toTexVertical;
450 float cmplTexFac = 1.0f - tTexFac;
451 float tTexNorth = cmplTexFac + vtAspectNorth * tTexFac;
452 float tTexSouth = cmplTexFac * vtAspectSouth;
453
454 int iLonsp1 = i * lonsp1;
455 int vertCurrLatNorth = vertOffsetNorthHemi + iLonsp1;
456 int vertCurrLatSouth = vertOffsetSouthHemi + iLonsp1;
457
458 for (int j = 0; j < lonsp1; ++j)
459 {
460 int jMod = j % longitudes;
461
462 float sTexture = sTextureCache[j];
463 QVector2D tc = thetaCartesian[jMod];
464
465 // North hemisphere.
466 int idxn = vertCurrLatNorth + j;
467 vs[idxn] = QVector3D(
468 rhoCosPhiNorth * tc.x(),
469 zOffsetNorth,
470 -rhoCosPhiNorth * tc.y());
471 vts[idxn] = QVector2D(sTexture, tTexNorth);
472 vns[idxn] = QVector3D(
473 cosPhiNorth * tc.x(),
474 -sinPhiNorth,
475 -cosPhiNorth * tc.y());
476
477 // South hemisphere.
478 int idxs = vertCurrLatSouth + j;
479 vs[idxs] = QVector3D(
480 rhoCosPhiSouth * tc.x(),
481 zOffsetSouth,
482 -rhoCosPhiSouth * tc.y());
483 vts[idxs] = QVector2D(sTexture, tTexSouth);
484 vns[idxs] = QVector3D(
485 cosPhiSouth * tc.x(),
486 -sinPhiSouth,
487 -cosPhiSouth * tc.y());
488 }
489 }
490
491 // Cylinder vertices.
492 if (calcMiddle)
493 {
494 // Exclude both origin and destination edges
495 // (North and South equators) from the interpolation.
496 float toFac = 1.0f / ringsp1;
497 int idxCylLat = vertOffsetCylinder;
498
499 for (int h = 1; h < ringsp1; ++h)
500 {
501 float fac = h * toFac;
502 float cmplFac = 1.0f - fac;
503 float tTexture = cmplFac * vtAspectNorth + fac * vtAspectSouth;
504 float z = halfDepth - depth * fac;
505
506 for (int j = 0; j < lonsp1; ++j)
507 {
508 int jMod = j % longitudes;
509 QVector2D tc = thetaCartesian[jMod];
510 QVector2D rtc = rhoThetaCartesian[jMod];
511 float sTexture = sTextureCache[j];
512
513 vs[idxCylLat] = QVector3D(rtc.x(), z, -rtc.y());
514 vts[idxCylLat] = QVector2D(sTexture, tTexture);
515 vns[idxCylLat] = QVector3D(tc.x(), 0.0f, -tc.y());
516
517 ++idxCylLat;
518 }
519 }
520 }
521
522 // Triangle indices.
523 // Stride is 3 for polar triangles;
524 // stride is 6 for two triangles forming a quad.
525 int lons3 = longitudes * 3;
526 int lons6 = longitudes * 6;
527 int hemiLons = halfLatsn1 * lons6;
528
529 int triOffsetNorthHemi = lons3;
530 int triOffsetCylinder = triOffsetNorthHemi + hemiLons;
531 int triOffsetSouthHemi = triOffsetCylinder + ringsp1 * lons6;
532 int triOffsetSouthCap = triOffsetSouthHemi + hemiLons;
533
534 int fsLen = triOffsetSouthCap + lons3;
535 QList<int> tris = QList<int>(fsLen);
536
537 // Polar caps.
538 for (int i = 0, k = 0, m = triOffsetSouthCap; i < longitudes; ++i, k += 3, m += 3)
539 {
540 // North.
541 tris[k] = i;
542 tris[k + 1] = vertOffsetNorthHemi + i;
543 tris[k + 2] = vertOffsetNorthHemi + i + 1;
544
545 // South.
546 tris[m] = vertOffsetSouthCap + i;
547 tris[m + 1] = vertOffsetSouthPolar + i + 1;
548 tris[m + 2] = vertOffsetSouthPolar + i;
549 }
550
551 // Hemispheres.
552 for (int i = 0, k = triOffsetNorthHemi, m = triOffsetSouthHemi; i < halfLatsn1; ++i)
553 {
554 int iLonsp1 = i * lonsp1;
555
556 int vertCurrLatNorth = vertOffsetNorthHemi + iLonsp1;
557 int vertNextLatNorth = vertCurrLatNorth + lonsp1;
558
559 int vertCurrLatSouth = vertOffsetSouthEquator + iLonsp1;
560 int vertNextLatSouth = vertCurrLatSouth + lonsp1;
561
562 for (int j = 0; j < longitudes; ++j, k += 6, m += 6)
563 {
564 // North.
565 int north00 = vertCurrLatNorth + j;
566 int north01 = vertNextLatNorth + j;
567 int north11 = vertNextLatNorth + j + 1;
568 int north10 = vertCurrLatNorth + j + 1;
569
570 tris[k] = north00;
571 tris[k + 1] = north11;
572 tris[k + 2] = north10;
573
574 tris[k + 3] = north00;
575 tris[k + 4] = north01;
576 tris[k + 5] = north11;
577
578 // South.
579 int south00 = vertCurrLatSouth + j;
580 int south01 = vertNextLatSouth + j;
581 int south11 = vertNextLatSouth + j + 1;
582 int south10 = vertCurrLatSouth + j + 1;
583
584 tris[m] = south00;
585 tris[m + 1] = south11;
586 tris[m + 2] = south10;
587
588 tris[m + 3] = south00;
589 tris[m + 4] = south01;
590 tris[m + 5] = south11;
591 }
592 }
593
594 // Cylinder.
595 for (int i = 0, k = triOffsetCylinder; i < ringsp1; ++i)
596 {
597 int vertCurrLat = vertOffsetNorthEquator + i * lonsp1;
598 int vertNextLat = vertCurrLat + lonsp1;
599
600 for (int j = 0; j < longitudes; ++j, k += 6)
601 {
602 int cy00 = vertCurrLat + j;
603 int cy01 = vertNextLat + j;
604 int cy11 = vertNextLat + j + 1;
605 int cy10 = vertCurrLat + j + 1;
606
607 tris[k] = cy00;
608 tris[k + 1] = cy11;
609 tris[k + 2] = cy10;
610
611 tris[k + 3] = cy00;
612 tris[k + 4] = cy01;
613 tris[k + 5] = cy11;
614 }
615 }
616
617 auto vertices = vs;
618 auto vertexTextures = vts;
619 auto vertexNormals = vns;
620
621 uint32_t stride = 3 * sizeof(float);
622 uint32_t strideNormal = 0;
623 uint32_t strideUV = 0;
624
625 if (enableNormals) {
626 strideNormal = stride;
627 stride += 3 * sizeof(float);
628 }
629 if (enableUV) {
630 strideUV = stride;
631 stride += 2 * sizeof(float);
632 }
633
634 QByteArray vertexData(vertices.length() * stride, Qt::Initialization::Uninitialized);
635 QByteArray indexData(tris.length() * sizeof(int), Qt::Initialization::Uninitialized);
636
637 const auto getVertexPtr = [&](const int vertexIdx) {
638 return reinterpret_cast<QVector3D *>(vertexData.data() + stride * vertexIdx);
639 };
640 const auto getNormalPtr = [&](const int vertexIdx) {
641 return reinterpret_cast<QVector3D *>(vertexData.data() + stride * vertexIdx + strideNormal);
642 };
643 const auto getTexturePtr = [&](const int vertexIdx) {
644 return reinterpret_cast<QVector2D *>(vertexData.data() + stride * vertexIdx + strideUV);
645 };
646
647 const QQuaternion rotateZ = QQuaternion::fromEulerAngles(0, 0, 90);
648 uint32_t *indexPtr = reinterpret_cast<uint32_t *>(indexData.data());
649
650 for (qsizetype i = 0; i < vertices.length(); i++) {
651 *getVertexPtr(i) = rotateZ * vertices[i];
652 }
653
654 for (qsizetype i = 0; i < tris.length() / 3; i++) {
655 std::array<int, 3> triIndices = { tris[i * 3], tris[i * 3 + 1], tris[i * 3 + 2] };
656 *indexPtr = triIndices[0];
657 indexPtr++;
658 *indexPtr = triIndices[1];
659 indexPtr++;
660 *indexPtr = triIndices[2];
661 indexPtr++;
662
663 if (enableNormals) {
664 *getNormalPtr(triIndices[0]) = rotateZ * vertexNormals[triIndices[0]];
665 *getNormalPtr(triIndices[1]) = rotateZ * vertexNormals[triIndices[1]];
666 *getNormalPtr(triIndices[2]) = rotateZ * vertexNormals[triIndices[2]];
667 }
668
669 if (enableUV) {
670 *getTexturePtr(triIndices[0]) = vertexTextures[triIndices[0]];
671 *getTexturePtr(triIndices[1]) = vertexTextures[triIndices[1]];
672 *getTexturePtr(triIndices[2]) = vertexTextures[triIndices[2]];
673 }
674 }
675
676 GeometryData geometryData;
677 geometryData.indexData = indexData;
678 geometryData.vertexData = vertexData;
679 geometryData.boundsMin = QVector3D(-radius - halfDepth, -radius, -radius);
680 geometryData.boundsMax = QVector3D(radius + halfDepth, radius, radius);
681 geometryData.stride = stride;
682 geometryData.strideNormal = strideNormal;
683 geometryData.strideUV = strideUV;
684 geometryData.enableNormals = enableNormals;
685 geometryData.enableUV = enableUV;
686 return geometryData;
687}
688
689#if QT_CONFIG(concurrent)
690void CapsuleGeometry::generateCapsuleGeometryAsync(QPromise<CapsuleGeometry::GeometryData> &promise,
691 bool enableNormals,
692 bool enableUV,
693 int longitudes,
694 int latitudes,
695 int rings,
696 float height,
697 float diameter,
698 CapsuleGeometry::UVProfile uvProfile)
699{
700 auto output = generateCapsuleGeometry(enableNormals, enableUV, longitudes, latitudes, rings, height, diameter, uvProfile);
701 promise.addResult(output);
702}
703#endif
704
705QT_END_NAMESPACE
#define M_PI
Definition qmath.h:200