Hi, I’m trying to create a material that “draws” other materials on its subarea. The number of the other materials can vary, in both the amount being used in the final material and the amount of candidates (choose N from M candidates and drawing them, both N and M can be very large).
I can’t create all possible meshes that have separate material slots for each “slot” in advance since the number of the "slot"s can be fairly high.
If there is a way to create material slots dynamically at runtime, please ignore the rest of this post and share your knowledge on how to do that.
(This is only for testing, for actual development I’ll make use of other attributes such as metallic, roughness, normal, …)
These are functions only because I couldn’t find a way to draw dynamic material instances.
I don’t want to use a render target and draw materials on it; it’s limited by its texture size. But please let me know if this is truly the only way.
Any idea how I could achieve it? Thanks in advance.
Solved it with dynamic mesh.
I didn’t create a mesh for each slot, instead, I copied the original static mesh and manipulated the slot IDs.
Sharing the code here.
void AWheel::UpdateSlotFloorMesh()
{
using namespace UE::Geometry;
UDynamicMesh* DynMesh = SlotFloorMeshComponent->GetDynamicMesh();
DynMesh->Reset();
constexpr FGeometryScriptMeshReadLOD RequestedLOD{ EGeometryScriptLODType::RenderData, 0 };
EGeometryScriptOutcomePins Outcome;
UGeometryScriptLibrary_StaticMeshFunctions::CopyMeshFromStaticMesh(StaticMesh, DynMesh, {}, RequestedLOD, Outcome);
if (Outcome == EGeometryScriptOutcomePins::Failure)
{
UE_LOG(LogTemp, Error, TEXT("Failed to copy mesh from static mesh"));
return;
}
for (const FStaticMaterial& Material : StaticMesh->GetStaticMaterials())
{
UMaterialInstanceDynamic* DynMat = SlotFloorMeshComponent->CreateAndSetMaterialInstanceDynamicFromMaterial(
StaticMesh->GetMaterialIndex(Material.MaterialSlotName), Material.MaterialInterface);
SlotMaterials.Add(DynMat);
}
FGeometryScriptIndexList TriangleIDList;
UGeometryScriptLibrary_MeshMaterialFunctions::GetTrianglesByMaterialID(DynMesh, SlotFloorMaterialID, TriangleIDList);
TArray<int>& TriangleIDs = *TriangleIDList.List.Get();
const int Size = TriangleIDs.Num();
const int TriangleCountPerSlot = Size / SlotCount;
const int LastSlotTriangleCount = TriangleCountPerSlot + Size % SlotCount;
int MaterialID = StaticMesh->GetStaticMaterials().Num();
FGeometryScriptIndexList SlotTriangleIDs;
SlotTriangleIDs.Reset(EGeometryScriptIndexType::Triangle);
SlotTriangleIDs.List->Reserve(LastSlotTriangleCount);
for (int i = 0; i < SlotCount; i++, MaterialID++)
{
const int SlotTriangleCount = i == SlotCount - 1 ? LastSlotTriangleCount : TriangleCountPerSlot;
SlotTriangleIDs.List->Reset();
SlotTriangleIDs.List->Append(TriangleIDs.GetData() + i * TriangleCountPerSlot, SlotTriangleCount);
UGeometryScriptLibrary_MeshMaterialFunctions::SetMaterialIDOnTriangles(DynMesh, SlotTriangleIDs, MaterialID);
UMaterialInstanceDynamic* DynMat = SlotFloorMeshComponent->CreateAndSetMaterialInstanceDynamicFromMaterial(MaterialID, i % 2 == 0 ? Mat : Mat2);
SlotMaterials.Add(DynMat);
}
}