Пример #1
0
/** Updates GCurrentSelectedLightmapSample given a selected actor's components and the location of the click. */
void SetDebugLightmapSample(TArray<UActorComponent*>* Components, UModel* Model, int32 iSurf, FVector ClickLocation)
{
	UStaticMeshComponent* SMComponent = NULL;
	if (Components)
	{
		// Find the first supported component
		for (int32 ComponentIndex = 0; ComponentIndex < Components->Num() && !SMComponent; ComponentIndex++)
		{
			SMComponent = Cast<UStaticMeshComponent>((*Components)[ComponentIndex]);
			if (SMComponent && (!SMComponent->StaticMesh || SMComponent->LODData.Num() == 0))
			{
				SMComponent = NULL;
			}
		}
	}
	 
	bool bFoundLightmapSample = false;
	// Only static mesh components and BSP handled for now
	if (SMComponent)
	{
		UStaticMesh* StaticMesh = SMComponent->StaticMesh;
		check(StaticMesh);
		check(StaticMesh->RenderData);
		check(StaticMesh->RenderData->LODResources.Num());
		// Only supporting LOD0
		const int32 LODIndex = 0;
		FStaticMeshLODResources& LODModel = StaticMesh->RenderData->LODResources[LODIndex];
		FIndexArrayView Indices = LODModel.IndexBuffer.GetArrayView();
		const bool bHasStaticLighting = SMComponent->HasStaticLighting();
		if (bHasStaticLighting)
		{
			bool bUseTextureMap = false;
			int32 LightmapSizeX = 0;
			int32 LightmapSizeY = 0;
			SMComponent->GetLightMapResolution(LightmapSizeX, LightmapSizeY);

			if (LightmapSizeX > 0 && LightmapSizeY > 0 
				&& StaticMesh->LightMapCoordinateIndex >= 0 
				&& (uint32)StaticMesh->LightMapCoordinateIndex < LODModel.VertexBuffer.GetNumTexCoords()
				)
			{
				bUseTextureMap = true;
			}
			else
			{
				bUseTextureMap = false;
			}

			// Search through the static mesh's triangles for the one that was hit (since we can't get triangle index from a line check)
			for(int32 TriangleIndex = 0; TriangleIndex < Indices.Num(); TriangleIndex += 3)
			{
				uint32 Index0 = Indices[TriangleIndex];
				uint32 Index1 = Indices[TriangleIndex + 1];
				uint32 Index2 = Indices[TriangleIndex + 2];

				// Transform positions to world space
				FVector Position0 = SMComponent->ComponentToWorld.TransformPosition(LODModel.PositionVertexBuffer.VertexPosition(Index0));
				FVector Position1 = SMComponent->ComponentToWorld.TransformPosition(LODModel.PositionVertexBuffer.VertexPosition(Index1));
				FVector Position2 = SMComponent->ComponentToWorld.TransformPosition(LODModel.PositionVertexBuffer.VertexPosition(Index2));

				FVector BaryCentricWeights;
				// Continue if click location is in the triangle and get its barycentric weights
				if (GetBarycentricWeights(Position0, Position1, Position2, ClickLocation, .001f, BaryCentricWeights))
				{
					RestoreSelectedLightmapSample();

					if (bUseTextureMap)
					{
						// Fetch lightmap UV's
						FVector2D LightmapUV0 = LODModel.VertexBuffer.GetVertexUV(Index0, StaticMesh->LightMapCoordinateIndex);
						FVector2D LightmapUV1 = LODModel.VertexBuffer.GetVertexUV(Index1, StaticMesh->LightMapCoordinateIndex);
						FVector2D LightmapUV2 = LODModel.VertexBuffer.GetVertexUV(Index2, StaticMesh->LightMapCoordinateIndex);
						// Interpolate lightmap UV's to the click location
						FVector2D InterpolatedUV = LightmapUV0 * BaryCentricWeights.X + LightmapUV1 * BaryCentricWeights.Y + LightmapUV2 * BaryCentricWeights.Z;

						int32 PaddedSizeX = LightmapSizeX;
						int32 PaddedSizeY = LightmapSizeY;
						if (GLightmassDebugOptions.bPadMappings && GAllowLightmapPadding && LightmapSizeX - 2 > 0 && LightmapSizeY - 2 > 0)
						{
							PaddedSizeX -= 2;
							PaddedSizeY -= 2;
						}

						const int32 LocalX = FMath::TruncToInt(InterpolatedUV.X * PaddedSizeX);
						const int32 LocalY = FMath::TruncToInt(InterpolatedUV.Y * PaddedSizeY);
						if (LocalX < 0 || LocalX >= PaddedSizeX
							|| LocalY < 0 || LocalY >= PaddedSizeY)
						{
							UE_LOG(LogStaticLightingSystem, Log, TEXT("Texel selection failed because the lightmap UV's wrap!"));
						}
						else
						{
							bFoundLightmapSample = UpdateSelectedTexel(SMComponent, -1, SMComponent->LODData[LODIndex].LightMap, ClickLocation, InterpolatedUV, LocalX, LocalY, LightmapSizeX, LightmapSizeY);
						}
					}

					break;
				}
			}

			if (!bFoundLightmapSample && Indices.Num() > 0)
			{
				const int32 SelectedTriangle = FMath::RandRange(0, Indices.Num() / 3 - 1);

				uint32 Index0 = Indices[SelectedTriangle];
				uint32 Index1 = Indices[SelectedTriangle + 1];
				uint32 Index2 = Indices[SelectedTriangle + 2];

				FVector2D LightmapUV0 = LODModel.VertexBuffer.GetVertexUV(Index0, StaticMesh->LightMapCoordinateIndex);
				FVector2D LightmapUV1 = LODModel.VertexBuffer.GetVertexUV(Index1, StaticMesh->LightMapCoordinateIndex);
				FVector2D LightmapUV2 = LODModel.VertexBuffer.GetVertexUV(Index2, StaticMesh->LightMapCoordinateIndex);

				FVector BaryCentricWeights;
				BaryCentricWeights.X = FMath::FRandRange(0, 1);
				BaryCentricWeights.Y = FMath::FRandRange(0, 1);

				if (BaryCentricWeights.X + BaryCentricWeights.Y >= 1)
				{
					BaryCentricWeights.X = 1 - BaryCentricWeights.X;
					BaryCentricWeights.Y = 1 - BaryCentricWeights.Y;
				}

				BaryCentricWeights.Z = 1 - BaryCentricWeights.X - BaryCentricWeights.Y;

				FVector2D InterpolatedUV = LightmapUV0 * BaryCentricWeights.X + LightmapUV1 * BaryCentricWeights.Y + LightmapUV2 * BaryCentricWeights.Z;

				UE_LOG(LogStaticLightingSystem, Log, TEXT("Failed to intersect any triangles, picking random texel"));

				int32 PaddedSizeX = LightmapSizeX;
				int32 PaddedSizeY = LightmapSizeY;
				if (GLightmassDebugOptions.bPadMappings && GAllowLightmapPadding && LightmapSizeX - 2 > 0 && LightmapSizeY - 2 > 0)
				{
					PaddedSizeX -= 2;
					PaddedSizeY -= 2;
				}

				const int32 LocalX = FMath::TruncToInt(InterpolatedUV.X * PaddedSizeX);
				const int32 LocalY = FMath::TruncToInt(InterpolatedUV.Y * PaddedSizeY);
				if (LocalX < 0 || LocalX >= PaddedSizeX
					|| LocalY < 0 || LocalY >= PaddedSizeY)
				{
					UE_LOG(LogStaticLightingSystem, Log, TEXT("Texel selection failed because the lightmap UV's wrap!"));
				}
				else
				{
					bFoundLightmapSample = UpdateSelectedTexel(SMComponent, -1, SMComponent->LODData[LODIndex].LightMap, ClickLocation, InterpolatedUV, LocalX, LocalY, LightmapSizeX, LightmapSizeY);
				}		
			}
		}
	}
	else if (Model)
	{
		UWorld* World = Model->LightingLevel->OwningWorld;
		check( World);
		for (int32 ModelIndex = 0; ModelIndex < World->GetCurrentLevel()->ModelComponents.Num(); ModelIndex++)
		{
			UModelComponent* CurrentComponent = World->GetCurrentLevel()->ModelComponents[ModelIndex];
			int32 LightmapSizeX = 0;
			int32 LightmapSizeY = 0;
			CurrentComponent->GetLightMapResolution(LightmapSizeX, LightmapSizeY);
			if (LightmapSizeX > 0 && LightmapSizeY > 0)
			{
				for (int32 ElementIndex = 0; ElementIndex < CurrentComponent->GetElements().Num(); ElementIndex++)
				{
					FModelElement& Element = CurrentComponent->GetElements()[ElementIndex];
					TScopedPointer<FRawIndexBuffer16or32>* IndexBufferRef = Model->MaterialIndexBuffers.Find(Element.Material);
					check(IndexBufferRef);
					for(uint32 TriangleIndex = Element.FirstIndex; TriangleIndex < Element.FirstIndex + Element.NumTriangles * 3; TriangleIndex += 3)
					{
						uint32 Index0 = (*IndexBufferRef)->Indices[TriangleIndex];
						uint32 Index1 = (*IndexBufferRef)->Indices[TriangleIndex + 1];
						uint32 Index2 = (*IndexBufferRef)->Indices[TriangleIndex + 2];

						FModelVertex* ModelVertices = (FModelVertex*)Model->VertexBuffer.Vertices.GetData();
						FVector Position0 = ModelVertices[Index0].Position;
						FVector Position1 = ModelVertices[Index1].Position;
						FVector Position2 = ModelVertices[Index2].Position;

						FVector BaryCentricWeights;
						// Continue if click location is in the triangle and get its barycentric weights
						if (GetBarycentricWeights(Position0, Position1, Position2, ClickLocation, .001f, BaryCentricWeights))
						{
							RestoreSelectedLightmapSample();

							// Fetch lightmap UV's
							FVector2D LightmapUV0 = ModelVertices[Index0].ShadowTexCoord;
							FVector2D LightmapUV1 = ModelVertices[Index1].ShadowTexCoord;
							FVector2D LightmapUV2 = ModelVertices[Index2].ShadowTexCoord;
							// Interpolate lightmap UV's to the click location
							FVector2D InterpolatedUV = LightmapUV0 * BaryCentricWeights.X + LightmapUV1 * BaryCentricWeights.Y + LightmapUV2 * BaryCentricWeights.Z;

							// Find the node index belonging to the selected triangle
							const UModel* CurrentModel = CurrentComponent->GetModel();
							int32 SelectedNodeIndex = INDEX_NONE;
							for (int32 ElementNodeIndex = 0; ElementNodeIndex < Element.Nodes.Num(); ElementNodeIndex++)
							{
								const FBspNode& CurrentNode = CurrentModel->Nodes[Element.Nodes[ElementNodeIndex]];
								if ((int32)Index0 >= CurrentNode.iVertexIndex && (int32)Index0 < CurrentNode.iVertexIndex + CurrentNode.NumVertices)
								{
									SelectedNodeIndex = Element.Nodes[ElementNodeIndex];
								}
							}
							check(SelectedNodeIndex >= 0);

							TArray<ULightComponentBase*> DummyLights;

							// fill out the model's NodeGroups (not the mapping part of it, but the nodes part)
							Model->GroupAllNodes(World->GetCurrentLevel(), DummyLights);

							// Find the FGatheredSurface that the selected node got put into during the last lighting rebuild
							TArray<int32> GatheredNodes;

							// find the NodeGroup that this node went into, and get all of its node
							for (TMap<int32, FNodeGroup*>::TIterator It(Model->NodeGroups); It && GatheredNodes.Num() == 0; ++It)
							{
								FNodeGroup* NodeGroup = It.Value();
								for (int32 NodeIndex = 0; NodeIndex < NodeGroup->Nodes.Num(); NodeIndex++)
								{
									if (NodeGroup->Nodes[NodeIndex] == SelectedNodeIndex)
									{
										GatheredNodes = NodeGroup->Nodes;
										break;
									}
								}
							}
							check(GatheredNodes.Num() > 0);

							// use the surface of the selected node, it will have to suffice for the GetSurfaceLightMapResolution() call
							int32 SelectedGatheredSurfIndex = Model->Nodes[SelectedNodeIndex].iSurf;

							// Get the lightmap resolution used by the FGatheredSurface containing the selected node
							FMatrix WorldToMap;
							CurrentComponent->GetSurfaceLightMapResolution(SelectedGatheredSurfIndex, 1, LightmapSizeX, LightmapSizeY, WorldToMap, &GatheredNodes);

							int32 PaddedSizeX = LightmapSizeX;
							int32 PaddedSizeY = LightmapSizeY;
							if (GLightmassDebugOptions.bPadMappings && GAllowLightmapPadding && LightmapSizeX - 2 > 0 && LightmapSizeY - 2 > 0)
							{
								PaddedSizeX -= 2;
								PaddedSizeY -= 2;
							}
							check(LightmapSizeX > 0 && LightmapSizeY > 0);

							// Apply the transform to the intersection position to find the local texel coordinates
							const FVector4 StaticLightingTextureCoordinate = WorldToMap.TransformPosition(ClickLocation);
							const int32 LocalX = FMath::TruncToInt(StaticLightingTextureCoordinate.X * PaddedSizeX);
							const int32 LocalY = FMath::TruncToInt(StaticLightingTextureCoordinate.Y * PaddedSizeY);
							check(LocalX >= 0 && LocalX < PaddedSizeX && LocalY >= 0 && LocalY < PaddedSizeY);

							bFoundLightmapSample = UpdateSelectedTexel(
								CurrentComponent, 
								SelectedNodeIndex, 
								Element.LightMap, 
								ClickLocation, 
								InterpolatedUV, 
								LocalX, LocalY,
								LightmapSizeX, LightmapSizeY);

							if (!bFoundLightmapSample)
							{
								RestoreSelectedLightmapSample();
								GCurrentSelectedLightmapSample = FSelectedLightmapSample();
							}
							return;
						}
					}
				}
			}
		}
	}

	if (!bFoundLightmapSample)
	{
		RestoreSelectedLightmapSample();
		GCurrentSelectedLightmapSample = FSelectedLightmapSample();
	}
}
Пример #2
0
	/** Add a new statistic to the internal map (or update an existing one) from the supplied component */
	UPrimitiveStats* Add(UPrimitiveComponent* InPrimitiveComponent, EPrimitiveObjectSets InObjectSet)
	{
		// Objects in transient package or transient objects are not part of level.
		if( InPrimitiveComponent->GetOutermost() == GetTransientPackage() || InPrimitiveComponent->HasAnyFlags( RF_Transient ) )
		{
			return NULL;
		}

		// Owned by a default object? Not part of a level either.
		if(InPrimitiveComponent->GetOuter() && InPrimitiveComponent->GetOuter()->IsDefaultSubobject() )
		{
			return NULL;
		}

		UStaticMeshComponent*	StaticMeshComponent		= Cast<UStaticMeshComponent>(InPrimitiveComponent);
		UModelComponent*		ModelComponent			= Cast<UModelComponent>(InPrimitiveComponent);
		USkeletalMeshComponent*	SkeletalMeshComponent	= Cast<USkeletalMeshComponent>(InPrimitiveComponent);
		ULandscapeComponent*	LandscapeComponent		= Cast<ULandscapeComponent>(InPrimitiveComponent);
		UObject*				Resource				= NULL;
		AActor*					ActorOuter				= Cast<AActor>(InPrimitiveComponent->GetOuter());

		int32 VertexColorMem		= 0;
		int32 InstVertexColorMem	= 0;
		// Calculate number of direct and other lights relevant to this component.
		int32 LightsLMCount			= 0;
		int32 LightsOtherCount		= 0;
		bool bUsesOnlyUnlitMaterials = InPrimitiveComponent->UsesOnlyUnlitMaterials();

		// The static mesh is a static mesh component's resource.
		if( StaticMeshComponent )
		{
			UStaticMesh* Mesh = StaticMeshComponent->StaticMesh;
			Resource = Mesh;

			// Calculate vertex color memory on the actual mesh.
			if( Mesh && Mesh->RenderData )
			{
				// Accumulate memory for each LOD
				for( int32 LODIndex = 0; LODIndex < Mesh->RenderData->LODResources.Num(); ++LODIndex )
				{
					VertexColorMem += Mesh->RenderData->LODResources[LODIndex].ColorVertexBuffer.GetAllocatedSize();
				}
			}

			// Calculate instanced vertex color memory used on the component.
			for( int32 LODIndex = 0; LODIndex < StaticMeshComponent->LODData.Num(); ++LODIndex )
			{
				// Accumulate memory for each LOD
				const FStaticMeshComponentLODInfo& LODInfo = StaticMeshComponent->LODData[ LODIndex ];
				if( LODInfo.OverrideVertexColors )
				{
					InstVertexColorMem += LODInfo.OverrideVertexColors->GetAllocatedSize();	
				}
			}
			// Calculate the number of lightmap and shadow map lights
			if( !bUsesOnlyUnlitMaterials )
			{
				if( StaticMeshComponent->LODData.Num() > 0 )
				{
					FStaticMeshComponentLODInfo& ComponentLODInfo = StaticMeshComponent->LODData[0];
					if( ComponentLODInfo.LightMap )
					{
						LightsLMCount = ComponentLODInfo.LightMap->LightGuids.Num();
					}
				}
			}
		}
		// A model component is its own resource.
		else if( ModelComponent )			
		{
			// Make sure model component is referenced by level.
			ULevel* Level = CastChecked<ULevel>(ModelComponent->GetOuter());
			if( Level->ModelComponents.Find( ModelComponent ) != INDEX_NONE )
			{
				Resource = ModelComponent->GetModel();

				// Calculate the number of lightmap and shadow map lights
				if( !bUsesOnlyUnlitMaterials )
				{
					const TIndirectArray<FModelElement> Elements = ModelComponent->GetElements();
					if( Elements.Num() > 0 )
					{
						if( Elements[0].LightMap )
						{
							LightsLMCount = Elements[0].LightMap->LightGuids.Num();
						}
					}
				}
			}
		}
		// The skeletal mesh of a skeletal mesh component is its resource.
		else if( SkeletalMeshComponent )
		{
			USkeletalMesh* Mesh = SkeletalMeshComponent->SkeletalMesh;
			Resource = Mesh;
			// Calculate vertex color usage for skeletal meshes
			if( Mesh )
			{
				FSkeletalMeshResource* SkelMeshResource = Mesh->GetResourceForRendering();
				for( int32 LODIndex = 0; LODIndex < SkelMeshResource->LODModels.Num(); ++LODIndex )
				{
					const FStaticLODModel& LODModel = SkelMeshResource->LODModels[ LODIndex ];
					VertexColorMem += LODModel.ColorVertexBuffer.GetVertexDataSize();
				}
			}
		}
		// The landscape of a landscape component is its resource.
		else if (LandscapeComponent)
		{
			Resource = LandscapeComponent->GetLandscapeProxy();
			if (LandscapeComponent->LightMap)
			{
				LightsLMCount = LandscapeComponent->LightMap->LightGuids.Num();
			}
		}

		UWorld* World = InPrimitiveComponent->GetWorld();
	//	check(World); // @todo: re-instate this check once the GWorld migration has completed
		/// If we should skip the actor. Skip if the actor has no outer or if we are only showing selected actors and the actor isn't selected
		const bool bShouldSkip = World == NULL || ActorOuter == NULL || (ActorOuter != NULL && InObjectSet == PrimitiveObjectSets_SelectedObjects && ActorOuter->IsSelected() == false );
		// Dont' care about components without a resource.
		if(	Resource 
			// Require actor association for selection and to disregard mesh emitter components. The exception being model components.
			&&	(!bShouldSkip || (ModelComponent && InObjectSet != PrimitiveObjectSets_SelectedObjects ) )
			// Only list primitives in visible levels
			&&	IsInVisibleLevel( InPrimitiveComponent, World ) 
			// Don't list pending kill components.
			&&	!InPrimitiveComponent->IsPendingKill() )
		{
			// Retrieve relevant lights.
			TArray<const ULightComponent*> RelevantLights;
			World->Scene->GetRelevantLights( InPrimitiveComponent, &RelevantLights );

			// Only look for relevant lights if we aren't unlit.
			if( !bUsesOnlyUnlitMaterials )
			{
				// Lightmap and shadow map lights are calculated above, per component type, infer the "other" light count here
				LightsOtherCount = RelevantLights.Num() >= LightsLMCount ? RelevantLights.Num() - LightsLMCount : 0;
			}

			// Figure out memory used by light and shadow maps and light/ shadow map resolution.
			int32 LightMapWidth			= 0;
			int32 LightMapHeight		= 0;
			InPrimitiveComponent->GetLightMapResolution( LightMapWidth, LightMapHeight );
			int32 LMSMResolution		= FMath::Sqrt( LightMapHeight * LightMapWidth );
			int32 LightMapData			= 0;
			int32 LegacyShadowMapData	= 0;
			InPrimitiveComponent->GetLightAndShadowMapMemoryUsage( LightMapData, LegacyShadowMapData );

			// Check whether we already have an entry for the associated static mesh.
			UPrimitiveStats** StatsEntryPtr = ResourceToStatsMap.Find( Resource );
			if( StatsEntryPtr )
			{
				check(*StatsEntryPtr);
				UPrimitiveStats* StatsEntry = *StatsEntryPtr;

				// We do. Update existing entry.
				StatsEntry->Count++;
				StatsEntry->Actors.AddUnique(ActorOuter);
				StatsEntry->RadiusMin		= FMath::Min( StatsEntry->RadiusMin, InPrimitiveComponent->Bounds.SphereRadius );
				StatsEntry->RadiusMax		= FMath::Max( StatsEntry->RadiusMax, InPrimitiveComponent->Bounds.SphereRadius );
				StatsEntry->RadiusAvg		+= InPrimitiveComponent->Bounds.SphereRadius;
				StatsEntry->LightsLM		+= LightsLMCount;
				StatsEntry->LightsOther		+= LightsOtherCount;
				StatsEntry->LightMapData	+= (float)LightMapData / 1024.0f;
				StatsEntry->LMSMResolution	+= LMSMResolution;
				StatsEntry->UpdateNames();

				if ( !ModelComponent && !LandscapeComponent )
				{
					// Count instanced sections
					StatsEntry->InstSections += StatsEntry->Sections;
					StatsEntry->InstTriangles += StatsEntry->Triangles;
				}

				// ... in the case of a model component (aka BSP).
				if( ModelComponent )
				{
					// If Count represents the Model itself, we do NOT want to increment it now.
					StatsEntry->Count--;

					for (const auto& Element : ModelComponent->GetElements())
					{
						StatsEntry->Triangles += Element.NumTriangles;
						StatsEntry->Sections++;
					}

					StatsEntry->InstSections = StatsEntry->Sections;
					StatsEntry->InstTriangles = StatsEntry->Triangles;
				}
				else if( StaticMeshComponent )
				{
					// This stat is used by multiple components so accumulate instanced vertex color memory.
					StatsEntry->InstVertexColorMem += (float)InstVertexColorMem / 1024.0f;
				}
				else if (LandscapeComponent)
				{
					// If Count represents the Landscape itself, we do NOT want to increment it now.
					StatsEntry->Count--;
				}
			}
			else
			{
				// We don't. Create new base entry.
				UPrimitiveStats* NewStatsEntry = NewObject<UPrimitiveStats>();
				NewStatsEntry->AddToRoot();
				NewStatsEntry->Object			= Resource;
				NewStatsEntry->Actors.AddUnique(ActorOuter);
				NewStatsEntry->Count			= 1;
				NewStatsEntry->Triangles		= 0;
				NewStatsEntry->InstTriangles	= 0;
				NewStatsEntry->ResourceSize		= (float)(FArchiveCountMem(Resource).GetNum() + Resource->GetResourceSize(EResourceSizeMode::Exclusive)) / 1024.0f;
				NewStatsEntry->Sections			= 0;
				NewStatsEntry->InstSections = 0;
				NewStatsEntry->RadiusMin		= InPrimitiveComponent->Bounds.SphereRadius;
				NewStatsEntry->RadiusAvg		= InPrimitiveComponent->Bounds.SphereRadius;
				NewStatsEntry->RadiusMax		= InPrimitiveComponent->Bounds.SphereRadius;
				NewStatsEntry->LightsLM			= LightsLMCount;
				NewStatsEntry->LightsOther		= (float)LightsOtherCount;
				NewStatsEntry->LightMapData		= (float)LightMapData / 1024.0f;
				NewStatsEntry->LMSMResolution	= LMSMResolution;
				NewStatsEntry->VertexColorMem	= (float)VertexColorMem / 1024.0f;
				NewStatsEntry->InstVertexColorMem = (float)InstVertexColorMem / 1024.0f;
				NewStatsEntry->UpdateNames();

				// Fix up triangle and section count...

				// ... in the case of a static mesh component.
				if( StaticMeshComponent )
				{
					UStaticMesh* StaticMesh = StaticMeshComponent->StaticMesh;
					if( StaticMesh && StaticMesh->RenderData )
					{
						for( int32 SectionIndex=0; SectionIndex<StaticMesh->RenderData->LODResources[0].Sections.Num(); SectionIndex++ )
						{
							const FStaticMeshSection& StaticMeshSection = StaticMesh->RenderData->LODResources[0].Sections[SectionIndex];
							NewStatsEntry->Triangles	+= StaticMeshSection.NumTriangles;
							NewStatsEntry->Sections++;
						}
					}
				}
				// ... in the case of a model component (aka BSP).
				else if( ModelComponent )
				{
					TIndirectArray<FModelElement> Elements = ModelComponent->GetElements();
					for( int32 ElementIndex=0; ElementIndex<Elements.Num(); ElementIndex++ )
					{
						const FModelElement& Element = Elements[ElementIndex];
						NewStatsEntry->Triangles += Element.NumTriangles;
						NewStatsEntry->Sections++;
					}

				}
				// ... in the case of skeletal mesh component.
				else if( SkeletalMeshComponent )
				{
					USkeletalMesh* SkeletalMesh = SkeletalMeshComponent->SkeletalMesh;
					if( SkeletalMesh )
					{
						FSkeletalMeshResource* SkelMeshResource = SkeletalMesh->GetResourceForRendering();
						if (SkelMeshResource->LODModels.Num())
						{
							const FStaticLODModel& BaseLOD = SkelMeshResource->LODModels[0];
							for( int32 SectionIndex=0; SectionIndex<BaseLOD.Sections.Num(); SectionIndex++ )
							{
								const FSkelMeshSection& Section = BaseLOD.Sections[SectionIndex];
								NewStatsEntry->Triangles += Section.NumTriangles;
								NewStatsEntry->Sections++;
							}
						}
					}
				}
				else if (LandscapeComponent)
				{
					TSet<UTexture2D*> UniqueTextures;
					for (auto ItComponents = LandscapeComponent->GetLandscapeProxy()->LandscapeComponents.CreateConstIterator(); ItComponents; ++ItComponents)
					{
						const ULandscapeComponent* CurrentComponent = *ItComponents;

						// count triangles and sections in the landscape
						NewStatsEntry->Triangles += FMath::Square(CurrentComponent->ComponentSizeQuads) * 2;
						NewStatsEntry->Sections += FMath::Square(CurrentComponent->NumSubsections);

						// count resource usage of landscape
						bool bNotUnique = false;
						UniqueTextures.Add(CurrentComponent->HeightmapTexture, &bNotUnique);
						if (!bNotUnique)
						{
							NewStatsEntry->ResourceSize += CurrentComponent->HeightmapTexture->GetResourceSize(EResourceSizeMode::Exclusive);
						}
						if (CurrentComponent->XYOffsetmapTexture)
						{
							UniqueTextures.Add(CurrentComponent->XYOffsetmapTexture, &bNotUnique);
							if (!bNotUnique)
							{
								NewStatsEntry->ResourceSize += CurrentComponent->XYOffsetmapTexture->GetResourceSize(EResourceSizeMode::Exclusive);
							}
						}

						for (auto ItWeightmaps = CurrentComponent->WeightmapTextures.CreateConstIterator(); ItWeightmaps; ++ItWeightmaps)
						{
							UniqueTextures.Add((*ItWeightmaps), &bNotUnique);
							if (!bNotUnique)
							{
								NewStatsEntry->ResourceSize += (*ItWeightmaps)->GetResourceSize(EResourceSizeMode::Exclusive);
							}
						}
					}
				}

				NewStatsEntry->InstTriangles = NewStatsEntry->Triangles;
				NewStatsEntry->InstSections = NewStatsEntry->Sections;

				// Add to map.
				ResourceToStatsMap.Add( Resource, NewStatsEntry );

				return NewStatsEntry;
			}
		}

		return NULL;
	}
