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

Provided by KDAB

Privacy Policy
Learn Advanced QML with KDAB
Find out more

source code of qtquick3dphysics/src/helpers/qcapsulegeometry.cpp