Exemplo n.º 1
0
int8 ComputeLODForMeshes( const TIndirectArray<class FStaticMesh>& StaticMeshes, const FSceneView& View, const FVector4& Origin, float SphereRadius, int32 ForcedLODLevel, float ScreenSizeScale )
{
	int8 LODToRender = 0;

	// Handle forced LOD level first
	if(ForcedLODLevel >= 0)
	{
		int8 MaxLOD = 0;
		for(int32 MeshIndex = 0 ; MeshIndex < StaticMeshes.Num() ; ++MeshIndex)
		{
			const FStaticMesh&  Mesh = StaticMeshes[MeshIndex];
			MaxLOD = FMath::Max(MaxLOD, Mesh.LODIndex);
		}
		LODToRender = FMath::Clamp<int8>(ForcedLODLevel, 0, MaxLOD);
	}
	else if (View.Family->EngineShowFlags.LOD)
	{
		int32 MinLODFound = INT_MAX;
		bool bFoundLOD = false;
		int32 NumMeshes = StaticMeshes.Num();

		const float ScreenSize = ComputeBoundsScreenSize(Origin, SphereRadius, View);

		for(int32 MeshIndex = NumMeshes-1 ; MeshIndex >= 0 ; --MeshIndex)
		{
			const FStaticMesh& Mesh = StaticMeshes[MeshIndex];

			float MeshScreenSize = Mesh.ScreenSize * ScreenSizeScale;

			if(MeshScreenSize >= ScreenSize)
			{
				LODToRender = Mesh.LODIndex;
				bFoundLOD = true;
				break;
			}

			MinLODFound = FMath::Min<int32>(MinLODFound, Mesh.LODIndex);
		}

		// If no LOD was found matching the screen size, use the lowest in the array instead of LOD 0, to handle non-zero MinLOD
		if (!bFoundLOD)
		{
			LODToRender = MinLODFound;
		}
	}
	return LODToRender;
}
Exemplo n.º 2
0
int8 ComputeStaticMeshLOD( const FStaticMeshRenderData* RenderData, const FVector4& Origin, const float SphereRadius, const FSceneView& View, float FactorScale )
{
	const int32 NumLODs = MAX_STATIC_MESH_LODS;

	const float ScreenSize = ComputeBoundsScreenSize(Origin, SphereRadius, View) * FactorScale;

	// Walk backwards and return the first matching LOD
	for(int32 LODIndex = NumLODs - 1 ; LODIndex >= 0 ; --LODIndex)
	{
		if(RenderData->ScreenSize[LODIndex] > ScreenSize)
		{
			return LODIndex;
		}
	}

	return 0;
}
Exemplo n.º 3
0
int8 ComputeLODForMeshes( const TIndirectArray<class FStaticMesh>& StaticMeshes, const FSceneView& View, const FVector4& Origin, float SphereRadius, int32 ForcedLODLevel, float ScreenSizeScale )
{
	int8 LODToRender = 0;

	// Handle forced LOD level first
	if(ForcedLODLevel >= 0)
	{
		int8 MaxLOD = 0;
		for(int32 MeshIndex = 0 ; MeshIndex < StaticMeshes.Num() ; ++MeshIndex)
		{
			const FStaticMesh&  Mesh = StaticMeshes[MeshIndex];
			MaxLOD = FMath::Max(MaxLOD, Mesh.LODIndex);
		}
		LODToRender = FMath::Clamp<int8>(ForcedLODLevel, 0, MaxLOD);
	}
	else
	{
		int32 NumMeshes = StaticMeshes.Num();

		const float ScreenSize = ComputeBoundsScreenSize(Origin, SphereRadius, View);

		for(int32 MeshIndex = NumMeshes-1 ; MeshIndex >= 0 ; --MeshIndex)
		{
			const FStaticMesh& Mesh = StaticMeshes[MeshIndex];

			if(View.Family->EngineShowFlags.LOD == 1)
			{
				float MeshScreenSize = Mesh.ScreenSize * ScreenSizeScale;

				if(MeshScreenSize >= ScreenSize)
				{
					LODToRender = Mesh.LODIndex;
					break;
				}
			}
		}
	}
	return LODToRender;
}
void FStaticMeshEditorViewportClient::DrawCanvas( FViewport& InViewport, FSceneView& View, FCanvas& Canvas )
{
#if TODO_STATICMESH
	if ( StaticMesh->bHasBeenSimplified && SimplygonLogo && SimplygonLogo->Resource )
	{
		const float LogoSizeX = 64.0f;
		const float LogoSizeY = 40.65f;
		const float Padding = 6.0f;
		const float LogoX = Viewport->GetSizeXY().X - Padding - LogoSizeX;
		const float LogoY = Viewport->GetSizeXY().Y - Padding - LogoSizeY;

		Canvas->DrawTile(
			LogoX,
			LogoY,
			LogoSizeX,
			LogoSizeY,
			0.0f,
			0.0f,
			1.0f,
			1.0f,
			FLinearColor::White,
			SimplygonLogo->Resource,
			SE_BLEND_Opaque );
	}
#endif // #if TODO_STATICMESH

	auto StaticMeshEditor = StaticMeshEditorPtr.Pin();
	auto StaticMeshEditorViewport = StaticMeshEditorViewportPtr.Pin();
	if (!StaticMeshEditor.IsValid() || !StaticMeshEditorViewport.IsValid())
	{
		return;
	}

	const int32 HalfX = Viewport->GetSizeXY().X/2;
	const int32 HalfY = Viewport->GetSizeXY().Y/2;

	// Draw socket names if desired.
	if( bShowSockets )
	{
		for(int32 i=0; i<StaticMesh->Sockets.Num(); i++)
		{
			UStaticMeshSocket* Socket = StaticMesh->Sockets[i];
			if(Socket!=NULL)
			{
				FMatrix SocketTM;
				Socket->GetSocketMatrix(SocketTM, StaticMeshComponent);
				const FVector SocketPos	= SocketTM.GetOrigin();
				const FPlane proj		= View.Project( SocketPos );
				if(proj.W > 0.f)
				{
					const int32 XPos = HalfX + ( HalfX * proj.X );
					const int32 YPos = HalfY + ( HalfY * (proj.Y * -1) );

					FCanvasTextItem TextItem( FVector2D( XPos, YPos ), FText::FromString( Socket->SocketName.ToString() ), GEngine->GetSmallFont(), FLinearColor(FColor(255,196,196)) );
					Canvas.DrawItem( TextItem );	

					const UStaticMeshSocket* SelectedSocket = StaticMeshEditor->GetSelectedSocket();
					if (bManipulating && SelectedSocket == Socket)
					{
						//Figure out the text height
						FTextSizingParameters Parameters(GEngine->GetSmallFont(), 1.0f, 1.0f);
						UCanvas::CanvasStringSize(Parameters, *Socket->SocketName.ToString());
						int32 YL = FMath::TruncToInt(Parameters.DrawYL);

						DrawAngles(&Canvas, XPos, YPos + YL, 
							Widget->GetCurrentAxis(), 
							GetWidgetMode(),
							Socket->RelativeRotation,
							Socket->RelativeLocation);
					}
				}
			}
		}
	}

	TArray<SStaticMeshEditorViewport::FOverlayTextItem> TextItems;

	int32 CurrentLODLevel = StaticMeshEditor->GetCurrentLODLevel();
	if (CurrentLODLevel == 0)
	{
		CurrentLODLevel = ComputeStaticMeshLOD(StaticMesh->RenderData, StaticMeshComponent->Bounds.Origin, StaticMeshComponent->Bounds.SphereRadius, View);
	}
	else
	{
		CurrentLODLevel -= 1;
	}

	TextItems.Add(SStaticMeshEditorViewport::FOverlayTextItem(
		FText::Format(NSLOCTEXT("UnrealEd", "LOD_F", "LOD:  {0}"), FText::AsNumber(CurrentLODLevel))));

	float CurrentScreenSize = ComputeBoundsScreenSize(StaticMeshComponent->Bounds.Origin, StaticMeshComponent->Bounds.SphereRadius, View);
	FNumberFormattingOptions FormatOptions;
	FormatOptions.MinimumFractionalDigits = 3;
	FormatOptions.MaximumFractionalDigits = 6;
	FormatOptions.MaximumIntegralDigits = 6;
	TextItems.Add(SStaticMeshEditorViewport::FOverlayTextItem(
		FText::Format(NSLOCTEXT("UnrealEd", "ScreenSize_F", "Current Screen Size:  {0}"), FText::AsNumber(CurrentScreenSize, &FormatOptions))));

	TextItems.Add(SStaticMeshEditorViewport::FOverlayTextItem(
		FText::Format(NSLOCTEXT("UnrealEd", "Triangles_F", "Triangles:  {0}"), FText::AsNumber(StaticMeshEditorPtr.Pin()->GetNumTriangles(CurrentLODLevel)))));

	TextItems.Add(SStaticMeshEditorViewport::FOverlayTextItem(
		FText::Format(NSLOCTEXT("UnrealEd", "Vertices_F", "Vertices:  {0}"), FText::AsNumber(StaticMeshEditorPtr.Pin()->GetNumVertices(CurrentLODLevel)))));

	TextItems.Add(SStaticMeshEditorViewport::FOverlayTextItem(
		FText::Format(NSLOCTEXT("UnrealEd", "UVChannels_F", "UV Channels:  {0}"), FText::AsNumber(StaticMeshEditorPtr.Pin()->GetNumUVChannels(CurrentLODLevel)))));

	if( StaticMesh->RenderData->LODResources.Num() > 0 )
	{
		if (StaticMesh->RenderData->LODResources[0].DistanceFieldData != nullptr )
		{
			const FDistanceFieldVolumeData& VolumeData = *(StaticMesh->RenderData->LODResources[0].DistanceFieldData);

			if (VolumeData.Size.GetMax() > 0)
			{
				float MemoryMb = (VolumeData.Size.X * VolumeData.Size.Y * VolumeData.Size.Z * VolumeData.DistanceFieldVolume.GetTypeSize()) / (1024.0f * 1024.0f);

				FNumberFormattingOptions NumberOptions;
				NumberOptions.MinimumFractionalDigits = 2;
				NumberOptions.MaximumFractionalDigits = 2;

				if (VolumeData.bMeshWasClosed)
				{
					TextItems.Add(SStaticMeshEditorViewport::FOverlayTextItem(
						FText::Format(NSLOCTEXT("UnrealEd", "DistanceFieldRes_F", "Distance Field:  {0}x{1}x{2} = {3}Mb"), FText::AsNumber(VolumeData.Size.X), FText::AsNumber(VolumeData.Size.Y), FText::AsNumber(VolumeData.Size.Z), FText::AsNumber(MemoryMb, &NumberOptions))));
				}
				else
				{
					TextItems.Add(SStaticMeshEditorViewport::FOverlayTextItem(
						NSLOCTEXT("UnrealEd", "DistanceFieldClosed_F", "Distance Field:  Mesh was not closed and material was one-sided")));
				}
			}
		}
	}

	TextItems.Add(SStaticMeshEditorViewport::FOverlayTextItem(
		FText::Format(NSLOCTEXT("UnrealEd", "ApproxSize_F", "Approx Size: {0}x{1}x{2}"),
		FText::AsNumber(int32(StaticMesh->GetBounds().BoxExtent.X * 2.0f)), // x2 as artists wanted length not radius
		FText::AsNumber(int32(StaticMesh->GetBounds().BoxExtent.Y * 2.0f)),
		FText::AsNumber(int32(StaticMesh->GetBounds().BoxExtent.Z * 2.0f)))));

	// Show the number of collision primitives if we are drawing collision.
	if(bShowCollision && StaticMesh->BodySetup)
	{
		TextItems.Add(SStaticMeshEditorViewport::FOverlayTextItem(
			FText::Format(NSLOCTEXT("UnrealEd", "NumPrimitives_F", "Num Primitives:  {0}"), FText::AsNumber(StaticMesh->BodySetup->AggGeom.GetElementCount()))));
	}

	StaticMeshEditorViewport->PopulateOverlayText(TextItems);

	if(bDrawUVs)
	{
		const int32 YPos = 160;
		DrawUVsForMesh(Viewport, &Canvas, YPos);
	}
}
FLODMask ComputeLODForMeshes( const TIndirectArray<class FStaticMesh>& StaticMeshes, const FSceneView& View, const FVector4& Origin, float SphereRadius, int32 ForcedLODLevel, float ScreenSizeScale )
{
	FLODMask LODToRender;

	// Handle forced LOD level first
	if(ForcedLODLevel >= 0)
	{
		// Note: starting at -1 which is the default LODIndex, for cases where LODIndex didn't get set
		int8 MaxLOD = -1;
		for(int32 MeshIndex = 0 ; MeshIndex < StaticMeshes.Num() ; ++MeshIndex)
		{
			const FStaticMesh&  Mesh = StaticMeshes[MeshIndex];
			MaxLOD = FMath::Max(MaxLOD, Mesh.LODIndex);
		}
		LODToRender.SetLOD(FMath::Clamp<int8>(ForcedLODLevel, 0, MaxLOD));
	}
	else if (View.Family->EngineShowFlags.LOD)
	{
		int32 NumMeshes = StaticMeshes.Num();

		if (NumMeshes && StaticMeshes[0].bDitheredLODTransition)
		{
			for (int32 SampleIndex = 0; SampleIndex < 2; SampleIndex++)
			{
				int32 MinLODFound = INT_MAX;
				bool bFoundLOD = false;
				const float ScreenSize = ComputeTemporalLODBoundsScreenSize(Origin, SphereRadius, View, SampleIndex);

				for(int32 MeshIndex = NumMeshes-1 ; MeshIndex >= 0 ; --MeshIndex)
				{
					const FStaticMesh& Mesh = StaticMeshes[MeshIndex];

					float MeshScreenSize = Mesh.ScreenSize * ScreenSizeScale;

					if(MeshScreenSize >= ScreenSize)
					{
						LODToRender.SetLODSample(Mesh.LODIndex, SampleIndex);
						bFoundLOD = true;
						break;
					}

					MinLODFound = FMath::Min<int32>(MinLODFound, Mesh.LODIndex);
				}
				// If no LOD was found matching the screen size, use the lowest in the array instead of LOD 0, to handle non-zero MinLOD
				if (!bFoundLOD)
				{
					LODToRender.SetLODSample(MinLODFound, SampleIndex);
				}
			}
		}
		else
		{
			int32 MinLODFound = INT_MAX;
			bool bFoundLOD = false;
			const float ScreenSize = ComputeBoundsScreenSize(Origin, SphereRadius, View);

			for(int32 MeshIndex = NumMeshes-1 ; MeshIndex >= 0 ; --MeshIndex)
			{
				const FStaticMesh& Mesh = StaticMeshes[MeshIndex];

				float MeshScreenSize = Mesh.ScreenSize * ScreenSizeScale;

				if(MeshScreenSize >= ScreenSize)
				{
					LODToRender.SetLOD(Mesh.LODIndex);
					bFoundLOD = true;
					break;
				}

				MinLODFound = FMath::Min<int32>(MinLODFound, Mesh.LODIndex);
			}
			// If no LOD was found matching the screen size, use the lowest in the array instead of LOD 0, to handle non-zero MinLOD
			if (!bFoundLOD)
			{
				LODToRender.SetLOD(MinLODFound);
			}
		}
	}
	return LODToRender;
}