Пример #3
-1
void SetLevelVisibility(ULevel* Level, bool bShouldBeVisible, bool bForceLayersVisible)
{
    // Nothing to do
    if ( Level == NULL )
    {
        return;
    }


    // Handle the case of the p-level
    // The p-level can't be unloaded, so its actors/BSP should just be temporarily hidden/unhidden
    // Also, intentionally do not force layers visible for the p-level
    if ( Level->IsPersistentLevel() )
    {
        //create a transaction so we can undo the visibilty toggle
        const FScopedTransaction Transaction( LOCTEXT( "ToggleLevelVisibility", "Toggle Level Visibility" ) );
        if ( Level->bIsVisible != bShouldBeVisible )
        {
            Level->Modify();
        }
        // Set the visibility of each actor in the p-level
        for ( TArray<AActor*>::TIterator PLevelActorIter( Level->Actors ); PLevelActorIter; ++PLevelActorIter )
        {
            AActor* CurActor = *PLevelActorIter;
            if ( CurActor && !FActorEditorUtils::IsABuilderBrush(CurActor) && CurActor->bHiddenEdLevel == bShouldBeVisible )
            {
                CurActor->Modify();
                CurActor->bHiddenEdLevel = !bShouldBeVisible;
                CurActor->RegisterAllComponents();
                CurActor->MarkComponentsRenderStateDirty();
            }
        }

        // Set the visibility of each BSP surface in the p-level
        UModel* CurLevelModel = Level->Model;
        if ( CurLevelModel )
        {
            CurLevelModel->Modify();
            for ( TArray<FBspSurf>::TIterator SurfaceIterator( CurLevelModel->Surfs ); SurfaceIterator; ++SurfaceIterator )
            {
                FBspSurf& CurSurf = *SurfaceIterator;
                CurSurf.bHiddenEdLevel = !bShouldBeVisible;
            }
        }

        // Add/remove model components from the scene
        for(int32 ComponentIndex = 0; ComponentIndex < Level->ModelComponents.Num(); ComponentIndex++)
        {
            UModelComponent* CurLevelModelCmp = Level->ModelComponents[ComponentIndex];
            if(CurLevelModelCmp)
            {
                if (bShouldBeVisible && CurLevelModelCmp)
                {
                    CurLevelModelCmp->RegisterComponentWithWorld(Level->OwningWorld);
                }
                else if (!bShouldBeVisible && CurLevelModelCmp->IsRegistered())
                {
                    CurLevelModelCmp->UnregisterComponent();
                }
            }
        }

        FEditorSupportDelegates::RedrawAllViewports.Broadcast();
    }
    else
    {
        ULevelStreaming* StreamingLevel = NULL;
        if (Level->OwningWorld == NULL || Level->OwningWorld->PersistentLevel != Level )
        {
            StreamingLevel = FLevelUtils::FindStreamingLevel( Level );
        }

        // If were hiding a level, lets make sure to close the level transform mode if its the same level currently selected for edit
        FEdModeLevel* LevelMode = static_cast<FEdModeLevel*>(GEditorModeTools().GetActiveMode( FBuiltinEditorModes::EM_Level ));
        if( LevelMode && LevelMode->IsEditing( StreamingLevel ) )
        {
            GEditorModeTools().DeactivateMode( FBuiltinEditorModes::EM_Level );
        }

        //create a transaction so we can undo the visibilty toggle
        const FScopedTransaction Transaction( LOCTEXT( "ToggleLevelVisibility", "Toggle Level Visibility" ) );

        // Handle the case of a streaming level
        if ( StreamingLevel )
        {
            // We need to set the RF_Transactional to make a streaming level serialize itself. so store the original ones, set the flag, and put the original flags back when done
            EObjectFlags cachedFlags = StreamingLevel->GetFlags();
            StreamingLevel->SetFlags( RF_Transactional );
            StreamingLevel->Modify();
            StreamingLevel->SetFlags( cachedFlags );

            // Set the visibility state for this streaming level.
            StreamingLevel->bShouldBeVisibleInEditor = bShouldBeVisible;
        }

        if( !bShouldBeVisible )
        {
            GEditor->Layers->RemoveLevelLayerInformation( Level );
        }

        // UpdateLevelStreaming sets Level->bIsVisible directly, so we need to make sure it gets saved to the transaction buffer.
        if ( Level->bIsVisible != bShouldBeVisible )
        {
            Level->Modify();
        }

        if ( StreamingLevel )
        {
            Level->OwningWorld->FlushLevelStreaming();

            // In the Editor we expect this operation will complete in a single call
            check(Level->bIsVisible == bShouldBeVisible);
        }
        else if (Level->OwningWorld != NULL)
        {
            // In case we level has no associated StreamingLevel, remove or add to world directly
            if (bShouldBeVisible)
            {
                if (!Level->bIsVisible)
                {
                    Level->OwningWorld->AddToWorld(Level);
                }
            }
            else
            {
                Level->OwningWorld->RemoveFromWorld(Level);
            }

            // In the Editor we expect this operation will complete in a single call
            check(Level->bIsVisible == bShouldBeVisible);
        }

        if( bShouldBeVisible )
        {
            GEditor->Layers->AddLevelLayerInformation( Level );
        }

        // Force the level's layers to be visible, if desired
        FEditorSupportDelegates::RedrawAllViewports.Broadcast();

        // Iterate over the level's actors, making a list of their layers and unhiding the layers.
        TTransArray<AActor*>& Actors = Level->Actors;
        for ( int32 ActorIndex = 0 ; ActorIndex < Actors.Num() ; ++ActorIndex )
        {
            AActor* Actor = Actors[ ActorIndex ];
            if ( Actor )
            {
                bool bModified = false;
                if ( bShouldBeVisible && bForceLayersVisible && GEditor->Layers->IsActorValidForLayer( Actor ) )
                {
                    // Make the actor layer visible, if it's not already.
                    if ( Actor->bHiddenEdLayer )
                    {
                        bModified = Actor->Modify();
                        Actor->bHiddenEdLayer = false;
                    }

                    const bool bIsVisible = true;
                    GEditor->Layers->SetLayersVisibility( Actor->Layers, bIsVisible );
                }

                // Set the visibility of each actor in the streaming level
                if ( !FActorEditorUtils::IsABuilderBrush(Actor) && Actor->bHiddenEdLevel == bShouldBeVisible )
                {
                    if ( !bModified )
                    {
                        bModified = Actor->Modify();
                    }
                    Actor->bHiddenEdLevel = !bShouldBeVisible;

                    if (bShouldBeVisible)
                    {
                        Actor->ReregisterAllComponents();
                    }
                    else
                    {
                        Actor->UnregisterAllComponents();
                    }
                }
            }
        }
    }

    FEditorDelegates::RefreshLayerBrowser.Broadcast();

    // Notify the Scene Outliner, as new Actors may be present in the world.
    GEngine->BroadcastLevelActorsChanged();

    // If the level is being hidden, deselect actors and surfaces that belong to this level.
    if ( !bShouldBeVisible )
    {
        USelection* SelectedActors = GEditor->GetSelectedActors();
        SelectedActors->Modify();
        TTransArray<AActor*>& Actors = Level->Actors;
        for ( int32 ActorIndex = 0 ; ActorIndex < Actors.Num() ; ++ActorIndex )
        {
            AActor* Actor = Actors[ ActorIndex ];
            if ( Actor )
            {
                SelectedActors->Deselect( Actor );
            }
        }

        DeselectAllSurfacesInLevel(Level);

        // Tell the editor selection status was changed.
        GEditor->NoteSelectionChange();
    }

    Level->bIsVisible = bShouldBeVisible;
}