How to create UCanvas without using BeginDrawCanvasToRenderTarget()

How to create UCanvas object without using BeginDrawCanvasToRenderTarget()

Hello! :smiley:
I am working on combining the base color texture and normal map texture used in a material for an avatar’s clothing into each single texture.
To do this I am using a TextureRenderTarget and a UCanvas. Below is the code.

	UCanvas* BaseColorCanvas;
	BaseRenderTarget = UKismetRenderingLibrary::CreateRenderTarget2D(GetWorld(), AtlasSize, AtlasSize);
	UKismetRenderingLibrary::ClearRenderTarget2D(GetWorld(), BaseRenderTarget, FLinearColor::Transparent);

	UCanvas* NormalCanvas;
	NormalRenderTarget = UKismetRenderingLibrary::CreateRenderTarget2D(GetWorld(), AtlasSize, AtlasSize);
	UKismetRenderingLibrary::ClearRenderTarget2D(GetWorld(), NormalRenderTarget, FLinearColor::Transparent);

	FVector2D SizeOfAtlas(AtlasSize, AtlasSize);
	UKismetRenderingLibrary::BeginDrawCanvasToRenderTarget(GetWorld(), BaseRenderTarget, BaseColorCanvas, SizeOfAtlas, BaseColorContext);
	UKismetRenderingLibrary::BeginDrawCanvasToRenderTarget(GetWorld(), NormalRenderTarget, NormalCanvas, SizeOfAtlas, NormalContext);

	TArray<USceneComponent*> AvatarCompList;
	Avatar->GetRootComponent()->GetChildrenComponents(true, AvatarCompList);
	
	for (auto Component : AvatarCompList)
	{
		for (FString ChildComp : BodyComponents)
		{
			if (Component->GetName() == ChildComp)
			{
				USkeletalMeshComponent* SMComponent = Cast<USkeletalMeshComponent>(Component);
				UMaterialInterface* SMCMaterialInterface = SMComponent->GetMaterial(0);

				TArray<FMaterialParameterInfo> OutParameterInfo;
				TArray<FGuid> OutParameterIds;
				SMCMaterialInterface->GetAllTextureParameterInfo(OutParameterInfo, OutParameterIds);

				for (const FMaterialParameterInfo& ParaInfo : OutParameterInfo)
				{
					if (ParaInfo.Name.ToString().Contains(TEXT("base")))
						DrawMaterialToRenderTargetNMakeTexture(Component->GetName(), SMCMaterialInterface, ParaInfo, BaseColorCanvas);
					else if (ParaInfo.Name.ToString().Contains(TEXT("normal")))
						DrawMaterialToRenderTargetNMakeTexture(Component->GetName(), SMCMaterialInterface, ParaInfo, NormalCanvas);
				}

				++Row;
				if (Row == RowNColumnMaxNum)
				{
					Row = 0;
					++Column;
				}
			}
		}
	}
	UKismetRenderingLibrary::EndDrawCanvasToRenderTarget(GetWorld(), BaseColorContext);
	UKismetRenderingLibrary::EndDrawCanvasToRenderTarget(GetWorld(), NormalContext);

When I checked the output, the base color texture that should have been drawn in the BaseRenderTarget was drawn in the NormalRenderTarget. The BaseRenderTarget was empty with a clear color.
During the debugging process, I discovered that the BaseColorCanvas and NormalCanvas were pointing to the same UCanvas object after passing through UKismetRenderingLibrary::BeginDrawCanvasToRenderTarget(). This happens because the UCanvas parameter passed to UKismetRenderingLibrary::BeginDrawCanvasToRenderTarget() is assigned a variable ‘CanvasForRenderingToTarget’ of UWorld.

So it looks like I need to create two UCanvas objects without using UKismetRenderingLibrary::BeginDrawCanvasToRenderTarget() to draw the base color texture and normal map texture properly.
I’m wondering if I’m on the right track and need some clues on how to accomplish my goal.
It looks like I need to use NewObject() to create a UCanvas directly, but then I have no idea how to replace UKismetRenderingLibrary::EndDrawCanvasToRenderTarget().

If anyone with a clue to my predicament could post, I’d really, really appreciate it! :)///

Hi seungmki,

Just do it in 2 loops, one for the BaseColor and one for the Normal - it’s not a large loop, it won’t slow it down.

1 Like

Is this the only way to go in the end? :smiling_face_with_tear:
I was thinking of the method you @RecourseDesign suggested as a last resort… and it looks like I’ll have to use it… thanks for the answer!

1 Like

It will be possible, but you’d have to recreate those kismet routines and use your own canvas objects, the tricky part would be wrapping it up with the RHI routines…

1 Like

Oooh… as you just pointed out, when I looked at the UKismetRenderingLibrary’s BeginDrawCanvasToRenderTarget() and EndDrawCanvasToRenderTarget(), I was worried that I’d have to implement what they do myself…
Sounds like a long and complicated road to me. :smiling_face_with_tear:

1 Like

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