1531 const QVector<QVector3D> &normals,
1532 const QVector<quint32> &indexes,
1533 QVector<MeshVertexSplit> &splitVertices,
1534 float normalMergeAngle,
1535 float normalSplitAngle)
1540 splitVertices.clear();
1542 if (positions.isEmpty() || indexes.isEmpty())
1547 const bool recalculateNormals = normals.size() == positions.size()
1548 && !(qFuzzyIsNull(normalMergeAngle) && qFuzzyIsNull(normalSplitAngle));
1549 const float normalMergeThreshold = qCos(qDegreesToRadians(normalMergeAngle));
1550 const float normalSplitThreshold = qCos(qDegreesToRadians(normalSplitAngle));
1552 quint32 splitVertexCount = positions.size();
1571 QVector<quint32> weldRemap(positions.size());
1572 QVarLengthArray<MeshVertexStream, 2> streams;
1573 streams.append({ positions.constData(),
sizeof(QVector3D),
sizeof(QVector3D) });
1574 if (!recalculateNormals && normals.size() == positions.size())
1575 streams.append({ normals.constData(),
sizeof(QVector3D),
sizeof(QVector3D) });
1576 const quint32 weldedVertexCount = generateVertexRemap(weldRemap.data(), indexes.constData(), indexes.size(),
1577 positions.size(), streams.constData(),
1578 size_t(streams.size()));
1579 QVector<quint32> weldedIndexes(indexes.size());
1580 remapIndexBuffer(weldedIndexes.data(), indexes.constData(), indexes.size(), weldRemap.constData());
1581 QVector<QVector3D> weldedPositions(weldedVertexCount);
1582 remapVertexBuffer(weldedPositions.data(), positions.constData(), positions.size(),
sizeof(QVector3D),
1583 weldRemap.constData());
1590 constexpr quint32 unusedVertex = std::numeric_limits<quint32>::max();
1591 QVector<quint32> weldedToOriginal(weldedVertexCount, unusedVertex);
1592 for (quint32 i = 0, end = quint32(positions.size()); i < end; ++i) {
1593 const quint32 welded = weldRemap.at(i);
1595 if (welded != unusedVertex && weldedToOriginal.at(welded) == unusedVertex)
1596 weldedToOriginal[welded] = i;
1599 const float targetError = std::numeric_limits<
float>::max();
1600 const float *vertexData =
reinterpret_cast<
const float *>(weldedPositions.constData());
1601 const float scaleFactor = simplifyScale(vertexData, weldedVertexCount,
sizeof(QVector3D));
1602 const quint32 indexCount = indexes.size();
1606 const quint32 maxLevelIndexes = indexCount - indexCount / 4 - 1;
1607 const quint32 maxIndexTarget = maxLevelIndexes - maxLevelIndexes % 3;
1608 quint32 indexTarget = 12;
1609 quint32 lastIndexCount = 0;
1610 QVector<MeshLevelOfDetail> lods;
1612 while (indexTarget < indexCount) {
1614 QVector<quint32> newIndexes;
1615 newIndexes.resize(indexCount);
1616 size_t newLength = simplifyMesh(newIndexes.data(), weldedIndexes.constData(), weldedIndexes.size(),
1617 vertexData, weldedVertexCount,
sizeof(QVector3D), indexTarget,
1618 targetError, 0, &error);
1621 if (newLength < lastIndexCount + (lastIndexCount + 1) / 2) {
1622 const quint32 nextTarget = qMin(indexTarget + indexTarget / 2, maxIndexTarget);
1623 if (nextTarget <= indexTarget)
1625 indexTarget = nextTarget;
1630 if (newLength == 0 || newLength > maxLevelIndexes)
1633 newIndexes.resize(newLength);
1637 for (quint32 &index : newIndexes)
1638 index = weldedToOriginal.at(index);
1641 if (recalculateNormals) {
1643 QVector<QVector3D> faceNormals;
1645 QVector<quint32> culledIndexes;
1646 for (quint32 j = 0; j < quint32(newIndexes.size()); j += 3) {
1647 const QVector3D &v0 = positions[newIndexes[j]];
1648 const QVector3D &v1 = positions[newIndexes[j + 1]];
1649 const QVector3D &v2 = positions[newIndexes[j + 2]];
1651 QVector3D faceNormal = QVector3D::crossProduct(v1 - v0, v2 - v0);
1653 const float faceArea = QSSGUtils::vec3::normalize(faceNormal);
1658 if (faceArea != 0.0f) {
1659 faceNormals.append(faceNormal);
1660 faceNormals.append(faceNormal);
1661 faceNormals.append(faceNormal);
1662 culledIndexes.append({newIndexes[j], newIndexes[j + 1], newIndexes[j + 2]});
1666 if (newIndexes.size() != culledIndexes.size())
1667 newIndexes = culledIndexes;
1672 const quint32 newIndexCount = quint32(newIndexes.size());
1673 QHash<QVector3D, QVector<quint32>> positionHash;
1674 for (quint32 i = 0; i < newIndexCount; ++i) {
1675 const quint32 index = newIndexes[i];
1676 const QVector3D position = positions[index];
1677 positionHash[position].append(i);
1684 QVector<QPair<quint32, quint32>> remapIndexes;
1685 for (quint32 positionIndex = 0; positionIndex < newIndexCount; ++positionIndex) {
1686 const quint32 index = newIndexes[positionIndex];
1687 const QVector3D &position = positions[index];
1688 const QVector3D &faceNormal = faceNormals[positionIndex];
1689 QVector3D newNormal;
1691 const auto &sharedPositions = positionHash.value(position);
1692 for (
const auto positionIndex2 : sharedPositions) {
1693 if (positionIndex == positionIndex2) {
1695 newNormal += faceNormal;
1697 const QVector3D &faceNormal2 = faceNormals[positionIndex2];
1698 if (QVector3D::dotProduct(faceNormal2, faceNormal) >= normalMergeThreshold)
1699 newNormal += faceNormal2;
1704 QSSGUtils::vec3::normalize(newNormal);
1715 const QVector3D &originalNormal = normals[index];
1716 const float theta = QVector3D::dotProduct(originalNormal, newNormal);
1717 if (theta < normalSplitThreshold) {
1718 splitVertices.append({ index, newNormal.normalized() });
1719 remapIndexes.append({positionIndex, splitVertexCount++});
1724 for (
const auto &pair : std::as_const(remapIndexes))
1725 newIndexes[pair.first] = pair.second;
1728 lods.append({error * scaleFactor, newIndexes});
1729 lastIndexCount = newLength;
1732 if (lastIndexCount + (lastIndexCount + 1) / 2 > maxLevelIndexes)
1735 const size_t doubled = qMax(newLength, size_t(indexTarget)) * 2;
1736 const quint32 nextTarget = quint32(qMin<size_t>(doubled, maxIndexTarget));
1737 if (nextTarget <= indexTarget)
1739 indexTarget = nextTarget;