@JoeJ I implemented the LOD algorithm on the CPU but using: meshoptmizer, METIS and Vulkan API. Following the implementation code of LOD selection:
std::vector<uint32_t> LODSelectionDispatcher::LodSelector(std::vector<MeshletGroup>& totalGroups,
const glm::mat4& modelViewMatrix, int width, float hFov,
const LOD& lastLOD, const glm::vec3& instancePos,
float& avgLOD, std::vector<MINERVA_VERTEX>& vertexBuffer) {
float distanceMul = 2.0f;
errorThreshold = 1.0f;
std::unordered_set<idx_t> groupsSelected;
std::vector<uint32_t> newIndexBuffer;
std::vector<MeshletGroup> tempTotal = totalGroups;
for (auto& group : tempTotal) {
MeshletGroup parentGroup = group;
float parentGroupError = 0.0f;
float currentGroupError = ComputeScreenSpaceError(group.groupBound, modelViewMatrix, group.groupError, width,
hFov, instancePos, distanceMul);
if (group.parentsGroup.size() <= 0) {
parentGroupError = errorThreshold + 0.1f;
if (currentGroupError <= errorThreshold && parentGroupError > errorThreshold && !group.isSelected) {
group.isSelected = true;
groupsSelected.insert(group.groupID);
}
continue;
}
for (int i = 0; i < group.parentsGroup.size(); i++) {
parentGroup = tempTotal[group.parentsGroup[i]];
assert(group.groupBound.radius > 0 && parentGroup.groupBound.radius > 0);
assert(group.groupError < parentGroup.groupError);
parentGroupError = ComputeScreenSpaceError(parentGroup.groupBound, modelViewMatrix, parentGroup.groupError,
width, hFov, instancePos, distanceMul);
if (currentGroupError <= errorThreshold && parentGroupError > errorThreshold && !group.isSelected) {
for (int i = 0; i < group.parentsGroup.size(); i++) {
MeshletGroup* parent = &tempTotal[group.parentsGroup[i]];
parent->isSelected = true;
}
groupsSelected.insert(group.groupID);
}
}
}
// CPU side
for (auto group : groupsSelected) {
MeshletGroup* currentGroup = &totalGroups[group];
avgLOD += currentGroup->lod;
newIndexBuffer.insert(newIndexBuffer.end(), currentGroup->localGroupIndexBuffer.begin(),
currentGroup->localGroupIndexBuffer.end());
vertexBuffer.insert(vertexBuffer.end(), currentGroup->localGroupVertexBuffer.begin(),
currentGroup->localGroupVertexBuffer.end());
}
avgLOD /= groupsSelected.size();
if (newIndexBuffer.size() <= 0) {
avgLOD = -1.0f;
newIndexBuffer = lastLOD.lodIndexBuffer;
}
currentAvgLOD = avgLOD;
return newIndexBuffer;
}
float LODSelectionDispatcher::ComputeScreenSpaceError(PhoenixBound bound, const glm::mat4& modelViewMatrix,
float groupError, int width, float hFov,
const glm::vec3& instancePos, float distanceMul) {
bound.center += instancePos;
// Bound center in View space
glm::vec4 distanceFromCamera = modelViewMatrix * glm::vec4{bound.center, 1.0f};
float d = glm::length(distanceFromCamera);
float screenSpaceError = (groupError * static_cast<float>(width)) / (distanceMul * d * tan(hFov / 2.0f));
return screenSpaceError;
}