Hello!
I’m trying to setup a system for capturing thumbnails at runtime to allow us to display images of dynamic characters/objects on the UI (NPC menus, inventories etc).
The capture system handles requests for thumbnails by loading actors into a capture room located far below the map, where it waits for the actor to be fully loaded in before rendering them with a Scene Capture Component. The resulting render texture is then run through some post-processing materials before being passed over to the UI.
I have been following some of the advice shared on the threads started by [Eric [Content removed] and [Sam [Content removed] however similar to their experiences, I am struggling to ensure that actors that use Nanite meshes are of a sufficient/consistent quality, and unfortunately disabling Nanite is not an option.
Here’s some rough pseudo code outlining my current process for Nanite meshes:
`// After the subject actor’s resources have streamed in and the subject actor is has finished spawning
for (UPrimitiveComponent* PrimitiveComponent : SubjectPrimitiveComponents)
{
// Force static meshs components to LOD0
if (UStaticMeshComponent* StaticMeshComponent = Cast(PrimitiveComponent))
{
StaticMeshComponent->SetForcedLodModel(1);
}
// Force streamable render assets mip levels to resident
FStreamingTextureLevelContext LevelContext(EMaterialQualityLevel::Num, PrimitiveComponent);
TArray RenderAssetInfoArray;
PrimitiveComponent->GetStreamingRenderAssetInfo(LevelContext, RenderAssetInfoArray);
for (const FStreamingRenderAssetPrimitiveInfo& RenderAssetInfo : RenderAssetInfoArray)
{
RenderAssetInfo.RenderAsset->SetForceMipLevelsToBeResident(30.0f); // 30 seconds should be more than enough for the capture
RenderAssetInfo.RenderAsset->bIgnoreStreamingMipBias = 1;
IStreamingManager::Get().GetRenderAssetStreamingManager().FastForceFullyResident(RenderAssetInfo.RenderAsset);
}
}
// Wait for render assets to stream in
for (UStreamableRenderAsset* RenderAsset : RenderAssets)
{
if (!RenderAsset->IsFullyStreamedIn())
{
return;
}
}
// Pre-warm Nanite resources for a number of frames before the capture
ENQUEUE_RENDER_COMMAND(PreWarmNaniteForThumbnailCapture)
([NaniteResources = MoveTemp(NaniteResources), NanitePreWarmFrameCount = NanitePreWarmFrameCount](FRHICommandListImmediate& RHICmdList) {
IRendererModule& RendererModule = GetRendererModule();
for (const Nanite::FResources* NaniteResource : NaniteResources)
{
RendererModule.PrefetchNaniteResource(NaniteResource, NanitePreWarmFrameCount);
}
});
// Wait for the nanite pre-warm to complete
if (GFrameCounter - NanitePreWarmStartFrame < NanitePreWarmFrameCount)
{
return;
}
// Render the subject repeatedly for a number of frames
if (CaptureFramesRemaining > 0)
{
SceneCaptureComponent->CaptureScene();
–CaptureFramesRemaining;
return;
}`
I’ve experimented with various pre-warm/capture durations and found that 5 frames for each produces decent results, but while the quality is 90% there, 10% of the time the quality deviates, and parts of the Nanite meshes appear notably blurry/low detail.
What I am hoping for is a consistent way to request the highest level of detail for a Nanite mesh, and a definitive way of knowing when the Nanite mesh is fully loaded at that highest level so that the capture can be executed.
Does anyone have any advice or recommendations?
Thanks!