1548 const QVector<QVector3D> &normals,
1549 const QVector<quint32> &indexes,
1550 QVector<MeshVertexSplit> &splitVertices,
1551 float normalMergeAngle,
1552 float normalSplitAngle)
1557 splitVertices.clear();
1559 if (positions.isEmpty() || indexes.isEmpty())
1564 const bool recalculateNormals = normals.size() == positions.size()
1565 && !(qFuzzyIsNull(normalMergeAngle) && qFuzzyIsNull(normalSplitAngle));
1566 const float normalMergeThreshold = qCos(qDegreesToRadians(normalMergeAngle));
1567 const float normalSplitThreshold = qCos(qDegreesToRadians(normalSplitAngle));
1569 quint32 splitVertexCount = positions.size();
1588 QVector<quint32> weldRemap(positions.size());
1589 QVarLengthArray<MeshVertexStream, 2> streams;
1590 streams.append({ positions.constData(),
sizeof(QVector3D),
sizeof(QVector3D) });
1591 if (!recalculateNormals && normals.size() == positions.size())
1592 streams.append({ normals.constData(),
sizeof(QVector3D),
sizeof(QVector3D) });
1593 const quint32 weldedVertexCount = quint32(generateVertexRemap(weldRemap.data(), indexes.constData(),
1595 positions.size(), streams.constData(),
1596 size_t(streams.size())));
1597 QVector<quint32> weldedIndexes(indexes.size());
1598 remapIndexBuffer(weldedIndexes.data(), indexes.constData(), indexes.size(), weldRemap.constData());
1599 QVector<QVector3D> weldedPositions(weldedVertexCount);
1600 remapVertexBuffer(weldedPositions.data(), positions.constData(), positions.size(),
sizeof(QVector3D),
1601 weldRemap.constData());
1608 constexpr quint32 unusedVertex = std::numeric_limits<quint32>::max();
1609 QVector<quint32> weldedToOriginal(weldedVertexCount, unusedVertex);
1610 for (quint32 i = 0, end = quint32(positions.size()); i < end; ++i) {
1611 const quint32 welded = weldRemap.at(i);
1613 if (welded != unusedVertex && weldedToOriginal.at(welded) == unusedVertex)
1614 weldedToOriginal[welded] = i;
1617 const float targetError = std::numeric_limits<
float>::max();
1618 const float *vertexData =
reinterpret_cast<
const float *>(weldedPositions.constData());
1619 const float scaleFactor = simplifyScale(vertexData, weldedVertexCount,
sizeof(QVector3D));
1620 const quint32 indexCount = indexes.size();
1624 const quint32 maxLevelIndexes = indexCount - indexCount / 4 - 1;
1625 const quint32 maxIndexTarget = maxLevelIndexes - maxLevelIndexes % 3;
1626 quint32 indexTarget = 12;
1627 quint32 lastIndexCount = 0;
1628 QVector<MeshLevelOfDetail> lods;
1630 while (indexTarget < indexCount) {
1632 QVector<quint32> newIndexes;
1633 newIndexes.resize(indexCount);
1634 size_t newLength = simplifyMesh(newIndexes.data(), weldedIndexes.constData(), weldedIndexes.size(),
1635 vertexData, weldedVertexCount,
sizeof(QVector3D), indexTarget,
1636 targetError, 0, &error);
1639 if (newLength < lastIndexCount + (lastIndexCount + 1) / 2) {
1640 const quint32 nextTarget = qMin(indexTarget + indexTarget / 2, maxIndexTarget);
1641 if (nextTarget <= indexTarget)
1643 indexTarget = nextTarget;
1648 if (newLength == 0 || newLength > maxLevelIndexes)
1651 newIndexes.resize(newLength);
1655 for (quint32 &index : newIndexes)
1656 index = weldedToOriginal.at(index);
1659 if (recalculateNormals) {
1661 QVector<QVector3D> faceNormals;
1663 QVector<quint32> culledIndexes;
1664 for (quint32 j = 0; j < quint32(newIndexes.size()); j += 3) {
1665 const QVector3D &v0 = positions[newIndexes[j]];
1666 const QVector3D &v1 = positions[newIndexes[j + 1]];
1667 const QVector3D &v2 = positions[newIndexes[j + 2]];
1669 QVector3D faceNormal = QVector3D::crossProduct(v1 - v0, v2 - v0);
1671 const float faceArea = QSSGUtils::vec3::normalize(faceNormal);
1676 if (faceArea != 0.0f) {
1677 faceNormals.append(faceNormal);
1678 faceNormals.append(faceNormal);
1679 faceNormals.append(faceNormal);
1680 culledIndexes.append({newIndexes[j], newIndexes[j + 1], newIndexes[j + 2]});
1684 if (newIndexes.size() != culledIndexes.size())
1685 newIndexes = culledIndexes;
1690 const quint32 newIndexCount = quint32(newIndexes.size());
1691 QHash<QVector3D, QVector<quint32>> positionHash;
1692 for (quint32 i = 0; i < newIndexCount; ++i) {
1693 const quint32 index = newIndexes[i];
1694 const QVector3D position = positions[index];
1695 positionHash[position].append(i);
1702 QVector<QPair<quint32, quint32>> remapIndexes;
1703 for (quint32 positionIndex = 0; positionIndex < newIndexCount; ++positionIndex) {
1704 const quint32 index = newIndexes[positionIndex];
1705 const QVector3D &position = positions[index];
1706 const QVector3D &faceNormal = faceNormals[positionIndex];
1707 QVector3D newNormal;
1709 const auto &sharedPositions = positionHash.value(position);
1710 for (
const auto positionIndex2 : sharedPositions) {
1711 if (positionIndex == positionIndex2) {
1713 newNormal += faceNormal;
1715 const QVector3D &faceNormal2 = faceNormals[positionIndex2];
1716 if (QVector3D::dotProduct(faceNormal2, faceNormal) >= normalMergeThreshold)
1717 newNormal += faceNormal2;
1722 QSSGUtils::vec3::normalize(newNormal);
1733 const QVector3D &originalNormal = normals[index];
1734 const float theta = QVector3D::dotProduct(originalNormal, newNormal);
1735 if (theta < normalSplitThreshold) {
1736 splitVertices.append({ index, newNormal.normalized() });
1737 remapIndexes.append({positionIndex, splitVertexCount++});
1742 for (
const auto &pair : std::as_const(remapIndexes))
1743 newIndexes[pair.first] = pair.second;
1746 lods.append({error * scaleFactor, newIndexes});
1747 lastIndexCount = quint32(newLength);
1750 if (lastIndexCount + (lastIndexCount + 1) / 2 > maxLevelIndexes)
1753 const size_t doubled = qMax(newLength, size_t(indexTarget)) * 2;
1754 const quint32 nextTarget = quint32(qMin<size_t>(doubled, maxIndexTarget));
1755 if (nextTarget <= indexTarget)
1757 indexTarget = nextTarget;