" " " "

c++ – LOD selection issue

Share post:

I have been developing an LOD algorithm similar to Nanite’s style. I have been developing the algorithm using Vulkan .However, I encountered problems with LOD selection. It seems that the algorithm doesn’t select some clusters, causing holes during the LOD selection process. Below is an image that shows these strange effects:

I’m using meshoptimizer to create meshlets and simplify my mesh, and the METIS library to group my meshlets. The error is stored per group and calculated as the sum of the errors of the meshlets within the group. I sum the group error of the current LOD with the maximum group error of the previous LOD to ensure that the child error is less than the parent error. I’m sure that the error function is monotonically increasing. The lod selection code is the following:
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;

}

totalGroups contains all groups of all LOD. I use it to simply iterate among all groups and compute the screen space error.
Where am I going wrong?

Related articles

Real Madrid’s Mbappe struggling with thigh injury

Real Madrid's French forward Kylian Mbappe has been diagnosed with an injury to...

A Night With the Best Baseball Team in New York

The Brooklyn Cyclones are leading their minor league division this summer, while New York’s major league teams...