前置信息:
灯光从World到Scene的流程。
mesh从world到Scene流程,与灯光类似
void UStaticMeshComponent::CreateRenderState_Concurrent(FRegisterComponentContext* Context)
{
LLM_SCOPE(ELLMTag::StaticMesh);
Super::CreateRenderState_Concurrent(Context);
}
void UPrimitiveComponent::CreateRenderState_Concurrent(FRegisterComponentContext* Context)
{
// Make sure cached cull distance is up-to-date if its zero and we have an LD cull distance
if( CachedMaxDrawDistance == 0.f && LDMaxDrawDistance > 0.f )
{
bool bNeverCull = bNeverDistanceCull || GetLODParentPrimitive();
CachedMaxDrawDistance = bNeverCull ? 0.f : LDMaxDrawDistance;
}
Super::CreateRenderState_Concurrent(Context);
UpdateBounds();
// If the primitive isn't hidden and the detail mode setting allows it, add it to the scene.
if (ShouldComponentAddToScene())
{
if (Context != nullptr)
{
Context->AddPrimitive(this);
}
else
{
GetWorld()->Scene->AddPrimitive(this);
}
}
// Components are either registered as static or dynamic in the streaming manager.
// Static components are registered in batches the first frame the level becomes visible (or incrementally each frame when loaded but not yet visible).
// The level static streaming data is never updated after this, and gets reused whenever the level becomes visible again (after being hidden).
// Dynamic components, on the other hand, are updated whenever their render states change.
// The following logic handles all cases where static components should fallback on the dynamic path.
// It is based on a design where each component must either have bHandledByStreamingManagerAsDynamic or bAttachedToStreamingManagerAsStatic set.
// If this is not the case, then the component has never been handled before.
// The bIgnoreStreamingManagerUpdate flag is used to prevent handling component that are already in the update list or that don't have streaming data.
if (!bIgnoreStreamingManagerUpdate && (Mobility != EComponentMobility::Static || bHandledByStreamingManagerAsDynamic || (!bAttachedToStreamingManagerAsStatic && OwnerLevelHasRegisteredStaticComponentsInStreamingManager(GetOwner()))))
{
FStreamingManagerCollection* Collection = IStreamingManager::Get_Concurrent();
if (Collection)
{
Collection->NotifyPrimitiveUpdated_Concurrent(this);
}
}
}
void FScene::AddPrimitive(UPrimitiveComponent* Primitive)
{
SCOPE_CYCLE_COUNTER(STAT_AddScenePrimitiveGT);
SCOPED_NAMED_EVENT(FScene_AddPrimitive, FColor::Green);
checkf(!Primitive->IsUnreachable(), TEXT("%s"), *Primitive->GetFullName());
const float WorldTime = GetWorld()->GetTimeSeconds();
// Save the world transform for next time the primitive is added to the scene
float DeltaTime = WorldTime - Primitive->LastSubmitTime;
if ( DeltaTime < -0.0001f || Primitive->LastSubmitTime < 0.0001f )
{
// Time was reset?
Primitive->LastSubmitTime = WorldTime;
}
else if ( DeltaTime > 0.0001f )
{
// First call for the new frame?
Primitive->LastSubmitTime = WorldTime;
}
checkf(!Primitive->SceneProxy, TEXT("Primitive has already been added to the scene!"));
// Create the primitive's scene proxy.
FPrimitiveSceneProxy* PrimitiveSceneProxy = Primitive->CreateSceneProxy();
Primitive->SceneProxy = PrimitiveSceneProxy;
if(!PrimitiveSceneProxy)
{
// Primitives which don't have a proxy are irrelevant to the scene manager.
return;
}
// Create the primitive scene info.
FPrimitiveSceneInfo* PrimitiveSceneInfo = new FPrimitiveSceneInfo(Primitive, this);
PrimitiveSceneProxy->PrimitiveSceneInfo = PrimitiveSceneInfo;
// Cache the primitives initial transform.
FMatrix RenderMatrix = Primitive->GetRenderMatrix();
FVector AttachmentRootPosition = Primitive->GetActorPositionForRenderer();
struct FCreateRenderThreadParameters
{
FPrimitiveSceneProxy* PrimitiveSceneProxy;
FMatrix RenderMatrix;
FBoxSphereBounds WorldBounds;
FVector AttachmentRootPosition;
FBoxSphereBounds LocalBounds;
};
FCreateRenderThreadParameters Params =
{
PrimitiveSceneProxy,
RenderMatrix,
Primitive->Bounds,
AttachmentRootPosition,
Primitive->GetLocalBounds()
};
// Help track down primitive with bad bounds way before the it gets to the Renderer
ensureMsgf(!Primitive->Bounds.ContainsNaN(),
TEXT("Nans found on Bounds for Primitive %s: Origin %s, BoxExtent %s, SphereRadius %f"), *Primitive->GetName(), *Primitive->Bounds.Origin.ToString(), *Primitive->Bounds.BoxExtent.ToString(), Primitive->Bounds.SphereRadius);
INC_DWORD_STAT_BY( STAT_GameToRendererMallocTotal, PrimitiveSceneProxy->GetMemoryFootprint() + PrimitiveSceneInfo->GetMemoryFootprint() );
// Verify the primitive is valid
VerifyProperPIEScene(Primitive, World);
// Increment the attachment counter, the primitive is about to be attached to the scene.
Primitive->AttachmentCounter.Increment();
// Create any RenderThreadResources required and send a command to the rendering thread to add the primitive to the scene.
FScene* Scene = this;
// If this primitive has a simulated previous transform, ensure that the velocity data for the scene representation is correct
TOptional<FTransform> PreviousTransform = FMotionVectorSimulation::Get().GetPreviousTransform(Primitive);
ENQUEUE_RENDER_COMMAND(AddPrimitiveCommand)(
[Params = MoveTemp(Params), Scene, PrimitiveSceneInfo, PreviousTransform = MoveTemp(PreviousTransform)](FRHICommandListImmediate& RHICmdList)
{
FPrimitiveSceneProxy* SceneProxy = Params.PrimitiveSceneProxy;
FScopeCycleCounter Context(SceneProxy->GetStatId());
SceneProxy->SetTransform(Params.RenderMatrix, Params.WorldBounds, Params.LocalBounds, Params.AttachmentRootPosition);
// Create any RenderThreadResources required.
SceneProxy->CreateRenderThreadResources();
Scene->AddPrimitiveSceneInfo_RenderThread(PrimitiveSceneInfo, PreviousTransform);
});
}
AddedPrimitiveSceneInfos 会在后面创建LumenSceneData用到。
void FScene::AddPrimitiveSceneInfo_RenderThread(FPrimitiveSceneInfo* PrimitiveSceneInfo, const TOptional<FTransform>& PreviousTransform)
{
check(IsInRenderingThread());
check(PrimitiveSceneInfo->PackedIndex == INDEX_NONE);
check(AddedPrimitiveSceneInfos.Find(PrimitiveSceneInfo) == nullptr);
AddedPrimitiveSceneInfos.FindOrAdd(PrimitiveSceneInfo);
if (PreviousTransform.IsSet())
{
OverridenPreviousTransforms.Update(PrimitiveSceneInfo, PreviousTransform.GetValue().ToMatrixWithScale());
}
}
LumenSceneData创建流程
Engine/Source/Runtime/Renderer/Private/DeferredShadingRenderer.cpp
Scene->UpdateAllPrimitiveSceneInfos(GraphBuilder, true);
void FScene::UpdateAllPrimitiveSceneInfos(FRDGBuilder& GraphBuilder, bool bAsyncCreateLPIs)
{
TArray<FPrimitiveSceneInfo*> AddedLocalPrimitiveSceneInfos;
AddedLocalPrimitiveSceneInfos.Reserve(AddedPrimitiveSceneInfos.Num());
for (FPrimitiveSceneInfo* SceneInfo : AddedPrimitiveSceneInfos)
{
AddedLocalPrimitiveSceneInfos.Add(SceneInfo);
}
AddedLocalPrimitiveSceneInfos.Sort(FPrimitiveArraySortKey());
while (AddedLocalPrimitiveSceneInfos.Num())
{
int32 StartIndex = AddedLocalPrimitiveSceneInfos.Num() - 1;
for (int AddIndex = StartIndex; AddIndex < AddedLocalPrimitiveSceneInfos.Num(); AddIndex++)
{
FPrimitiveSceneInfo* PrimitiveSceneInfo = AddedLocalPrimitiveSceneInfos[AddIndex];
int32 PrimitiveIndex = PrimitiveSceneInfo->PackedIndex;
FPrimitiveSceneProxy* SceneProxy = PrimitiveSceneInfo->Proxy;
if (ShouldPrimitiveOutputVelocity(SceneProxy, GetShaderPlatform()))
{
PrimitiveSceneInfo->bRegisteredWithVelocityData = true;
// We must register the initial LocalToWorld with the velocity state.
// In the case of a moving component with MarkRenderStateDirty() called every frame, UpdateTransform will never happen.
VelocityData.UpdateTransform(PrimitiveSceneInfo, PrimitiveTransforms[PrimitiveIndex], PrimitiveTransforms[PrimitiveIndex]);
}
DistanceFieldSceneData.AddPrimitive(PrimitiveSceneInfo);
LumenAddPrimitive(PrimitiveSceneInfo);
}
}
}
// Add function is a member of FScene, because it needs to add the primitive to all FLumenSceneData at once
void FScene::LumenAddPrimitive(FPrimitiveSceneInfo* InPrimitive)
{
LLM_SCOPE_BYTAG(Lumen);
if (DefaultLumenSceneData->bTrackAllPrimitives)
{
const FPrimitiveSceneProxy* Proxy = InPrimitive->Proxy;
bool bTrackPrimitveForLumenScene = TrackPrimitiveForLumenScene(Proxy);
for (FLumenSceneDataIterator LumenSceneData = GetLumenSceneDataIterator(); LumenSceneData; ++LumenSceneData)
{
// We copy this flag over when creating per-view lumen scene data, validate that it's still the same
check(LumenSceneData->bTrackAllPrimitives == DefaultLumenSceneData->bTrackAllPrimitives);
LumenSceneData->PrimitivesToUpdateMeshCards.Add(InPrimitive->GetIndex());
if (bTrackPrimitveForLumenScene)
{
ensure(!LumenSceneData->PendingAddOperations.Contains(InPrimitive));
ensure(!LumenSceneData->PendingUpdateOperations.Contains(InPrimitive));
LumenSceneData->PendingAddOperations.Add(InPrimitive);
}
}
}
}