You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
* This fixes the bug where many unbuilt interactions during registration would get corrected by blueprint construction scripts but the stationary light would continue to think it was built [CL 2496244 by Daniel Wright in Main branch]
259 lines
7.9 KiB
C++
259 lines
7.9 KiB
C++
// Copyright 1998-2015 Epic Games, Inc. All Rights Reserved.
|
|
|
|
/*=============================================================================
|
|
LightSceneInfo.cpp: Light scene info implementation.
|
|
=============================================================================*/
|
|
|
|
#include "RendererPrivate.h"
|
|
#include "ScenePrivate.h"
|
|
#include "DistanceFieldLightingShared.h"
|
|
|
|
int32 GWholeSceneShadowUnbuiltInteractionThreshold = 500;
|
|
static FAutoConsoleVariableRef CVarWholeSceneShadowUnbuiltInteractionThreshold(
|
|
TEXT("r.Shadow.WholeSceneShadowUnbuiltInteractionThreshold"),
|
|
GWholeSceneShadowUnbuiltInteractionThreshold,
|
|
TEXT("How many unbuilt light-primitive interactions there can be for a light before the light switches to whole scene shadows"),
|
|
ECVF_RenderThreadSafe
|
|
);
|
|
|
|
void FLightSceneInfoCompact::Init(FLightSceneInfo* InLightSceneInfo)
|
|
{
|
|
LightSceneInfo = InLightSceneInfo;
|
|
FSphere BoundingSphere(
|
|
InLightSceneInfo->Proxy->GetOrigin(),
|
|
InLightSceneInfo->Proxy->GetRadius() > 0.0f ?
|
|
InLightSceneInfo->Proxy->GetRadius() :
|
|
FLT_MAX
|
|
);
|
|
FMemory::Memcpy(&BoundingSphereVector,&BoundingSphere,sizeof(BoundingSphereVector));
|
|
Color = InLightSceneInfo->Proxy->GetColor();
|
|
LightType = InLightSceneInfo->Proxy->GetLightType();
|
|
|
|
bCastDynamicShadow = InLightSceneInfo->Proxy->CastsDynamicShadow();
|
|
bCastStaticShadow = InLightSceneInfo->Proxy->CastsStaticShadow();
|
|
bStaticLighting = InLightSceneInfo->Proxy->HasStaticLighting();
|
|
}
|
|
|
|
FLightSceneInfo::FLightSceneInfo(FLightSceneProxy* InProxy, bool InbVisible)
|
|
: Proxy(InProxy)
|
|
, DynamicPrimitiveList(NULL)
|
|
, Id(INDEX_NONE)
|
|
, TileIntersectionResources(NULL)
|
|
, bPrecomputedLightingIsValid(InProxy->GetLightComponent()->bPrecomputedLightingIsValid)
|
|
, bVisible(InbVisible)
|
|
, bEnableLightShaftBloom(InProxy->GetLightComponent()->bEnableLightShaftBloom)
|
|
, BloomScale(InProxy->GetLightComponent()->BloomScale)
|
|
, BloomThreshold(InProxy->GetLightComponent()->BloomThreshold)
|
|
, BloomTint(InProxy->GetLightComponent()->BloomTint)
|
|
, NumUnbuiltInteractions(0)
|
|
, bCreatePerObjectShadowsForDynamicObjects(Proxy->ShouldCreatePerObjectShadowsForDynamicObjects())
|
|
, Scene(InProxy->GetLightComponent()->GetScene()->GetRenderScene())
|
|
{
|
|
// Only visible lights can be added in game
|
|
check(bVisible || GIsEditor);
|
|
|
|
BeginInitResource(this);
|
|
|
|
for(uint32 LightTypeIndex = 0;LightTypeIndex < LightType_MAX;++LightTypeIndex)
|
|
{
|
|
for(uint32 A = 0;A < 2;++A)
|
|
{
|
|
for(uint32 B = 0;B < 2;++B)
|
|
{
|
|
for(uint32 C = 0;C < 2;++C)
|
|
{
|
|
TranslucentInjectCachedShaderMaps[LightTypeIndex][A][B][C] = NULL;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
FLightSceneInfo::~FLightSceneInfo()
|
|
{
|
|
ReleaseResource();
|
|
}
|
|
|
|
void FLightSceneInfo::AddToScene()
|
|
{
|
|
const FLightSceneInfoCompact& LightSceneInfoCompact = Scene->Lights[Id];
|
|
|
|
// Only need to create light interactions for lights that can cast a shadow,
|
|
// As deferred shading doesn't need to know anything about the primitives that a light affects
|
|
if (Proxy->CastsDynamicShadow()
|
|
|| Proxy->CastsStaticShadow()
|
|
// Lights that should be baked need to check for interactions to track unbuilt state correctly
|
|
|| Proxy->HasStaticLighting())
|
|
{
|
|
// Add the light to the scene's light octree.
|
|
Scene->LightOctree.AddElement(LightSceneInfoCompact);
|
|
|
|
// TODO: Special case directional lights, no need to traverse the octree.
|
|
|
|
// Find primitives that the light affects in the primitive octree.
|
|
FMemMark MemStackMark(FMemStack::Get());
|
|
for(FScenePrimitiveOctree::TConstElementBoxIterator<SceneRenderingAllocator> PrimitiveIt(
|
|
Scene->PrimitiveOctree,
|
|
GetBoundingBox()
|
|
);
|
|
PrimitiveIt.HasPendingElements();
|
|
PrimitiveIt.Advance())
|
|
{
|
|
CreateLightPrimitiveInteraction(LightSceneInfoCompact, PrimitiveIt.GetCurrentElement());
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* If the light affects the primitive, create an interaction, and process children
|
|
*
|
|
* @param LightSceneInfoCompact Compact representation of the light
|
|
* @param PrimitiveSceneInfoCompact Compact representation of the primitive
|
|
*/
|
|
void FLightSceneInfo::CreateLightPrimitiveInteraction(const FLightSceneInfoCompact& LightSceneInfoCompact, const FPrimitiveSceneInfoCompact& PrimitiveSceneInfoCompact)
|
|
{
|
|
if( LightSceneInfoCompact.AffectsPrimitive(PrimitiveSceneInfoCompact))
|
|
{
|
|
// create light interaction and add to light/primitive lists
|
|
FLightPrimitiveInteraction::Create(this,PrimitiveSceneInfoCompact.PrimitiveSceneInfo);
|
|
}
|
|
}
|
|
|
|
|
|
void FLightSceneInfo::RemoveFromScene()
|
|
{
|
|
if (OctreeId.IsValidId())
|
|
{
|
|
// Remove the light from the octree.
|
|
Scene->LightOctree.RemoveElement(OctreeId);
|
|
}
|
|
|
|
// Detach the light from the primitives it affects.
|
|
Detach();
|
|
}
|
|
|
|
void FLightSceneInfo::Detach()
|
|
{
|
|
check(IsInRenderingThread());
|
|
|
|
// implicit linked list. The destruction will update this "head" pointer to the next item in the list.
|
|
while(DynamicPrimitiveList)
|
|
{
|
|
FLightPrimitiveInteraction::Destroy(DynamicPrimitiveList);
|
|
}
|
|
}
|
|
|
|
bool FLightSceneInfo::ShouldRenderLight(const FViewInfo& View) const
|
|
{
|
|
// Only render the light if it is in the view frustum
|
|
bool bLocalVisible = bVisible ? View.VisibleLightInfos[Id].bInViewFrustum : true;
|
|
|
|
#if !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
|
|
ELightComponentType Type = (ELightComponentType)Proxy->GetLightType();
|
|
|
|
switch(Type)
|
|
{
|
|
case LightType_Directional:
|
|
if(!View.Family->EngineShowFlags.DirectionalLights)
|
|
{
|
|
bLocalVisible = false;
|
|
}
|
|
break;
|
|
case LightType_Point:
|
|
if(!View.Family->EngineShowFlags.PointLights)
|
|
{
|
|
bLocalVisible = false;
|
|
}
|
|
break;
|
|
case LightType_Spot:
|
|
if(!View.Family->EngineShowFlags.SpotLights)
|
|
{
|
|
bLocalVisible = false;
|
|
}
|
|
break;
|
|
}
|
|
#endif
|
|
|
|
return bLocalVisible
|
|
// Only render lights with static shadowing for reflection captures, since they are only captured at edit time
|
|
&& (!View.bStaticSceneOnly || Proxy->HasStaticShadowing());
|
|
}
|
|
|
|
bool FLightSceneInfo::IsPrecomputedLightingValid() const
|
|
{
|
|
return (bPrecomputedLightingIsValid && NumUnbuiltInteractions < GWholeSceneShadowUnbuiltInteractionThreshold) || !Proxy->HasStaticShadowing();
|
|
}
|
|
|
|
void FLightSceneInfo::ReleaseRHI()
|
|
{
|
|
for(uint32 LightTypeIndex = 0;LightTypeIndex < LightType_MAX;++LightTypeIndex)
|
|
{
|
|
for(uint32 A = 0;A < 2;++A)
|
|
{
|
|
for(uint32 B = 0;B < 2;++B)
|
|
{
|
|
for(uint32 C = 0;C < 2;++C)
|
|
{
|
|
TranslucentInjectBoundShaderState[LightTypeIndex][A][B][C].SafeRelease();
|
|
TranslucentInjectCachedShaderMaps[LightTypeIndex][A][B][C] = NULL;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (TileIntersectionResources)
|
|
{
|
|
TileIntersectionResources->Release();
|
|
}
|
|
}
|
|
|
|
/** Determines whether two bounding spheres intersect. */
|
|
FORCEINLINE bool AreSpheresNotIntersecting(
|
|
const VectorRegister& A_XYZ,
|
|
const VectorRegister& A_Radius,
|
|
const VectorRegister& B_XYZ,
|
|
const VectorRegister& B_Radius
|
|
)
|
|
{
|
|
const VectorRegister DeltaVector = VectorSubtract(A_XYZ,B_XYZ);
|
|
const VectorRegister DistanceSquared = VectorDot3(DeltaVector,DeltaVector);
|
|
const VectorRegister MaxDistance = VectorAdd(A_Radius,B_Radius);
|
|
const VectorRegister MaxDistanceSquared = VectorMultiply(MaxDistance,MaxDistance);
|
|
return !!VectorAnyGreaterThan(DistanceSquared,MaxDistanceSquared);
|
|
}
|
|
|
|
/**
|
|
* Tests whether this light affects the given primitive. This checks both the primitive and light settings for light relevance
|
|
* and also calls AffectsBounds.
|
|
*
|
|
* @param CompactPrimitiveSceneInfo - The primitive to test.
|
|
* @return True if the light affects the primitive.
|
|
*/
|
|
bool FLightSceneInfoCompact::AffectsPrimitive(const FPrimitiveSceneInfoCompact& CompactPrimitiveSceneInfo) const
|
|
{
|
|
// Check if the light's bounds intersect the primitive's bounds.
|
|
if(AreSpheresNotIntersecting(
|
|
BoundingSphereVector,
|
|
VectorReplicate(BoundingSphereVector,3),
|
|
VectorLoadFloat3(&CompactPrimitiveSceneInfo.Bounds.Origin),
|
|
VectorLoadFloat1(&CompactPrimitiveSceneInfo.Bounds.SphereRadius)
|
|
))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// Cull based on information in the full scene infos.
|
|
|
|
if(!LightSceneInfo->Proxy->AffectsBounds(CompactPrimitiveSceneInfo.Bounds))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (LightSceneInfo->Proxy->CastsShadowsFromCinematicObjectsOnly() && !CompactPrimitiveSceneInfo.Proxy->CastsCinematicShadow())
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|