Can't override FPrimitiveSceneProxy::GetViewRelevance()

Hello, I’m trying to implement a custom component to render a voxel-like mesh. I’m follow existing code examples, particularly I rely on FStaticMeshSceneProxy implementation.

After I implemented a template, I noticed GetViewRelevance method is not called in my descendant class, resulting GetDynamicMeshElements is not called as well. Meanwhile methods related to static rendering such as DrawStaticElements are invoked as expected.

Here is my code:

FFrPrimitive.h
class FFrPrimitive : public FPrimitiveSceneProxy
{
public:
	FFrPrimitive(UPrimitiveComponent* F);

	ENGINE_API virtual FPrimitiveViewRelevance GetViewRelevance(const FSceneView* View) const override;
	ENGINE_API virtual void GetDynamicMeshElements(const TArray<const FSceneView*>& Views, const FSceneViewFamily& ViewFamily, uint32 VisibilityMap, class FMeshElementCollector& Collector) const override;
	ENGINE_API virtual void DrawStaticElements(FStaticPrimitiveDrawInterface* PDI) override;
	ENGINE_API virtual void CreateRenderThreadResources(FRHICommandListBase& RHICmdList) override;
	ENGINE_API virtual void DestroyRenderThreadResources() override;

	virtual uint32 GetMemoryFootprint() const override { return sizeof(*this); }
	virtual SIZE_T GetTypeHash() const override;
};
FFrPrimitive.cpp
#define LOG(method) UE_LOG(LogActorComponent, Display, TEXT("FRPRIMITIVE 0x%x %hs"), this, method)

FFrPrimitive::FFrPrimitive(UPrimitiveComponent* F)
	: FPrimitiveSceneProxy(F, FName("FFrPrimitive")) {
	LOG("Ctor") // logged
}

FPrimitiveViewRelevance FFrPrimitive::GetViewRelevance(const FSceneView* View) const {
	LOG("GetViewRelevance") // I never see this in the log
	FPrimitiveViewRelevance Relevance;
	Relevance.bDrawRelevance = true;
	Relevance.bDynamicRelevance = true;
	Relevance.bStaticRelevance = false;

	return Relevance;
}

void FFrPrimitive::GetDynamicMeshElements(const TArray<const FSceneView*>& Views, const FSceneViewFamily& ViewFamily,
	uint32 VisibilityMap, class FMeshElementCollector& Collector) const {
	LOG("Get Dynamic Elements") // not called
	FPrimitiveSceneProxy::GetDynamicMeshElements(Views, ViewFamily, VisibilityMap, Collector);
}

void FFrPrimitive::DrawStaticElements(FStaticPrimitiveDrawInterface* PDI) {
	LOG("DrawStaticElements") // called
	FPrimitiveSceneProxy::DrawStaticElements(PDI);
}

void FFrPrimitive::CreateRenderThreadResources(FRHICommandListBase& RHICmdList) {
	LOG("Create Render Thread Resources") // called
	FPrimitiveSceneProxy::CreateRenderThreadResources(RHICmdList);
}

void FFrPrimitive::DestroyRenderThreadResources() {
	LOG("Destroy Render Thread Resources") // called
	FPrimitiveSceneProxy::DestroyRenderThreadResources();
}
Logs
[108]LogActorFactory: Loading ActorFactory Class /Script/Engine.LevelInstance
[108]LogEditor: Attempting to add actor of class 'LandscapeChunk' to level at 50.00,-180.00,-580.00
[108]LogActorComponent: Display: FRPRIMITIVE 0xf090ae00 Ctor
[108]LogActorComponent: Display: FRPRIMITIVE 0xf090ae00 Create Render Thread Resources
[108]LogActorComponent: Display: FRPRIMITIVE 0xf090ae00 Destroy Render Thread Resources
[108]LogActorComponent: Display: FRPRIMITIVE 0xf090ab00 Ctor
[108]LogActorComponent: Display: FRPRIMITIVE 0xf090ab00 Create Render Thread Resources
[109]LogActorComponent: Display: FRPRIMITIVE 0xf090ab00 DrawStaticElements
[110]LogActorComponent: Display: FRPRIMITIVE 0xf090ab00 DrawStaticElements
[111]LogActorComponent: Display: FRPRIMITIVE 0xf090ab00 DrawStaticElements
[112]LogActorComponent: Display: FRPRIMITIVE 0xf090ab00 DrawStaticElements
[113]LogActorComponent: Display: FRPRIMITIVE 0xf090ab00 DrawStaticElements
[114]LogActorComponent: Display: FRPRIMITIVE 0xf090ab00 DrawStaticElements

What am I doing wrong?

UE5.6, MacOS build

The problem was in CalcBounds method in UComponent which creates FPrimitiveSceneProxy. View relevance methods and subsequent GetDynamicMeshElements won’t call if you won’t override UPrimitiveComponent::CalcBounds. Any non-zero bounds is enough to make primitive visible.

FBoxSphereBounds ULandscapeChunkComponent::CalcBounds(const FTransform& LocalToWorld) const
{
	return FBoxSphereBounds(LocalToWorld.GetLocation(), FVector(1,1,1) * 50, 71.f);
}
1 Like