In the function FStaticMeshOperations::ConvertFromRawMesh(), in the file StaticMeshOperations.cpp, the new polygon groups are created for the new mesh.
//Create the PolygonGroups
for (int32 MaterialIndex : SourceRawMesh.FaceMaterialIndices)
{
if (!MaterialIndexToPolygonGroup.Contains(MaterialIndex))
{
FPolygonGroupID PolygonGroupID(MaterialIndex);
DestinationMeshDescription.CreatePolygonGroupWithID(PolygonGroupID);
if (MaterialMap.Contains(MaterialIndex))
{
PolygonGroupImportedMaterialSlotNames[PolygonGroupID] = MaterialMap[MaterialIndex];
}
else
{
PolygonGroupImportedMaterialSlotNames[PolygonGroupID] = FName(*FString::Printf(TEXT("MaterialSlot_%d"), MaterialIndex));
}
PolygonGroups.Add(PolygonGroupID);
MaterialIndexToPolygonGroup.Add(MaterialIndex, PolygonGroupID);
}
}
Inside the first if statement, the PolygonGroupID is being created, but it is created based on the Material Index, as opposed to the polygon group that the original polygon is a part of.
This will cause the polygons to be placed in the group associated with the material index that it is mapped to. In this case, for LOD 0, the head polygons were moved from section 0 to section 7, as can be seen above. This resulted in the head using a different section to mapping. In this case section 7 mapped to material 5 - the lacrimal fluid.
There is also another issue that appears once this issue is resolved, although it was hidden in the higher LODs until this issue is resolved.
In the function FMeshUtilities::ConvertMeshesToStaticMesh(), from the file MeshUtilties.cpp, we have the section to material mapping being created:
int32 SectionIndex = 0;
for (int32 UniqueMaterialIndex : UniqueMaterialIndices)
{
if (RawMesh.MaterialIndexToImportIndex.IsValidIndex(SectionIndex))
{
StaticMesh->GetSectionInfoMap().Set(RawMeshLODIndex, SectionIndex, FMeshSectionInfo(RawMesh.MaterialIndexToImportIndex[SectionIndex]));
}
else
{
StaticMesh->GetSectionInfoMap().Set(RawMeshLODIndex, SectionIndex, FMeshSectionInfo(UniqueMaterialIndex));
}
SectionIndex++;
}
For all the sections, it runs through all the unique material indices and tries to remap the indices if there is a mapping available. In the case where there is no mapping, it is because it is a 1:1 mapping (this is the else part). There it correctly uses the UniqueMaterialIndex to do the mapping. However, in the if part, it uses the SectionIndex as a map into the MaterialIndexToImportIndex instead of the UniqueMaterialIndex. This can result in incorrect section to material mappings in the cases where a MaterialIndexToImportIndex was needed, which is actually the case for the higher LODs.
It didn’t result in messed up materials in the particular cases for the higher LODs because the mapping just so happened to work out. (The head was moved to the bottom section, which just so happened to need a higher material slot mapping. And the other polygons all got moved up and their mappings also just happened to be in order.)
These issues are easily resolved using the correct variables for the indices.
//Create the PolygonGroups
int32 ActualPolygonSection = 0;
for (int32 MaterialIndex : SourceRawMesh.FaceMaterialIndices)
{
if (!MaterialIndexToPolygonGroup.Contains(MaterialIndex))
{
//FPolygonGroupID PolygonGroupID(MaterialIndex);
FPolygonGroupID PolygonGroupID(ActualPolygonSection);
DestinationMeshDescription.CreatePolygonGroupWithID(PolygonGroupID);
ActualPolygonSection++;
if (MaterialMap.Contains(MaterialIndex))
{
PolygonGroupImportedMaterialSlotNames[PolygonGroupID] = MaterialMap[MaterialIndex];
}
else
{
PolygonGroupImportedMaterialSlotNames[PolygonGroupID] = FName(*FString::Printf(TEXT("MaterialSlot_%d"), MaterialIndex));
}
PolygonGroups.Add(PolygonGroupID);
MaterialIndexToPolygonGroup.Add(MaterialIndex, PolygonGroupID);
}
}
For the second issue, just use UniqueMaterialIndex instead of SectionID for the MaterialIndexToImportedIndex array.






