2014-12-07 19:09:38 -05:00
// Copyright 1998-2015 Epic Games, Inc. All Rights Reserved.
2014-03-14 14:13:41 -04:00
/*=============================================================================
PrimitiveSceneInfo . cpp : Primitive scene info implementation .
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
# include "RendererPrivate.h"
# include "ScenePrivate.h"
# include "../../Engine/Classes/Components/SkeletalMeshComponent.h"
# include "ParticleDefinitions.h"
/** An implementation of FStaticPrimitiveDrawInterface that stores the drawn elements for the rendering thread to use. */
class FBatchingSPDI : public FStaticPrimitiveDrawInterface
{
public :
// Constructor.
FBatchingSPDI ( FPrimitiveSceneInfo * InPrimitiveSceneInfo ) :
PrimitiveSceneInfo ( InPrimitiveSceneInfo )
{ }
// FStaticPrimitiveDrawInterface.
virtual void SetHitProxy ( HHitProxy * HitProxy )
{
CurrentHitProxy = HitProxy ;
if ( HitProxy )
{
// Only use static scene primitive hit proxies in the editor.
if ( GIsEditor )
{
// Keep a reference to the hit proxy from the FPrimitiveSceneInfo, to ensure it isn't deleted while the static mesh still
// uses its id.
PrimitiveSceneInfo - > HitProxies . Add ( HitProxy ) ;
}
}
}
virtual void DrawMesh (
const FMeshBatch & Mesh ,
2014-05-07 05:33:26 -04:00
float ScreenSize ,
2014-03-14 14:13:41 -04:00
bool bShadowOnly
)
{
2015-03-09 14:41:36 -04:00
if ( Mesh . GetNumPrimitives ( ) > 0 )
{
check ( Mesh . VertexFactory ) ;
check ( Mesh . VertexFactory - > IsInitialized ( ) ) ;
2014-03-14 14:13:41 -04:00
# if DO_CHECK
2015-03-09 14:41:36 -04:00
Mesh . CheckUniformBuffers ( ) ;
2014-03-14 14:13:41 -04:00
# endif
2015-03-09 14:41:36 -04:00
FStaticMesh * StaticMesh = new ( PrimitiveSceneInfo - > StaticMeshes ) FStaticMesh (
PrimitiveSceneInfo ,
Mesh ,
ScreenSize ,
bShadowOnly ,
CurrentHitProxy ? CurrentHitProxy - > Id : FHitProxyId ( )
) ;
}
2014-03-14 14:13:41 -04:00
}
private :
FPrimitiveSceneInfo * PrimitiveSceneInfo ;
TRefCountPtr < HHitProxy > CurrentHitProxy ;
} ;
void FPrimitiveSceneInfoCompact : : Init ( FPrimitiveSceneInfo * InPrimitiveSceneInfo )
{
PrimitiveSceneInfo = InPrimitiveSceneInfo ;
Proxy = PrimitiveSceneInfo - > Proxy ;
Bounds = PrimitiveSceneInfo - > Proxy - > GetBounds ( ) ;
MinDrawDistance = PrimitiveSceneInfo - > Proxy - > GetMinDrawDistance ( ) ;
MaxDrawDistance = PrimitiveSceneInfo - > Proxy - > GetMaxDrawDistance ( ) ;
VisibilityId = PrimitiveSceneInfo - > Proxy - > GetVisibilityId ( ) ;
bHasViewDependentDPG = Proxy - > HasViewDependentDPG ( ) ;
bCastDynamicShadow = PrimitiveSceneInfo - > Proxy - > CastsDynamicShadow ( ) ;
bAffectDynamicIndirectLighting = PrimitiveSceneInfo - > Proxy - > AffectsDynamicIndirectLighting ( ) ;
LpvBiasMultiplier = PrimitiveSceneInfo - > Proxy - > GetLpvBiasMultiplier ( ) ;
StaticDepthPriorityGroup = bHasViewDependentDPG ? 0 : Proxy - > GetStaticDepthPriorityGroup ( ) ;
}
FPrimitiveSceneInfo : : FPrimitiveSceneInfo ( UPrimitiveComponent * InComponent , FScene * InScene ) :
Proxy ( InComponent - > SceneProxy ) ,
PrimitiveComponentId ( InComponent - > ComponentId ) ,
ComponentLastRenderTime ( & InComponent - > LastRenderTime ) ,
IndirectLightingCacheAllocation ( NULL ) ,
CachedReflectionCaptureProxy ( NULL ) ,
bNeedsCachedReflectionCaptureUpdate ( true ) ,
bVelocityIsSupressed ( false ) ,
DefaultDynamicHitProxy ( NULL ) ,
LightList ( NULL ) ,
LastRenderTime ( - FLT_MAX ) ,
LastVisibilityChangeTime ( 0.0f ) ,
Scene ( InScene ) ,
PackedIndex ( INDEX_NONE ) ,
2014-03-16 04:24:33 -04:00
ComponentForDebuggingOnly ( InComponent ) ,
2015-03-02 13:22:35 -05:00
bNeedsStaticMeshUpdate ( false )
2014-03-14 14:13:41 -04:00
{
check ( ComponentForDebuggingOnly ) ;
check ( PrimitiveComponentId . IsValid ( ) ) ;
check ( Proxy ) ;
UPrimitiveComponent * SearchParentComponent = Cast < UPrimitiveComponent > ( InComponent - > GetAttachmentRoot ( ) ) ;
if ( SearchParentComponent & & SearchParentComponent ! = InComponent )
{
LightingAttachmentRoot = SearchParentComponent - > ComponentId ;
}
2015-01-22 11:05:14 -05:00
2014-03-14 14:13:41 -04:00
// Only create hit proxies in the Editor as that's where they are used.
if ( GIsEditor )
{
// Create a dynamic hit proxy for the primitive.
DefaultDynamicHitProxy = Proxy - > CreateHitProxies ( InComponent , HitProxies ) ;
if ( DefaultDynamicHitProxy )
{
DefaultDynamicHitProxyId = DefaultDynamicHitProxy - > Id ;
}
}
2015-01-22 11:05:14 -05:00
// set LOD parent info if exists
2015-04-27 19:10:22 -04:00
UPrimitiveComponent * LODParent = InComponent - > GetLODParentPrimitive ( ) ;
if ( LODParent )
2015-01-22 11:05:14 -05:00
{
2015-04-27 19:10:22 -04:00
LODParentComponentId = LODParent - > ComponentId ;
2015-01-22 11:05:14 -05:00
}
2014-03-14 14:13:41 -04:00
}
FPrimitiveSceneInfo : : ~ FPrimitiveSceneInfo ( )
{
check ( ! OctreeId . IsValidId ( ) ) ;
}
2014-06-27 11:07:13 -04:00
void FPrimitiveSceneInfo : : AddStaticMeshes ( FRHICommandListImmediate & RHICmdList )
2014-03-14 14:13:41 -04:00
{
// Cache the primitive's static mesh elements.
FBatchingSPDI BatchingSPDI ( this ) ;
BatchingSPDI . SetHitProxy ( DefaultDynamicHitProxy ) ;
Proxy - > DrawStaticElements ( & BatchingSPDI ) ;
StaticMeshes . Shrink ( ) ;
for ( int32 MeshIndex = 0 ; MeshIndex < StaticMeshes . Num ( ) ; MeshIndex + + )
{
FStaticMesh & Mesh = StaticMeshes [ MeshIndex ] ;
// Add the static mesh to the scene's static mesh list.
FSparseArrayAllocationInfo SceneArrayAllocation = Scene - > StaticMeshes . AddUninitialized ( ) ;
Scene - > StaticMeshes [ SceneArrayAllocation . Index ] = & Mesh ;
Mesh . Id = SceneArrayAllocation . Index ;
// By this point, the index buffer render resource must be initialized
// Add the static mesh to the appropriate draw lists.
2014-06-27 11:07:13 -04:00
Mesh . AddToDrawLists ( RHICmdList , Scene ) ;
2014-03-14 14:13:41 -04:00
}
}
2014-06-27 11:07:13 -04:00
void FPrimitiveSceneInfo : : AddToScene ( FRHICommandListImmediate & RHICmdList , bool bUpdateStaticDrawLists )
2014-03-14 14:13:41 -04:00
{
check ( IsInRenderingThread ( ) ) ;
// If we are attaching a primitive that should be statically lit but has unbuilt lighting,
// Allocate space in the indirect lighting cache so that it can be used for previewing indirect lighting
if ( Proxy - > HasStaticLighting ( )
& & Proxy - > NeedsUnbuiltPreviewLighting ( )
2014-05-08 09:05:50 -04:00
& & IsIndirectLightingCacheAllowed ( Scene - > GetFeatureLevel ( ) ) )
2014-03-14 14:13:41 -04:00
{
FIndirectLightingCacheAllocation * PrimitiveAllocation = Scene - > IndirectLightingCache . FindPrimitiveAllocation ( PrimitiveComponentId ) ;
if ( PrimitiveAllocation )
{
IndirectLightingCacheAllocation = PrimitiveAllocation ;
PrimitiveAllocation - > SetDirty ( ) ;
}
else
{
PrimitiveAllocation = Scene - > IndirectLightingCache . AllocatePrimitive ( this , true ) ;
PrimitiveAllocation - > SetDirty ( ) ;
IndirectLightingCacheAllocation = PrimitiveAllocation ;
}
}
if ( bUpdateStaticDrawLists )
{
2014-06-27 11:07:13 -04:00
AddStaticMeshes ( RHICmdList ) ;
2014-03-14 14:13:41 -04:00
}
// create potential storage for our compact info
FPrimitiveSceneInfoCompact LocalCompactPrimitiveSceneInfo ;
FPrimitiveSceneInfoCompact * CompactPrimitiveSceneInfo = & LocalCompactPrimitiveSceneInfo ;
// if we are being added directly to the Octree, initialize the temp compact scene info,
// and let the Octree make a copy of it
LocalCompactPrimitiveSceneInfo . Init ( this ) ;
// Add the primitive to the octree.
check ( ! OctreeId . IsValidId ( ) ) ;
Scene - > PrimitiveOctree . AddElement ( LocalCompactPrimitiveSceneInfo ) ;
check ( OctreeId . IsValidId ( ) ) ;
// Set bounds.
FPrimitiveBounds & PrimitiveBounds = Scene - > PrimitiveBounds [ PackedIndex ] ;
FBoxSphereBounds BoxSphereBounds = Proxy - > GetBounds ( ) ;
PrimitiveBounds . Origin = BoxSphereBounds . Origin ;
PrimitiveBounds . SphereRadius = BoxSphereBounds . SphereRadius ;
PrimitiveBounds . BoxExtent = BoxSphereBounds . BoxExtent ;
PrimitiveBounds . MinDrawDistanceSq = FMath : : Square ( Proxy - > GetMinDrawDistance ( ) ) ;
PrimitiveBounds . MaxDrawDistance = Proxy - > GetMaxDrawDistance ( ) ;
// Store precomputed visibility ID.
int32 VisibilityBitIndex = Proxy - > GetVisibilityId ( ) ;
FPrimitiveVisibilityId & VisibilityId = Scene - > PrimitiveVisibilityIds [ PackedIndex ] ;
VisibilityId . ByteIndex = VisibilityBitIndex / 8 ;
VisibilityId . BitMask = ( 1 < < ( VisibilityBitIndex & 0x7 ) ) ;
// Store occlusion flags.
uint8 OcclusionFlags = EOcclusionFlags : : None ;
if ( Proxy - > CanBeOccluded ( ) )
{
OcclusionFlags | = EOcclusionFlags : : CanBeOccluded ;
}
2015-03-04 09:58:16 -05:00
if ( Proxy - > HasSubprimitiveOcclusionQueries ( ) )
{
OcclusionFlags | = EOcclusionFlags : : HasSubprimitiveQueries ;
}
2014-03-14 14:13:41 -04:00
if ( Proxy - > AllowApproximateOcclusion ( )
// Allow approximate occlusion if attached, even if the parent does not have bLightAttachmentsAsGroup enabled
| | LightingAttachmentRoot . IsValid ( ) )
{
OcclusionFlags | = EOcclusionFlags : : AllowApproximateOcclusion ;
}
if ( VisibilityBitIndex > = 0 )
{
OcclusionFlags | = EOcclusionFlags : : HasPrecomputedVisibility ;
}
Scene - > PrimitiveOcclusionFlags [ PackedIndex ] = OcclusionFlags ;
// Store occlusion bounds.
FBoxSphereBounds OcclusionBounds = BoxSphereBounds ;
if ( Proxy - > HasCustomOcclusionBounds ( ) )
{
OcclusionBounds = Proxy - > GetCustomOcclusionBounds ( ) ;
}
OcclusionBounds . BoxExtent . X = OcclusionBounds . BoxExtent . X + OCCLUSION_SLOP ;
OcclusionBounds . BoxExtent . Y = OcclusionBounds . BoxExtent . Y + OCCLUSION_SLOP ;
OcclusionBounds . BoxExtent . Z = OcclusionBounds . BoxExtent . Z + OCCLUSION_SLOP ;
OcclusionBounds . SphereRadius = OcclusionBounds . SphereRadius + OCCLUSION_SLOP ;
Scene - > PrimitiveOcclusionBounds [ PackedIndex ] = OcclusionBounds ;
// Store the component.
Scene - > PrimitiveComponentIds [ PackedIndex ] = PrimitiveComponentId ;
bNeedsCachedReflectionCaptureUpdate = true ;
{
FMemMark MemStackMark ( FMemStack : : Get ( ) ) ;
// Find lights that affect the primitive in the light octree.
for ( FSceneLightOctree : : TConstElementBoxIterator < SceneRenderingAllocator > LightIt ( Scene - > LightOctree , Proxy - > GetBounds ( ) . GetBox ( ) ) ;
LightIt . HasPendingElements ( ) ;
LightIt . Advance ( ) )
{
const FLightSceneInfoCompact & LightSceneInfoCompact = LightIt . GetCurrentElement ( ) ;
if ( LightSceneInfoCompact . AffectsPrimitive ( * CompactPrimitiveSceneInfo ) )
{
FLightPrimitiveInteraction : : Create ( LightSceneInfoCompact . LightSceneInfo , this ) ;
}
}
}
INC_MEMORY_STAT_BY ( STAT_PrimitiveInfoMemory , sizeof ( * this ) + StaticMeshes . GetAllocatedSize ( ) + Proxy - > GetMemoryFootprint ( ) ) ;
}
void FPrimitiveSceneInfo : : RemoveStaticMeshes ( )
{
// Remove static meshes from the scene.
StaticMeshes . Empty ( ) ;
}
void FPrimitiveSceneInfo : : RemoveFromScene ( bool bUpdateStaticDrawLists )
{
check ( IsInRenderingThread ( ) ) ;
// implicit linked list. The destruction will update this "head" pointer to the next item in the list.
while ( LightList )
{
FLightPrimitiveInteraction : : Destroy ( LightList ) ;
}
// Remove the primitive from the octree.
check ( OctreeId . IsValidId ( ) ) ;
check ( Scene - > PrimitiveOctree . GetElementById ( OctreeId ) . PrimitiveSceneInfo = = this ) ;
Scene - > PrimitiveOctree . RemoveElement ( OctreeId ) ;
OctreeId = FOctreeElementId ( ) ;
IndirectLightingCacheAllocation = NULL ;
DEC_MEMORY_STAT_BY ( STAT_PrimitiveInfoMemory , sizeof ( * this ) + StaticMeshes . GetAllocatedSize ( ) + Proxy - > GetMemoryFootprint ( ) ) ;
if ( bUpdateStaticDrawLists )
{
RemoveStaticMeshes ( ) ;
}
}
2014-09-15 13:41:48 -04:00
void FPrimitiveSceneInfo : : UpdateStaticMeshes ( FRHICommandListImmediate & RHICmdList )
2014-03-14 14:13:41 -04:00
{
2014-09-15 13:41:48 -04:00
checkSlow ( bNeedsStaticMeshUpdate ) ;
bNeedsStaticMeshUpdate = false ;
2014-03-14 14:13:41 -04:00
2015-03-04 08:31:40 -05:00
QUICK_SCOPE_CYCLE_COUNTER ( STAT_FPrimitiveSceneInfo_UpdateStaticMeshes ) ;
2014-09-15 13:41:48 -04:00
// Remove the primitive's static meshes from the draw lists they're currently in, and re-add them to the appropriate draw lists.
for ( int32 MeshIndex = 0 ; MeshIndex < StaticMeshes . Num ( ) ; MeshIndex + + )
{
StaticMeshes [ MeshIndex ] . RemoveFromDrawLists ( ) ;
StaticMeshes [ MeshIndex ] . AddToDrawLists ( RHICmdList , Scene ) ;
2014-03-14 14:13:41 -04:00
}
}
void FPrimitiveSceneInfo : : BeginDeferredUpdateStaticMeshes ( )
{
// Set a flag which causes InitViews to update the static meshes the next time the primitive is visible.
bNeedsStaticMeshUpdate = true ;
}
2015-01-22 11:05:14 -05:00
void FPrimitiveSceneInfo : : LinkLODParentComponent ( )
{
if ( LODParentComponentId . IsValid ( ) )
{
Scene - > SceneLODHierarchy . AddChildNode ( LODParentComponentId , this ) ;
}
}
void FPrimitiveSceneInfo : : UnlinkLODParentComponent ( )
{
if ( LODParentComponentId . IsValid ( ) )
{
Scene - > SceneLODHierarchy . RemoveChildNode ( LODParentComponentId , this ) ;
// I don't think this will be reused but just in case
LODParentComponentId = FPrimitiveComponentId ( ) ;
}
}
2014-03-14 14:13:41 -04:00
void FPrimitiveSceneInfo : : LinkAttachmentGroup ( )
{
// Add the primitive to its attachment group.
if ( LightingAttachmentRoot . IsValid ( ) )
{
FAttachmentGroupSceneInfo * AttachmentGroup = Scene - > AttachmentGroups . Find ( LightingAttachmentRoot ) ;
if ( ! AttachmentGroup )
{
// If this is the first primitive attached that uses this attachment parent, create a new attachment group.
AttachmentGroup = & Scene - > AttachmentGroups . Add ( LightingAttachmentRoot , FAttachmentGroupSceneInfo ( ) ) ;
}
AttachmentGroup - > Primitives . Add ( this ) ;
}
else if ( Proxy - > LightAttachmentsAsGroup ( ) )
{
FAttachmentGroupSceneInfo * AttachmentGroup = Scene - > AttachmentGroups . Find ( PrimitiveComponentId ) ;
if ( ! AttachmentGroup )
{
// Create an empty attachment group
AttachmentGroup = & Scene - > AttachmentGroups . Add ( PrimitiveComponentId , FAttachmentGroupSceneInfo ( ) ) ;
}
AttachmentGroup - > ParentSceneInfo = this ;
}
}
void FPrimitiveSceneInfo : : UnlinkAttachmentGroup ( )
{
// Remove the primitive from its attachment group.
if ( LightingAttachmentRoot . IsValid ( ) )
{
FAttachmentGroupSceneInfo & AttachmentGroup = Scene - > AttachmentGroups . FindChecked ( LightingAttachmentRoot ) ;
AttachmentGroup . Primitives . RemoveSwap ( this ) ;
if ( AttachmentGroup . Primitives . Num ( ) = = 0 )
{
// If this was the last primitive attached that uses this attachment root, free the group.
Scene - > AttachmentGroups . Remove ( LightingAttachmentRoot ) ;
}
}
else if ( Proxy - > LightAttachmentsAsGroup ( ) )
{
FAttachmentGroupSceneInfo * AttachmentGroup = Scene - > AttachmentGroups . Find ( PrimitiveComponentId ) ;
if ( AttachmentGroup )
{
AttachmentGroup - > ParentSceneInfo = NULL ;
}
}
}
void FPrimitiveSceneInfo : : GatherLightingAttachmentGroupPrimitives ( TArray < FPrimitiveSceneInfo * , SceneRenderingAllocator > & OutChildSceneInfos )
{
OutChildSceneInfos . Add ( this ) ;
if ( ! LightingAttachmentRoot . IsValid ( ) & & Proxy - > LightAttachmentsAsGroup ( ) )
{
const FAttachmentGroupSceneInfo * AttachmentGroup = Scene - > AttachmentGroups . Find ( PrimitiveComponentId ) ;
if ( AttachmentGroup )
{
for ( int32 ChildIndex = 0 ; ChildIndex < AttachmentGroup - > Primitives . Num ( ) ; ChildIndex + + )
{
FPrimitiveSceneInfo * ShadowChild = AttachmentGroup - > Primitives [ ChildIndex ] ;
checkSlow ( ! OutChildSceneInfos . Contains ( ShadowChild ) )
OutChildSceneInfos . Add ( ShadowChild ) ;
}
}
}
}
FBoxSphereBounds FPrimitiveSceneInfo : : GetAttachmentGroupBounds ( ) const
{
FBoxSphereBounds Bounds = Proxy - > GetBounds ( ) ;
if ( ! LightingAttachmentRoot . IsValid ( ) & & Proxy - > LightAttachmentsAsGroup ( ) )
{
const FAttachmentGroupSceneInfo * AttachmentGroup = Scene - > AttachmentGroups . Find ( PrimitiveComponentId ) ;
if ( AttachmentGroup )
{
for ( int32 ChildIndex = 0 ; ChildIndex < AttachmentGroup - > Primitives . Num ( ) ; ChildIndex + + )
{
FPrimitiveSceneInfo * AttachmentChild = AttachmentGroup - > Primitives [ ChildIndex ] ;
Bounds = Bounds + AttachmentChild - > Proxy - > GetBounds ( ) ;
}
}
}
return Bounds ;
}
uint32 FPrimitiveSceneInfo : : GetMemoryFootprint ( )
{
return ( sizeof ( * this ) + HitProxies . GetAllocatedSize ( ) + StaticMeshes . GetAllocatedSize ( ) ) ;
}
2014-09-15 13:41:48 -04:00
bool FPrimitiveSceneInfo : : ShouldRenderVelocity ( const FViewInfo & View , bool bCheckVisibility ) const
2014-03-14 14:13:41 -04:00
{
int32 PrimitiveId = GetIndex ( ) ;
2014-09-15 13:41:48 -04:00
if ( bCheckVisibility )
2014-03-14 14:13:41 -04:00
{
2014-09-15 13:41:48 -04:00
const bool bVisible = View . PrimitiveVisibilityMap [ PrimitiveId ] ;
2014-03-14 14:13:41 -04:00
2014-09-15 13:41:48 -04:00
// Only render if visible.
2015-01-14 18:33:45 -05:00
if ( ! bVisible )
2014-09-15 13:41:48 -04:00
{
return false ;
}
}
2015-01-14 18:33:45 -05:00
const FPrimitiveViewRelevance & PrimitiveViewRelevance = View . PrimitiveViewRelevanceMap [ PrimitiveId ] ;
2015-01-23 20:20:19 -05:00
if ( ! Proxy - > IsMovable ( ) )
2014-03-14 14:13:41 -04:00
{
return false ;
}
// !Skip translucent objects as they don't support velocities and in the case of particles have a significant CPU overhead.
2015-01-14 18:33:45 -05:00
if ( ! PrimitiveViewRelevance . bOpaqueRelevance | | ! PrimitiveViewRelevance . bRenderInMainPass )
2014-03-14 14:13:41 -04:00
{
return false ;
}
const float LODFactorDistanceSquared = ( Proxy - > GetBounds ( ) . Origin - View . ViewMatrices . ViewOrigin ) . SizeSquared ( ) * FMath : : Square ( View . LODDistanceFactor ) ;
// The minimum projected screen radius for a primitive to be drawn in the velocity pass, as a fraction of half the horizontal screen width (likely to be 0.08f)
float MinScreenRadiusForVelocityPass = View . FinalPostProcessSettings . MotionBlurPerObjectSize * ( 2.0f / 100.0f ) ;
float MinScreenRadiusForVelocityPassSquared = FMath : : Square ( MinScreenRadiusForVelocityPass ) ;
// Skip primitives that only cover a small amount of screenspace, motion blur on them won't be noticeable.
2015-01-14 18:33:45 -05:00
if ( FMath : : Square ( Proxy - > GetBounds ( ) . SphereRadius ) < = MinScreenRadiusForVelocityPassSquared * LODFactorDistanceSquared )
2014-03-14 14:13:41 -04:00
{
return false ;
}
// Only render primitives with velocity.
2015-01-22 17:14:31 -05:00
if ( ! FVelocityDrawingPolicy : : HasVelocity ( View , this ) )
2014-03-14 14:13:41 -04:00
{
return false ;
}
return true ;
}
2015-01-14 18:33:45 -05:00
2014-03-14 14:13:41 -04:00
void FPrimitiveSceneInfo : : ApplyWorldOffset ( FVector InOffset )
{
Proxy - > ApplyWorldOffset ( InOffset ) ;
2015-01-14 18:33:45 -05:00
}