Material that draws arbitrary amount of other materials

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 have this mesh:


I want to paint the black part with various dynamic material instances. The UV of the black part is just a rectangle; [0, 0] from [1, 0.031].

This image explains what I’m trying to do:

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.

By far, this is the closest one I got:


Since I can’t take arrays in materials, I’m using a texture to pass the material indices, which is updated in code. reference

Each material function from the above looks like this:


(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.

Update: I’m investigating the dynamic mesh now. I think I might go with a method that creates a mesh for each “slot”.

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);
    }
}

Result:


where SlotCount is 50.
(I changed the outer ring’s material; it’s not caused by the code above)

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.