Files
UnrealEngineUWP/Engine/Source/Runtime/Renderer/Private/SceneCore.cpp
Ben Marsh 4cb383cad7 Fix Clang warnings due to reordered variables.
#codereview Rolando.Caloca

[CL 2508235 by Ben Marsh in Main branch]
2015-04-10 08:39:28 -04:00

373 lines
12 KiB
C++

// Copyright 1998-2015 Epic Games, Inc. All Rights Reserved.
/*=============================================================================
SceneCore.cpp: Core scene implementation.
=============================================================================*/
#include "RendererPrivate.h"
#include "ScenePrivate.h"
#include "AllocatorFixedSizeFreeList.h"
/**
* Fixed Size pool allocator for FLightPrimitiveInteractions
*/
#define FREE_LIST_GROW_SIZE ( 16384 / sizeof(FLightPrimitiveInteraction) )
TAllocatorFixedSizeFreeList<sizeof(FLightPrimitiveInteraction), FREE_LIST_GROW_SIZE> GLightPrimitiveInteractionAllocator;
uint32 FRendererModule::GetNumDynamicLightsAffectingPrimitive(const FPrimitiveSceneInfo* PrimitiveSceneInfo,const FLightCacheInterface* LCI)
{
uint32 NumDynamicLights = 0;
FLightPrimitiveInteraction *LightList = PrimitiveSceneInfo->LightList;
while ( LightList )
{
const FLightSceneInfo* LightSceneInfo = LightList->GetLight();
// Determine the interaction type between the mesh and the light.
FLightInteraction LightInteraction = FLightInteraction::Dynamic();
if(LCI)
{
LightInteraction = LCI->GetInteraction(LightSceneInfo->Proxy);
}
// Don't count light-mapped or irrelevant lights.
if(LightInteraction.GetType() != LIT_CachedIrrelevant && LightInteraction.GetType() != LIT_CachedLightMap)
{
++NumDynamicLights;
}
LightList = LightList->GetNextLight();
}
return NumDynamicLights;
}
/*-----------------------------------------------------------------------------
FLightPrimitiveInteraction
-----------------------------------------------------------------------------*/
/**
* Custom new
*/
void* FLightPrimitiveInteraction::operator new(size_t Size)
{
// doesn't support derived classes with a different size
checkSlow(Size == sizeof(FLightPrimitiveInteraction));
return GLightPrimitiveInteractionAllocator.Allocate();
//return FMemory::Malloc(Size);
}
/**
* Custom delete
*/
void FLightPrimitiveInteraction::operator delete(void *RawMemory)
{
GLightPrimitiveInteractionAllocator.Free(RawMemory);
//FMemory::Free(RawMemory);
}
/**
* Initialize the memory pool with a default size from the ini file.
* Called at render thread startup. Since the render thread is potentially
* created/destroyed multiple times, must make sure we only do it once.
*/
void FLightPrimitiveInteraction::InitializeMemoryPool()
{
static bool bAlreadyInitialized = false;
if (!bAlreadyInitialized)
{
bAlreadyInitialized = true;
int32 InitialBlockSize = 0;
GConfig->GetInt(TEXT("MemoryPools"), TEXT("FLightPrimitiveInteractionInitialBlockSize"), InitialBlockSize, GEngineIni);
GLightPrimitiveInteractionAllocator.Grow(InitialBlockSize);
}
}
/**
* Returns current size of memory pool
*/
uint32 FLightPrimitiveInteraction::GetMemoryPoolSize()
{
return GLightPrimitiveInteractionAllocator.GetAllocatedSize();
}
void FLightPrimitiveInteraction::Create(FLightSceneInfo* LightSceneInfo,FPrimitiveSceneInfo* PrimitiveSceneInfo)
{
// Attach the light to the primitive's static meshes.
bool bDynamic = true;
bool bRelevant = false;
bool bLightMapped = true;
bool bShadowMapped = false;
// Determine the light's relevance to the primitive.
check(PrimitiveSceneInfo->Proxy);
PrimitiveSceneInfo->Proxy->GetLightRelevance(LightSceneInfo->Proxy, bDynamic, bRelevant, bLightMapped, bShadowMapped);
if (bRelevant && bDynamic
// Don't let lights with static shadowing or static lighting affect primitives that should use static lighting, but don't have valid settings (lightmap res 0, etc)
// This prevents those components with invalid lightmap settings from causing lighting to remain unbuilt after a build
&& !(LightSceneInfo->Proxy->HasStaticShadowing() && PrimitiveSceneInfo->Proxy->HasStaticLighting() && !PrimitiveSceneInfo->Proxy->HasValidSettingsForStaticLighting()))
{
const bool bTranslucentObjectShadow = LightSceneInfo->Proxy->CastsTranslucentShadows() && PrimitiveSceneInfo->Proxy->CastsVolumetricTranslucentShadow();
const bool bInsetObjectShadow =
// Currently only supporting inset shadows on directional lights, but could be made to work with any whole scene shadows
LightSceneInfo->Proxy->GetLightType() == LightType_Directional
&& PrimitiveSceneInfo->Proxy->CastsInsetShadow();
// Movable directional lights determine shadow relevance dynamically based on the view and CSM settings. Interactions are only required for per-object cases.
if (LightSceneInfo->Proxy->GetLightType() != LightType_Directional || LightSceneInfo->Proxy->HasStaticShadowing() || bTranslucentObjectShadow || bInsetObjectShadow)
{
// Create the light interaction.
FLightPrimitiveInteraction* Interaction = new FLightPrimitiveInteraction(LightSceneInfo, PrimitiveSceneInfo, bDynamic, bLightMapped, bShadowMapped, bTranslucentObjectShadow, bInsetObjectShadow);
}
}
}
void FLightPrimitiveInteraction::Destroy(FLightPrimitiveInteraction* LightPrimitiveInteraction)
{
delete LightPrimitiveInteraction;
}
FLightPrimitiveInteraction::FLightPrimitiveInteraction(
FLightSceneInfo* InLightSceneInfo,
FPrimitiveSceneInfo* InPrimitiveSceneInfo,
bool bInIsDynamic,
bool bInLightMapped,
bool bInIsShadowMapped,
bool bInHasTranslucentObjectShadow,
bool bInHasInsetObjectShadow
):
LightSceneInfo(InLightSceneInfo),
PrimitiveSceneInfo(InPrimitiveSceneInfo),
LightId(InLightSceneInfo->Id),
bLightMapped(bInLightMapped),
bIsDynamic(bInIsDynamic),
bIsShadowMapped(bInIsShadowMapped),
bUncachedStaticLighting(false),
bHasTranslucentObjectShadow(bInHasTranslucentObjectShadow),
bHasInsetObjectShadow(bInHasInsetObjectShadow),
bSelfShadowOnly(false)
{
// Determine whether this light-primitive interaction produces a shadow.
if(PrimitiveSceneInfo->Proxy->HasStaticLighting())
{
const bool bHasStaticShadow =
LightSceneInfo->Proxy->HasStaticShadowing() &&
LightSceneInfo->Proxy->CastsStaticShadow() &&
PrimitiveSceneInfo->Proxy->CastsStaticShadow();
const bool bHasDynamicShadow =
!LightSceneInfo->Proxy->HasStaticLighting() &&
LightSceneInfo->Proxy->CastsDynamicShadow() &&
PrimitiveSceneInfo->Proxy->CastsDynamicShadow();
bCastShadow = bHasStaticShadow || bHasDynamicShadow;
}
else
{
bCastShadow = LightSceneInfo->Proxy->CastsDynamicShadow() && PrimitiveSceneInfo->Proxy->CastsDynamicShadow();
}
#if !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
if(bCastShadow && bIsDynamic)
{
// Determine the type of dynamic shadow produced by this light.
if (PrimitiveSceneInfo->Proxy->HasStaticLighting()
&& PrimitiveSceneInfo->Proxy->CastsStaticShadow()
&& (LightSceneInfo->Proxy->HasStaticLighting() || (LightSceneInfo->Proxy->HasStaticShadowing() && !bInIsShadowMapped)))
{
// Update the game thread's counter of number of uncached static lighting interactions.
bUncachedStaticLighting = true;
LightSceneInfo->NumUnbuiltInteractions++;
FPlatformAtomics::InterlockedIncrement(&PrimitiveSceneInfo->Scene->NumUncachedStaticLightingInteractions);
#if WITH_EDITOR
PrimitiveSceneInfo->Proxy->NumUncachedStaticLightingInteractions++;
#endif
}
}
#endif
bSelfShadowOnly = PrimitiveSceneInfo->Proxy->CastsSelfShadowOnly();
if (bIsDynamic)
{
// Add the interaction to the light's interaction list.
PrevPrimitiveLink = &LightSceneInfo->DynamicPrimitiveList;
}
NextPrimitive = *PrevPrimitiveLink;
if(*PrevPrimitiveLink)
{
(*PrevPrimitiveLink)->PrevPrimitiveLink = &NextPrimitive;
}
*PrevPrimitiveLink = this;
// Add the interaction to the primitive's interaction list.
PrevLightLink = &PrimitiveSceneInfo->LightList;
NextLight = *PrevLightLink;
if(*PrevLightLink)
{
(*PrevLightLink)->PrevLightLink = &NextLight;
}
*PrevLightLink = this;
}
FLightPrimitiveInteraction::~FLightPrimitiveInteraction()
{
check(IsInRenderingThread());
#if !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
// Update the game thread's counter of number of uncached static lighting interactions.
if(bUncachedStaticLighting)
{
LightSceneInfo->NumUnbuiltInteractions--;
FPlatformAtomics::InterlockedDecrement(&PrimitiveSceneInfo->Scene->NumUncachedStaticLightingInteractions);
#if WITH_EDITOR
PrimitiveSceneInfo->Proxy->NumUncachedStaticLightingInteractions--;
#endif
}
#endif
// Remove the interaction from the light's interaction list.
if(NextPrimitive)
{
NextPrimitive->PrevPrimitiveLink = PrevPrimitiveLink;
}
*PrevPrimitiveLink = NextPrimitive;
// Remove the interaction from the primitive's interaction list.
if(NextLight)
{
NextLight->PrevLightLink = PrevLightLink;
}
*PrevLightLink = NextLight;
}
/*-----------------------------------------------------------------------------
FStaticMesh
-----------------------------------------------------------------------------*/
void FStaticMesh::LinkDrawList(FStaticMesh::FDrawListElementLink* Link)
{
check(IsInRenderingThread());
check(!DrawListLinks.Contains(Link));
DrawListLinks.Add(Link);
}
void FStaticMesh::UnlinkDrawList(FStaticMesh::FDrawListElementLink* Link)
{
check(IsInRenderingThread());
verify(DrawListLinks.RemoveSingleSwap(Link) == 1);
}
void FStaticMesh::AddToDrawLists(FRHICommandListImmediate& RHICmdList, FScene* Scene)
{
const auto FeatureLevel = Scene->GetFeatureLevel();
if (CastShadow)
{
FShadowDepthDrawingPolicyFactory::AddStaticMesh(Scene, this);
}
if (!bShadowOnly && PrimitiveSceneInfo->Proxy->ShouldRenderInMainPass())
{
const bool bRequiresHitProxies = Scene->RequiresHitProxies();
if (bRequiresHitProxies && PrimitiveSceneInfo->Proxy->IsSelectable())
{
// Add the static mesh to the DPG's hit proxy draw list.
FHitProxyDrawingPolicyFactory::AddStaticMesh(Scene, this);
}
}
else
{
return;
}
if (IsTranslucent(FeatureLevel))
{
return;
}
if (Scene->ShouldUseDeferredRenderer())
{
extern TAutoConsoleVariable<int32> CVarEarlyZPass;
int32 EarlyZPass = CVarEarlyZPass.GetValueOnRenderThread();
extern int32 GEarlyZPassMovable;
// Render non-masked materials in the depth only pass
if (PrimitiveSceneInfo->Proxy->ShouldUseAsOccluder()
&& (!IsMasked(FeatureLevel) || EarlyZPass == 2)
&& (!PrimitiveSceneInfo->Proxy->IsMovable() || GEarlyZPassMovable))
{
FDepthDrawingPolicyFactory::AddStaticMesh(Scene,this);
}
// Add the static mesh to the DPG's base pass draw list.
FBasePassOpaqueDrawingPolicyFactory::AddStaticMesh(RHICmdList, Scene, this);
FVelocityDrawingPolicyFactory::AddStaticMesh(Scene, this);
}
else
{
// Add the static mesh to the DPG's base pass draw list.
FBasePassForwardOpaqueDrawingPolicyFactory::AddStaticMesh(RHICmdList, Scene, this);
}
}
void FStaticMesh::RemoveFromDrawLists()
{
// Remove the mesh from all draw lists.
while(DrawListLinks.Num())
{
FStaticMesh::FDrawListElementLink* Link = DrawListLinks[0];
const int32 OriginalNumLinks = DrawListLinks.Num();
// This will call UnlinkDrawList.
Link->Remove();
check(DrawListLinks.Num() == OriginalNumLinks - 1);
if(DrawListLinks.Num())
{
check(DrawListLinks[0] != Link);
}
}
}
/** Returns true if the mesh is linked to the given draw list. */
bool FStaticMesh::IsLinkedToDrawList(const FStaticMeshDrawListBase* DrawList) const
{
for (int32 i = 0; i < DrawListLinks.Num(); i++)
{
if (DrawListLinks[i]->IsInDrawList(DrawList))
{
return true;
}
}
return false;
}
FStaticMesh::~FStaticMesh()
{
// Remove this static mesh from the scene's list.
PrimitiveSceneInfo->Scene->StaticMeshes.RemoveAt(Id);
RemoveFromDrawLists();
}
/** Initialization constructor. */
FExponentialHeightFogSceneInfo::FExponentialHeightFogSceneInfo(const UExponentialHeightFogComponent* InComponent):
Component(InComponent),
FogHeight(InComponent->GetComponentLocation().Z),
// Scale the densities back down to their real scale
// Artists edit the densities scaled up so they aren't entering in minuscule floating point numbers
FogDensity(InComponent->FogDensity / 1000.0f),
FogHeightFalloff(InComponent->FogHeightFalloff / 1000.0f),
FogMaxOpacity(InComponent->FogMaxOpacity),
StartDistance(InComponent->StartDistance),
LightTerminatorAngle(0),
DirectionalInscatteringExponent(InComponent->DirectionalInscatteringExponent),
DirectionalInscatteringStartDistance(InComponent->DirectionalInscatteringStartDistance),
DirectionalInscatteringColor(InComponent->DirectionalInscatteringColor)
{
FogColor = InComponent->FogInscatteringColor;
}