15
16
17
18
19
20
21
22
23
24
25
28
29
30
31
34
35
36
37
40
41
42
43
46
47
48
49
52
53
54
55
58
59
60
61
64
65
66
67
69CapsuleGeometryPhysics::CapsuleGeometryPhysics()
74void CapsuleGeometryPhysics::setEnableNormals(
bool enable)
76 if (m_enableNormals == enable)
79 m_enableNormals = enable;
80 emit enableNormalsChanged();
85void CapsuleGeometryPhysics::setEnableUV(
bool enable)
87 if (m_enableUV == enable)
91 emit enableUVChanged();
96void CapsuleGeometryPhysics::setLongitudes(
int longitudes)
98 if (m_longitudes == longitudes)
101 m_longitudes = longitudes;
102 emit longitudesChanged();
107void CapsuleGeometryPhysics::setLatitudes(
int latitudes)
109 if (m_latitudes == latitudes)
112 m_latitudes = latitudes;
113 emit latitudesChanged();
118void CapsuleGeometryPhysics::setRings(
int rings)
120 if (m_rings == rings)
129void CapsuleGeometryPhysics::setHeight(
float height)
131 if (m_height == height)
135 emit heightChanged();
140void CapsuleGeometryPhysics::setDiameter(
float diameter)
142 if (m_diameter == diameter)
145 m_diameter = diameter;
146 emit diameterChanged();
161void CapsuleGeometryPhysics::updateData()
165 constexpr float EPSILON = 0.001f;
166 const float radius = m_diameter * 0.5f;
169 int verifLats = qMax(2, m_latitudes);
170 if (verifLats % 2 != 0) {
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);
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;
193 uint32_t idxVNEquator = verifLonsp1 + verifLons * halfLatsn2;
194 uint32_t idxVCyl = idxVNEquator + verifLons;
195 uint32_t idxVSEquator = idxVCyl;
197 idxVSEquator += verifLons * verifRings;
199 uint32_t idxVSouth = idxVSEquator + verifLons;
200 uint32_t idxVSouthCap = idxVSouth + verifLons * halfLatsn2;
201 uint32_t idxVSouthPole = idxVSouthCap + verifLons;
204 uint32_t idxVtNEquator = verifLons + verifLonsp1 * halfLatsn1;
205 uint32_t idxVtCyl = idxVtNEquator + verifLonsp1;
206 uint32_t idxVtSEquator = idxVtCyl;
208 idxVtSEquator += verifLonsp1 * verifRings;
210 uint32_t idxVtSHemi = idxVtSEquator + verifLonsp1;
211 uint32_t idxVtSPolar = idxVtSHemi + verifLonsp1 * halfLatsn2;
212 uint32_t idxVtSCap = idxVtSPolar + verifLonsp1;
215 uint32_t idxVnSouth = idxVNEquator + verifLons;
216 uint32_t idxVnSouthCap = idxVnSouth + verifLons * halfLatsn2;
217 uint32_t idxVnSouthPole = idxVnSouthCap + verifLons;
220 uint32_t idxFsCyl = verifLons + lonsHalfLatn1 * 2;
221 uint32_t idxFsSouthEquat = idxFsCyl + lonsRingsp1 * 2;
222 uint32_t idxFsSouthHemi = idxFsSouthEquat + lonsHalfLatn1 * 2;
225 uint32_t verticesLen = idxVSouthPole + 1;
226 uint32_t texturesLen = idxVtSCap + verifLons;
227 uint32_t normalsLen = idxVnSouthPole + 1;
228 uint32_t facesLen = idxFsSouthHemi + verifLons;
231 auto vertices = QList<QVector3D>(verticesLen);
232 auto vertexTextures = QList<QVector2D>(texturesLen);
233 auto vertexNormals = QList<QVector3D>(normalsLen);
237 auto faces = QList<std::array<Face, 3>>(facesLen);
240 vertices[0] = QVector3D(-summit, 0.f, 0.f);
241 vertexNormals[0] = QVector3D(-1.f, 0.f, 0.f);
244 vertices[idxVSouthPole] = QVector3D(summit, 0.f, 0.f);
245 vertexNormals[idxVnSouthPole] = QVector3D(1.f, 0.f, 0.f);
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;
255 for (uint32_t j = 0; j < verifLons; ++j) {
258 float theta = j * toTheta;
259 float sinTheta = sin(theta);
260 float cosTheta = cos(theta);
261 sinThetaCache[j] = sinTheta;
262 cosThetaCache[j] = cosTheta;
265 float sTex = (j + 0.5f) * toTexHorizontal;
266 vertexTextures[j] = QVector2D(sTex, 1.f);
267 vertexTextures[idxVtSCap + j] = QVector2D(sTex, 0.f);
270 float x = verifRad * cosTheta;
271 float z = verifRad * sinTheta;
274 vertices[idxVNEquator + j] = QVector3D(-halfDepth, x, -z);
275 vertices[idxVSEquator + j] = QVector3D(halfDepth, x, -z);
278 vertexNormals[idxVNEquator + j] = QVector3D(0.f, cosTheta, -sinTheta);
281 uint32_t jNextVt = j + 1;
282 uint32_t jNextV = jNextVt % verifLons;
285 faces[j] = {
Face { 0, j, 0 },
Face { jNextVt, verifLons + j, jNextVt },
286 Face { 1 + jNextV, verifLons + jNextVt, 1 + jNextV } };
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 }
297 float vtAspectRatio = 0.f;
298 switch (m_uvProfile) {
299 case CapsuleGeometryPhysics::UvProfile::Fixed:
300 vtAspectRatio = 0.33333333f;
302 case CapsuleGeometryPhysics::UvProfile::Aspect:
303 vtAspectRatio = verifRad / (verifDepth + verifRad + verifRad);
305 case CapsuleGeometryPhysics::UvProfile::Uniform:
306 vtAspectRatio = (
float)halfLats / (verifRingsp1 + verifLats);
309 float vtAspectSouth = vtAspectRatio;
310 float vtAspectNorth = 1.f - vtAspectRatio;
313 QList<
float> sTexCache = QList<
float>(verifLonsp1);
316 for (uint32_t j = 0; j < verifLonsp1; ++j) {
317 float sTex = j * toTexHorizontal;
319 vertexTextures[idxVtNEquator + j] = QVector2D(sTex, vtAspectNorth);
320 vertexTextures[idxVtSEquator + j] = QVector2D(sTex, vtAspectSouth);
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;
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);
341 float cosPhiNorth = sinPhiSouth;
342 float sinPhiNorth = -cosPhiSouth;
345 float rhoCosPhiNorth = verifRad * cosPhiNorth;
346 float rhoSinPhiNorth = verifRad * sinPhiNorth;
347 float yOffsetNorth = halfDepth - rhoSinPhiNorth;
350 float rhoCosPhiSouth = verifRad * cosPhiSouth;
351 float rhoSinPhiSouth = verifRad * sinPhiSouth;
352 float yOffsetSouth = -halfDepth - rhoSinPhiSouth;
355 uint32_t vCurrLatN = 1 + iLonsCurr;
356 uint32_t vNextLatN = vCurrLatN + verifLons;
359 uint32_t vCurrLatS = idxVSEquator + iLonsCurr;
360 uint32_t vNextLatS = vCurrLatS + verifLons;
363 uint32_t vtCurrLatN = verifLons + i * verifLonsp1;
364 uint32_t vtNextLatN = vtCurrLatN + verifLonsp1;
367 uint32_t vtCurrLatS = idxVtSEquator + i * verifLonsp1;
368 uint32_t vtNextLatS = vtCurrLatS + verifLonsp1;
371 uint32_t vnCurrLatN = 1 + iLonsCurr;
372 uint32_t vnNextLatN = vnCurrLatN + verifLons;
375 uint32_t vnCurrLatS = idxVNEquator + iLonsCurr;
376 uint32_t vnNextLatS = vnCurrLatS + verifLons;
379 for (uint32_t j = 0; j < verifLons; ++j) {
380 float sinTheta = sinThetaCache[j];
381 float cosTheta = cosThetaCache[j];
384 vertices[vHemiOffsetNorth] =
385 QVector3D(-yOffsetNorth, rhoCosPhiNorth * cosTheta, -rhoCosPhiNorth * sinTheta);
388 vertexNormals[vHemiOffsetNorth] =
389 QVector3D(sinPhiNorth, cosPhiNorth * cosTheta, -cosPhiNorth * sinTheta);
392 vertices[vHemiOffsetSouth] =
393 QVector3D(-yOffsetSouth, rhoCosPhiSouth * cosTheta, -rhoCosPhiSouth * sinTheta);
396 vertexNormals[vnHemiOffsetSouth] =
397 QVector3D(sinPhiSouth, cosPhiSouth * cosTheta, -cosPhiSouth * sinTheta);
403 uint32_t jNextVt = j + 1;
404 uint32_t jNextV = jNextVt % verifLons;
407 uint32_t vn00 = vCurrLatN + j;
408 uint32_t vn01 = vNextLatN + j;
409 uint32_t vn11 = vNextLatN + jNextV;
410 uint32_t vn10 = vCurrLatN + jNextV;
413 uint32_t vs00 = vCurrLatS + j;
414 uint32_t vs01 = vNextLatS + j;
415 uint32_t vs11 = vNextLatS + jNextV;
416 uint32_t vs10 = vCurrLatS + jNextV;
419 uint32_t vtn00 = vtCurrLatN + j;
420 uint32_t vtn01 = vtNextLatN + j;
421 uint32_t vtn11 = vtNextLatN + jNextVt;
422 uint32_t vtn10 = vtCurrLatN + jNextVt;
425 uint32_t vts00 = vtCurrLatS + j;
426 uint32_t vts01 = vtNextLatS + j;
427 uint32_t vts11 = vtNextLatS + jNextVt;
428 uint32_t vts10 = vtCurrLatS + jNextVt;
431 uint32_t vnn00 = vnCurrLatN + j;
432 uint32_t vnn01 = vnNextLatN + j;
433 uint32_t vnn11 = vnNextLatN + jNextV;
434 uint32_t vnn10 = vnCurrLatN + jNextV;
437 uint32_t vns00 = vnCurrLatS + j;
438 uint32_t vns01 = vnNextLatS + j;
439 uint32_t vns11 = vnNextLatS + jNextV;
440 uint32_t vns10 = vnCurrLatS + jNextV;
443 faces[fHemiOffsetNorth] = {
Face { vn00, vtn00, vnn00 },
Face { vn11, vtn11, vnn11 },
444 Face { vn10, vtn10, vnn10 } };
446 faces[fHemiOffsetNorth + 1] = {
Face { vn00, vtn00, vnn00 },
447 Face { vn01, vtn01, vnn01 },
448 Face { vn11, vtn11, vnn11 } };
451 faces[fHemiOffsetSouth] = {
Face { vs00, vts00, vns00 },
Face { vs11, vts11, vns11 },
452 Face { vs10, vts10, vns10 } };
454 faces[fHemiOffsetSouth + 1] = {
Face { vs00, vts00, vns00 },
455 Face { vs01, vts01, vns01 },
456 Face { vs11, vts11, vns11 } };
458 fHemiOffsetNorth += 2;
459 fHemiOffsetSouth += 2;
465 float tTexFac = ip1f * toTexVertical;
466 float tTexNorth = 1.f - tTexFac + tTexFac * vtAspectNorth;
467 float tTexSouth = vtAspectSouth * (1.f - tTexFac);
470 for (uint32_t j = 0; j < verifLonsp1; ++j) {
471 float sTex = sTexCache[j];
473 vertexTextures[vtHemiOffsetNorth] = QVector2D(sTex, tTexNorth);
474 vertexTextures[vtHemiOffsetSouth] = QVector2D(sTex, tTexSouth);
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;
495 for (uint32_t j = 0; j < verifLons; ++j) {
496 QVector3D vEquatorNorth = vertices[idxVNEquator + j];
497 QVector3D vEquatorSouth = vertices[idxVSEquator + j];
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());
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);
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;
527 uint32_t vtCurrRing = idxVtNEquator + m * verifLonsp1;
528 uint32_t vtNextRing = vtCurrRing + verifLonsp1;
530 for (uint32_t j = 0; j < verifLons; ++j) {
531 uint32_t jNextVt = j + 1;
532 uint32_t jNextV = jNextVt % verifLons;
535 uint32_t v00 = vCurrRing + j;
536 uint32_t v01 = vNextRing + j;
537 uint32_t v11 = vNextRing + jNextV;
538 uint32_t v10 = vCurrRing + jNextV;
541 uint32_t vt00 = vtCurrRing + j;
542 uint32_t vt01 = vtNextRing + j;
543 uint32_t vt11 = vtNextRing + jNextVt;
544 uint32_t vt10 = vtCurrRing + jNextVt;
547 uint32_t vn0 = idxVNEquator + j;
548 uint32_t vn1 = idxVNEquator + jNextV;
550 faces[fCylOffset] = {
Face { v00, vt00, vn0 },
Face { v11, vt11, vn1 },
551 Face { v10, vt10, vn1 } };
553 faces[fCylOffset + 1] = {
Face { v00, vt00, vn0 },
Face { v01, vt01, vn0 },
554 Face { v11, vt11, vn1 } };
560 uint32_t stride = 3 *
sizeof(
float);
561 uint32_t strideNormal = 0;
562 uint32_t strideUV = 0;
564 if (m_enableNormals) {
565 strideNormal = stride;
566 stride += 3 *
sizeof(
float);
570 stride += 2 *
sizeof(
float);
573 QByteArray vertexData(vertices.length() * stride, Qt::Initialization::Uninitialized);
574 QByteArray indexData(faces.length() * 3 *
sizeof(quint32), Qt::Initialization::Uninitialized);
576 const auto getVertexPtr = [&](
const int vertexIdx) {
577 return reinterpret_cast<QVector3D *>(vertexData.data() + stride * vertexIdx);
579 const auto getNormalPtr = [&](
const int vertexIdx) {
580 return reinterpret_cast<QVector3D *>(vertexData.data() + stride * vertexIdx + strideNormal);
582 const auto getTexturePtr = [&](
const int vertexIdx) {
583 return reinterpret_cast<QVector2D *>(vertexData.data() + stride * vertexIdx + strideUV);
586 uint32_t *indexPtr =
reinterpret_cast<uint32_t *>(indexData.data());
588 for (qsizetype i = 0; i < vertices.length(); i++) {
589 *getVertexPtr(i) = vertices[i];
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];
598 *indexPtr = vertexIndices[1];
600 *indexPtr = vertexIndices[2];
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]];
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]];
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);
629 addAttribute(QQuick3DGeometry::Attribute::TexCoordSemantic, strideUV,
630 QQuick3DGeometry::Attribute::ComponentType::F32Type);
632 addAttribute(QQuick3DGeometry::Attribute::IndexSemantic, 0,
633 QQuick3DGeometry::Attribute::ComponentType::U32Type);
636 setVertexData(vertexData);
637 setIndexData(indexData);
639 setBounds(QVector3D(-radius - 0.5f * m_height, -radius, -radius),
640 QVector3D(radius + 0.5f * m_height, radius, radius));
Combined button and popup list for selecting options.