void FPaperSpriteSceneProxy::GetDynamicMeshElements(const TArray<const FSceneView*>& Views, const FSceneViewFamily& ViewFamily, uint32 VisibilityMap, FMeshElementCollector& Collector) const
{
	if (BodySetup != nullptr)
	{
		// Show 3D physics
		if ((ViewFamily.EngineShowFlags.Collision /*@TODO: && bIsCollisionEnabled*/) && AllowDebugViewmodes())
		{
			if (FMath::Abs(GetLocalToWorld().Determinant()) < SMALL_NUMBER)
			{
				// Catch this here or otherwise GeomTransform below will assert
				// This spams so commented out
				//UE_LOG(LogStaticMesh, Log, TEXT("Zero scaling not supported (%s)"), *StaticMesh->GetPathName());
			}
			else
			{
				for (int32 ViewIndex = 0; ViewIndex < Views.Num(); ViewIndex++)
				{
					if (VisibilityMap & (1 << ViewIndex))
					{
						// Make a material for drawing solid collision stuff
						const UMaterial* LevelColorationMaterial = ViewFamily.EngineShowFlags.Lighting 
							? GEngine->ShadedLevelColorationLitMaterial : GEngine->ShadedLevelColorationUnlitMaterial;

						auto CollisionMaterialInstance = new FColoredMaterialRenderProxy(
							LevelColorationMaterial->GetRenderProxy(IsSelected(), IsHovered()),
							WireframeColor
							);

						Collector.RegisterOneFrameMaterialProxy(CollisionMaterialInstance);

						// Draw the sprite body setup.

						// Get transform without scaling.
						FTransform GeomTransform(GetLocalToWorld());

						// In old wireframe collision mode, always draw the wireframe highlighted (selected or not).
						bool bDrawWireSelected = IsSelected();
						if (ViewFamily.EngineShowFlags.Collision)
						{
							bDrawWireSelected = true;
						}

						// Differentiate the color based on bBlockNonZeroExtent.  Helps greatly with skimming a level for optimization opportunities.
						const FColor CollisionColor = FColor(220,149,223,255);

						const bool bUseSeparateColorPerHull = (Owner == nullptr);
						const bool bDrawSolid = false;
						BodySetup->AggGeom.GetAggGeom(GeomTransform, GetSelectionColor(CollisionColor, bDrawWireSelected, IsHovered()).ToFColor(true), CollisionMaterialInstance, bUseSeparateColorPerHull, bDrawSolid, false, ViewIndex, Collector);
					}
				}
			}
		}
	}

	FPaperRenderSceneProxy::GetDynamicMeshElements(Views, ViewFamily, VisibilityMap, Collector);
}
/**
 * Renders the scene's base pass 
 * @return true if anything was rendered
 */
bool FDeferredShadingSceneRenderer::RenderBasePass()
{
	bool bDirty = false;

	if(ViewFamily.EngineShowFlags.LightMapDensity && AllowDebugViewmodes())
	{
		// Override the base pass with the lightmap density pass if the viewmode is enabled.
		bDirty = RenderLightMapDensities();
	}
	else
	{
		SCOPED_DRAW_EVENT(BasePass, DEC_SCENE_ITEMS);
		SCOPE_CYCLE_COUNTER(STAT_BasePassDrawTime);

		// Draw the scene's emissive and light-map color.
		for(int32 ViewIndex = 0;ViewIndex < Views.Num();ViewIndex++)
		{
			SCOPED_CONDITIONAL_DRAW_EVENTF(EventView, Views.Num() > 1, DEC_SCENE_ITEMS, TEXT("View%d"), ViewIndex);
			FViewInfo& View = Views[ViewIndex];

			if (ViewFamily.EngineShowFlags.ShaderComplexity)
			{
				// Additive blending when shader complexity viewmode is enabled.
				RHISetBlendState(TStaticBlendState<CW_RGBA,BO_Add,BF_One,BF_One,BO_Add,BF_Zero,BF_One>::GetRHI());
				// Disable depth writes as we have a full depth prepass.
				RHISetDepthStencilState(TStaticDepthStencilState<false,CF_GreaterEqual>::GetRHI());
			}
			else
			{
				// Opaque blending for all G buffer targets, depth tests and writes.
				RHISetBlendState(TStaticBlendStateWriteMask<CW_RGBA, CW_RGBA, CW_RGBA, CW_RGBA>::GetRHI());
				// Note, this is a reversed Z depth surface, using CF_GreaterEqual.
				RHISetDepthStencilState(TStaticDepthStencilState<true,CF_GreaterEqual>::GetRHI());
			}
			RHISetViewport(View.ViewRect.Min.X, View.ViewRect.Min.Y, 0, View.ViewRect.Max.X, View.ViewRect.Max.Y, 1);

			bDirty |= RenderBasePass(View);
		}
	}

	return bDirty;
}
void FBufferVisualizationData::Initialize()
{
	if (!bIsInitialized)
	{
		if (AllowDebugViewmodes())
		{
			check(MaterialMap.Num() == 0);

			FConfigSection* MaterialSection = GConfig->GetSectionPrivate( TEXT("Engine.BufferVisualizationMaterials"), false, true, GEngineIni );

			if (MaterialSection != NULL)
			{
				for (FConfigSection::TIterator It(*MaterialSection); It; ++It)
				{
					FString MaterialName;
					if( FParse::Value( *It.Value().GetValue(), TEXT("Material="), MaterialName, true ) )
					{
						UMaterial* Material = LoadObject<UMaterial>(NULL, *MaterialName);
			
						if (Material)
						{
							Material->AddToRoot();
							Record& Rec = MaterialMap.Add(It.Key(), Record());
							Rec.Name = It.Key().GetPlainNameString();
							Rec.Material = Material;
							FText DisplayName;
							FParse::Value( *It.Value().GetValue(), TEXT("Name="), DisplayName, TEXT("Engine.BufferVisualizationMaterials") );
							Rec.DisplayName = DisplayName;
						}
					}
				}
			}

			ConfigureConsoleCommand();
		}

		bIsInitialized = true;
	}
}
void FPaperTileMapRenderSceneProxy::GetDynamicMeshElements(const TArray<const FSceneView*>& Views, const FSceneViewFamily& ViewFamily, uint32 VisibilityMap, FMeshElementCollector& Collector) const
{
	QUICK_SCOPE_CYCLE_COUNTER(STAT_FPaperTileMapRenderSceneProxy_GetDynamicMeshElements);
	checkSlow(IsInRenderingThread());

	// Slight depth bias so that the wireframe grid overlay doesn't z-fight with the tiles themselves
	const float DepthBias = 0.0001f;

	for (int32 ViewIndex = 0; ViewIndex < Views.Num(); ViewIndex++)
	{
		if (VisibilityMap & (1 << ViewIndex))
		{
			const FSceneView* View = Views[ViewIndex];
			FPrimitiveDrawInterface* PDI = Collector.GetPDI(ViewIndex);

			// Draw the tile maps
			//@TODO: RenderThread race condition
			if (TileMap != nullptr)
			{
				FColor WireframeColor = FColor(0, 255, 255, 255);

				if ((View->Family->EngineShowFlags.Collision /*@TODO: && bIsCollisionEnabled*/) && AllowDebugViewmodes())
				{
					if (UBodySetup2D* BodySetup2D = Cast<UBodySetup2D>(TileMap->BodySetup))
					{
						//@TODO: Draw 2D debugging geometry
					}
					else if (UBodySetup* BodySetup = TileMap->BodySetup)
					{
						if (FMath::Abs(GetLocalToWorld().Determinant()) < SMALL_NUMBER)
						{
							// Catch this here or otherwise GeomTransform below will assert
							// This spams so commented out
							//UE_LOG(LogStaticMesh, Log, TEXT("Zero scaling not supported (%s)"), *StaticMesh->GetPathName());
						}
						else
						{
							// Make a material for drawing solid collision stuff
							const UMaterial* LevelColorationMaterial = View->Family->EngineShowFlags.Lighting
								? GEngine->ShadedLevelColorationLitMaterial : GEngine->ShadedLevelColorationUnlitMaterial;

							auto CollisionMaterialInstance = new FColoredMaterialRenderProxy(
								LevelColorationMaterial->GetRenderProxy(IsSelected(), IsHovered()),
								WireframeColor
								);

							// Draw the static mesh's body setup.

							// Get transform without scaling.
							FTransform GeomTransform(GetLocalToWorld());

							// In old wireframe collision mode, always draw the wireframe highlighted (selected or not).
							bool bDrawWireSelected = IsSelected();
							if (View->Family->EngineShowFlags.Collision)
							{
								bDrawWireSelected = true;
							}

							// Differentiate the color based on bBlockNonZeroExtent.  Helps greatly with skimming a level for optimization opportunities.
							FColor CollisionColor = FColor(157, 149, 223, 255);

							const bool bPerHullColor = false;
							const bool bDrawSimpleSolid = false;
							BodySetup->AggGeom.GetAggGeom(GeomTransform, GetSelectionColor(CollisionColor, bDrawWireSelected, IsHovered()), CollisionMaterialInstance, bPerHullColor, bDrawSimpleSolid, UseEditorDepthTest(), ViewIndex, Collector);
						}
					}
				}

				// Draw the bounds
				RenderBounds(PDI, View->Family->EngineShowFlags, GetBounds(), IsSelected());

#if WITH_EDITOR
				// Draw the debug outline
				if (View->Family->EngineShowFlags.Grid)
				{
					const uint8 DPG = SDPG_Foreground;//GetDepthPriorityGroup(View);

					// Draw separation wires if selected
					FLinearColor OverrideColor;
					bool bUseOverrideColor = false;

					const bool bShowAsSelected = !(GIsEditor && View->Family->EngineShowFlags.Selection) || IsSelected();
					if (bShowAsSelected || IsHovered())
					{
						bUseOverrideColor = true;
						OverrideColor = GetSelectionColor(FLinearColor::White, bShowAsSelected, IsHovered());
					}

					FTransform LocalToWorld(GetLocalToWorld());

					if (bUseOverrideColor)
					{
						const int32 SelectedLayerIndex = TileMap->SelectedLayerIndex;

						// Draw a bound for any invisible layers
						for (int32 LayerIndex = 0; LayerIndex < TileMap->TileLayers.Num(); ++LayerIndex)
						{
							if (LayerIndex != SelectedLayerIndex)
							{
								const FVector TL(LocalToWorld.TransformPosition(TileMap->GetTilePositionInLocalSpace(0, 0, LayerIndex)));
								const FVector TR(LocalToWorld.TransformPosition(TileMap->GetTilePositionInLocalSpace(TileMap->MapWidth, 0, LayerIndex)));
								const FVector BL(LocalToWorld.TransformPosition(TileMap->GetTilePositionInLocalSpace(0, TileMap->MapHeight, LayerIndex)));
								const FVector BR(LocalToWorld.TransformPosition(TileMap->GetTilePositionInLocalSpace(TileMap->MapWidth, TileMap->MapHeight, LayerIndex)));

								PDI->DrawLine(TL, TR, OverrideColor, DPG, 0.0f, DepthBias);
								PDI->DrawLine(TR, BR, OverrideColor, DPG, 0.0f, DepthBias);
								PDI->DrawLine(BR, BL, OverrideColor, DPG, 0.0f, DepthBias);
								PDI->DrawLine(BL, TL, OverrideColor, DPG, 0.0f, DepthBias);
							}
						}

						if (SelectedLayerIndex != INDEX_NONE)
						{
							// Draw horizontal lines on the selection
							for (int32 Y = 0; Y <= TileMap->MapHeight; ++Y)
							{
								int32 X = 0;
								const FVector Start(TileMap->GetTilePositionInLocalSpace(X, Y, SelectedLayerIndex));

								X = TileMap->MapWidth;
								const FVector End(TileMap->GetTilePositionInLocalSpace(X, Y, SelectedLayerIndex));

								PDI->DrawLine(LocalToWorld.TransformPosition(Start), LocalToWorld.TransformPosition(End), OverrideColor, DPG, 0.0f, DepthBias);
							}

							// Draw vertical lines
							for (int32 X = 0; X <= TileMap->MapWidth; ++X)
							{
								int32 Y = 0;
								const FVector Start(TileMap->GetTilePositionInLocalSpace(X, Y, SelectedLayerIndex));

								Y = TileMap->MapHeight;
								const FVector End(TileMap->GetTilePositionInLocalSpace(X, Y, SelectedLayerIndex));

								PDI->DrawLine(LocalToWorld.TransformPosition(Start), LocalToWorld.TransformPosition(End), OverrideColor, DPG, 0.0f, DepthBias);
							}
						}
					}
				}
#endif
			}
		}
	}

	// Draw all of the queued up sprites
	FPaperRenderSceneProxy::GetDynamicMeshElements(Views, ViewFamily, VisibilityMap, Collector);
}
void FGeometryCacheSceneProxy::GetDynamicMeshElements(const TArray<const FSceneView*>& Views, const FSceneViewFamily& ViewFamily, uint32 VisibilityMap, FMeshElementCollector& Collector) const
{
	SCOPE_CYCLE_COUNTER(STAT_GeometryCacheSceneProxy_GetMeshElements);

	// Set up wireframe material (if needed)
	const bool bWireframe = AllowDebugViewmodes() && ViewFamily.EngineShowFlags.Wireframe;

	FColoredMaterialRenderProxy* WireframeMaterialInstance = NULL;
	if (bWireframe)
	{
		WireframeMaterialInstance = new FColoredMaterialRenderProxy(
			GEngine->WireframeMaterial ? GEngine->WireframeMaterial->GetRenderProxy(IsSelected()) : NULL,
			FLinearColor(0, 0.5f, 1.f)
			);

		Collector.RegisterOneFrameMaterialProxy(WireframeMaterialInstance);
	}
	
	// Iterate over sections	
	for (const FGeomCacheTrackProxy* TrackProxy : Sections )
	{
		// QQQ
		if (TrackProxy != nullptr)
		{
			INC_DWORD_STAT_BY(STAT_GeometryCacheSceneProxy_MeshBatchCount, TrackProxy->MeshData->BatchesInfo.Num());

			int32 BatchIndex = 0;
			for (FGeometryCacheMeshBatchInfo& BatchInfo : TrackProxy->MeshData->BatchesInfo)
			{
				FMaterialRenderProxy* MaterialProxy = bWireframe ? WireframeMaterialInstance : TrackProxy->Materials[BatchIndex]->GetRenderProxy(IsSelected());

				for (int32 ViewIndex = 0; ViewIndex < Views.Num(); ViewIndex++)
				{
					if (VisibilityMap & (1 << ViewIndex))
					{
						const FSceneView* View = Views[ViewIndex];
						// Draw the mesh.
						FMeshBatch& Mesh = Collector.AllocateMesh();
						FMeshBatchElement& BatchElement = Mesh.Elements[0];
						BatchElement.IndexBuffer = &TrackProxy->IndexBuffer;
						Mesh.bWireframe = bWireframe;
						Mesh.VertexFactory = &TrackProxy->VertexFactory;
						Mesh.MaterialRenderProxy = MaterialProxy;
						BatchElement.PrimitiveUniformBuffer = CreatePrimitiveUniformBufferImmediate(TrackProxy->WorldMatrix * GetLocalToWorld(), GetBounds(), GetLocalBounds(), true, UseEditorDepthTest());
						BatchElement.FirstIndex = BatchInfo.StartIndex;
						BatchElement.NumPrimitives = BatchInfo.NumTriangles;
						BatchElement.MinVertexIndex = 0;
						BatchElement.MaxVertexIndex = TrackProxy->VertexBuffer.Vertices.Num() - 1;
						Mesh.ReverseCulling = IsLocalToWorldDeterminantNegative();
						Mesh.Type = PT_TriangleList;
						Mesh.DepthPriorityGroup = SDPG_World;
						Mesh.bCanApplyViewModeOverrides = false;
						Collector.AddMesh(ViewIndex, Mesh);

						INC_DWORD_STAT_BY(STAT_GeometryCacheSceneProxy_TriangleCount, BatchElement.NumPrimitives);
					}
				}

				++BatchIndex;
			}			
		}
		
	}

	// Draw bounds
#if !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
	for (int32 ViewIndex = 0; ViewIndex < Views.Num(); ViewIndex++)
	{
		if (VisibilityMap & (1 << ViewIndex))
		{
			// Render bounds
			RenderBounds(Collector.GetPDI(ViewIndex), ViewFamily.EngineShowFlags, GetBounds(), IsSelected());
		}
	}
#endif
}
Ejemplo n.º 6
0
void FSceneView::EndFinalPostprocessSettings(const FSceneViewInitOptions& ViewInitOptions)
{
	{
		static const auto CVarMobileMSAA = IConsoleManager::Get().FindTConsoleVariableDataInt(TEXT("r.MobileMSAA"));
		if(CVarMobileMSAA ? CVarMobileMSAA->GetValueOnGameThread() > 1 : false)
		{
			// Turn off various features which won't work with mobile MSAA.
			FinalPostProcessSettings.DepthOfFieldScale = 0.0f;
			FinalPostProcessSettings.AntiAliasingMethod = AAM_None;
		}
	}

	{
		static const auto CVar = IConsoleManager::Get().FindTConsoleVariableDataInt(TEXT("r.BloomQuality"));

		int Value = CVar->GetValueOnGameThread();

		if(Value <= 0)
		{
			FinalPostProcessSettings.BloomIntensity = 0.0f;
		}
	}

	if(!Family->EngineShowFlags.Bloom)
	{
		FinalPostProcessSettings.BloomIntensity = 0.0f;
	}

	if(!Family->EngineShowFlags.GlobalIllumination)
	{
		FinalPostProcessSettings.LPVIntensity = 0.0f;
	}

	{
		static const auto CVar = IConsoleManager::Get().FindTConsoleVariableDataInt(TEXT("r.DepthOfFieldQuality"));

		int Value = CVar->GetValueOnGameThread();

		if(Value <= 0)
		{
			FinalPostProcessSettings.DepthOfFieldScale = 0.0f;
		}
	}

	if(!Family->EngineShowFlags.DepthOfField)
	{
		FinalPostProcessSettings.DepthOfFieldScale = 0;
	}

	if(!Family->EngineShowFlags.Vignette)
	{
		FinalPostProcessSettings.VignetteIntensity = 0;
		FinalPostProcessSettings.VignetteColor = FLinearColor(0.0f, 0.0f, 0.0f);
	}

	if(!Family->EngineShowFlags.Grain)
	{
		FinalPostProcessSettings.GrainIntensity = 0;
		FinalPostProcessSettings.GrainJitter = 0;
	}

	if(!Family->EngineShowFlags.CameraImperfections)
	{
		FinalPostProcessSettings.BloomDirtMaskIntensity = 0;
	}

	if(!Family->EngineShowFlags.AmbientCubemap)
	{
		FinalPostProcessSettings.ContributingCubemaps.Empty();
	}

	if(!Family->EngineShowFlags.LensFlares)
	{
		FinalPostProcessSettings.LensFlareIntensity = 0;
	}

#if !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
	{
		float Value = CVarExposureOffset.GetValueOnGameThread();
		FinalPostProcessSettings.AutoExposureBias += Value;
	}
#endif

	{
		static const auto CVar = IConsoleManager::Get().FindTConsoleVariableDataFloat(TEXT("r.ScreenPercentage"));

		float Value = CVar->GetValueOnGameThread();

		if(Value >= 0.0)
		{
			FinalPostProcessSettings.ScreenPercentage = Value;
		}
	}

#if !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
	{
		float Value = CVarSSRMaxRoughness.GetValueOnGameThread();

		if(Value >= 0.0f)
		{
			FinalPostProcessSettings.ScreenSpaceReflectionMaxRoughness = Value;
		}
	}
#endif

	{
		static const auto CVar = IConsoleManager::Get().FindTConsoleVariableDataFloat(TEXT("r.AmbientOcclusionStaticFraction"));

		float Value = CVar->GetValueOnGameThread();

		if(Value >= 0.0)
		{
			FinalPostProcessSettings.AmbientOcclusionStaticFraction = Value;
		}
	}

	if(!Family->EngineShowFlags.ScreenPercentage || bIsSceneCapture || bIsReflectionCapture)
	{
		FinalPostProcessSettings.ScreenPercentage = 100;
	}

	if(!Family->EngineShowFlags.AmbientOcclusion)
	{
		FinalPostProcessSettings.AmbientOcclusionIntensity = 0;
	}

	{
		static const auto CVar = IConsoleManager::Get().FindTConsoleVariableDataFloat(TEXT("r.AmbientOcclusionRadiusScale"));

		float Scale = FMath::Clamp(CVar->GetValueOnGameThread(), 0.1f, 5.0f);
		
		FinalPostProcessSettings.AmbientOcclusionRadius *= Scale;
	}

	{
		float Scale = FMath::Clamp(CVarSSAOFadeRadiusScale.GetValueOnGameThread(), 0.01f, 50.0f);

		FinalPostProcessSettings.AmbientOcclusionDistance *= Scale;
	}

	{
		float Value = FMath::Clamp(CVarMotionBlurScale.GetValueOnGameThread(), 0.0f, 50.0f);

		FinalPostProcessSettings.MotionBlurAmount *= Value;
	}

	{
		float Value = CVarMotionBlurMax.GetValueOnGameThread();

		if(Value >= 0.0f)
		{
			FinalPostProcessSettings.MotionBlurMax = FMath::Min(FinalPostProcessSettings.MotionBlurMax, Value);
		}
	}

	{
		float Value = CVarSceneColorFringeMax.GetValueOnGameThread();

		if (Value >= 0.0f)
		{
			FinalPostProcessSettings.SceneFringeIntensity = FMath::Min(FinalPostProcessSettings.SceneFringeIntensity, Value);
		}
	}

	if (!Family->EngineShowFlags.Lighting || !Family->EngineShowFlags.GlobalIllumination)
	{
		FinalPostProcessSettings.IndirectLightingColor = FLinearColor(0,0,0,0);
		FinalPostProcessSettings.IndirectLightingIntensity = 0.0f;
	}

	// Anti-Aliasing
	{
		const auto FeatureLevel = GetFeatureLevel();

		static const auto CVar = IConsoleManager::Get().FindTConsoleVariableDataInt(TEXT("r.PostProcessAAQuality")); 
		static auto* MobileHDRCvar = IConsoleManager::Get().FindTConsoleVariableDataInt(TEXT("r.MobileHDR"));
		static auto* MobileMSAACvar = IConsoleManager::Get().FindTConsoleVariableDataInt(TEXT("r.MobileMSAA"));
		static uint32 MSAAValue = GShaderPlatformForFeatureLevel[FeatureLevel] == SP_OPENGL_ES2_IOS ? 1 : MobileMSAACvar->GetValueOnGameThread();

		int32 Quality = FMath::Clamp(CVar->GetValueOnGameThread(), 0, 6);

		if( !Family->EngineShowFlags.PostProcessing || !Family->EngineShowFlags.AntiAliasing || Quality <= 0
			// Disable antialiasing in GammaLDR mode to avoid jittering.
			|| (FeatureLevel == ERHIFeatureLevel::ES2 && MobileHDRCvar->GetValueOnGameThread() == 0)
			|| (FeatureLevel <= ERHIFeatureLevel::ES3_1 && (MSAAValue > 1)))
		{
			FinalPostProcessSettings.AntiAliasingMethod = AAM_None;
		}

		if( FinalPostProcessSettings.AntiAliasingMethod == AAM_TemporalAA)
		{
			if( !Family->EngineShowFlags.TemporalAA || !Family->bRealtimeUpdate || Quality < 3 )
			{
				FinalPostProcessSettings.AntiAliasingMethod = AAM_FXAA;
			}
		}

	}

	if (AllowDebugViewmodes())
	{
		ConfigureBufferVisualizationSettings();
	}

#if WITH_EDITOR
	FHighResScreenshotConfig& Config = GetHighResScreenshotConfig();

	// Pass highres screenshot materials through post process settings
	FinalPostProcessSettings.HighResScreenshotMaterial = Config.HighResScreenshotMaterial;
	FinalPostProcessSettings.HighResScreenshotMaskMaterial = Config.HighResScreenshotMaskMaterial;
	FinalPostProcessSettings.HighResScreenshotCaptureRegionMaterial = NULL;

	// If the highres screenshot UI is open and we're not taking a highres screenshot this frame
	if (Config.bDisplayCaptureRegion && !GIsHighResScreenshot)
	{
		// Only enable the capture region effect if the capture region is different from the view rectangle...
		if ((Config.UnscaledCaptureRegion != ViewRect) && (Config.UnscaledCaptureRegion.Area() > 0) && (State != NULL))
		{
			// ...and if this is the viewport associated with the highres screenshot UI
			auto ConfigViewport = Config.TargetViewport.Pin();
			if (ConfigViewport.IsValid() && Family && Family->RenderTarget == ConfigViewport->GetViewport())
			{
				static const FName ParamName = "RegionRect";
				FLinearColor NormalizedCaptureRegion;

				// Normalize capture region into view rectangle
				NormalizedCaptureRegion.R = (float)Config.UnscaledCaptureRegion.Min.X / (float)ViewRect.Width();
				NormalizedCaptureRegion.G = (float)Config.UnscaledCaptureRegion.Min.Y / (float)ViewRect.Height();
				NormalizedCaptureRegion.B = (float)Config.UnscaledCaptureRegion.Max.X / (float)ViewRect.Width();
				NormalizedCaptureRegion.A = (float)Config.UnscaledCaptureRegion.Max.Y / (float)ViewRect.Height();

				// Get a MID for drawing this frame and push the capture region into the shader parameter
				FinalPostProcessSettings.HighResScreenshotCaptureRegionMaterial = State->GetReusableMID(Config.HighResScreenshotCaptureRegionMaterial);
				FinalPostProcessSettings.HighResScreenshotCaptureRegionMaterial->SetVectorParameterValue(ParamName, NormalizedCaptureRegion);
			}
		}
	}
#endif // WITH_EDITOR


	// Upscaling or Super sampling
	{
		float LocalScreenPercentage = FinalPostProcessSettings.ScreenPercentage;

		float Fraction = 1.0f;

		// apply ScreenPercentage
		if (LocalScreenPercentage != 100.f)
		{
			Fraction = FMath::Clamp(LocalScreenPercentage / 100.0f, 0.1f, 4.0f);
		}

		// Window full screen mode with upscaling
		bool bFullscreen = false;
		if (GEngine && GEngine->GameViewport && GEngine->GameViewport->GetWindow().IsValid())
		{
			bFullscreen = GEngine->GameViewport->GetWindow()->GetWindowMode() != EWindowMode::Windowed;
		}

		check(Family->RenderTarget);

		if (bFullscreen)
		{
			// CVar mode 2 is fullscreen with upscale
			if(GSystemResolution.WindowMode == EWindowMode::WindowedFullscreen)
			{
//				FIntPoint WindowSize = Viewport->GetSizeXY();
				FIntPoint WindowSize = Family->RenderTarget->GetSizeXY();

				// allow only upscaling
				float FractionX = FMath::Clamp((float)GSystemResolution.ResX / WindowSize.X, 0.1f, 4.0f);
				float FractionY = FMath::Clamp((float)GSystemResolution.ResY / WindowSize.Y, 0.1f, 4.0f);

				// maintain a pixel aspect ratio of 1:1 for easier internal computations
				Fraction *= FMath::Max(FractionX, FractionY);
			}
		}

#if !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
		if(CVarScreenPercentageEditor.GetValueOnAnyThread() == 0)
		{
			bool bNotInGame = GEngine && GEngine->GameViewport == 0;

			if(bNotInGame)
			{
				Fraction = 1.0f;
			}
		}
#endif


		// Upscale if needed
		if (Fraction != 1.0f)
		{
			// compute the view rectangle with the ScreenPercentage applied
			const FIntRect ScreenPercentageAffectedViewRect = ViewInitOptions.GetConstrainedViewRect().Scale(Fraction);
			SetScaledViewRect(ScreenPercentageAffectedViewRect);
		}
	}
}
void FPaperTileMapRenderSceneProxy::GetDynamicMeshElements(const TArray<const FSceneView*>& Views, const FSceneViewFamily& ViewFamily, uint32 VisibilityMap, FMeshElementCollector& Collector) const
{
	SCOPE_CYCLE_COUNTER(STAT_TileMap_GetDynamicMeshElements);
	checkSlow(IsInRenderingThread());

	for (int32 ViewIndex = 0; ViewIndex < Views.Num(); ViewIndex++)
	{
		SCOPE_CYCLE_COUNTER(STAT_TileMap_EditorWireDrawing);

		if (VisibilityMap & (1 << ViewIndex))
		{
			const FSceneView* View = Views[ViewIndex];
			FPrimitiveDrawInterface* PDI = Collector.GetPDI(ViewIndex);

			// Draw the tile maps
			//@TODO: RenderThread race condition
			if (TileMap != nullptr)
			{
				if ((View->Family->EngineShowFlags.Collision /*@TODO: && bIsCollisionEnabled*/) && AllowDebugViewmodes())
				{
					if (UBodySetup2D* BodySetup2D = Cast<UBodySetup2D>(TileMap->BodySetup))
					{
						//@TODO: Draw 2D debugging geometry
					}
					else if (UBodySetup* BodySetup = TileMap->BodySetup)
					{
						if (FMath::Abs(GetLocalToWorld().Determinant()) < SMALL_NUMBER)
						{
							// Catch this here or otherwise GeomTransform below will assert
							// This spams so commented out
							//UE_LOG(LogStaticMesh, Log, TEXT("Zero scaling not supported (%s)"), *StaticMesh->GetPathName());
						}
						else
						{
							// Make a material for drawing solid collision stuff
							const UMaterial* LevelColorationMaterial = View->Family->EngineShowFlags.Lighting
								? GEngine->ShadedLevelColorationLitMaterial : GEngine->ShadedLevelColorationUnlitMaterial;

							auto CollisionMaterialInstance = new FColoredMaterialRenderProxy(
								LevelColorationMaterial->GetRenderProxy(IsSelected(), IsHovered()),
								WireframeColor
								);

							// Draw the static mesh's body setup.

							// Get transform without scaling.
							FTransform GeomTransform(GetLocalToWorld());

							// In old wireframe collision mode, always draw the wireframe highlighted (selected or not).
							bool bDrawWireSelected = IsSelected();
							if (View->Family->EngineShowFlags.Collision)
							{
								bDrawWireSelected = true;
							}

							// Differentiate the color based on bBlockNonZeroExtent.  Helps greatly with skimming a level for optimization opportunities.
							FColor CollisionColor = FColor(157, 149, 223, 255);

							const bool bPerHullColor = false;
							const bool bDrawSimpleSolid = false;
							BodySetup->AggGeom.GetAggGeom(GeomTransform, GetSelectionColor(CollisionColor, bDrawWireSelected, IsHovered()).ToFColor(true), CollisionMaterialInstance, bPerHullColor, bDrawSimpleSolid, UseEditorDepthTest(), ViewIndex, Collector);
						}
					}
				}

				// Draw the bounds
				RenderBounds(PDI, View->Family->EngineShowFlags, GetBounds(), IsSelected());

#if WITH_EDITOR
				const bool bShowAsSelected = IsSelected();
				const bool bEffectivelySelected = bShowAsSelected || IsHovered();

				const uint8 DPG = SDPG_Foreground;//GetDepthPriorityGroup(View);

				// Draw separation wires if selected
				const FLinearColor OverrideColor = GetSelectionColor(FLinearColor::White, bShowAsSelected, IsHovered(), /*bUseOverlayIntensity=*/ false);

				// Draw the debug outline
				if (bEffectivelySelected)
				{
					const int32 SelectedLayerIndex = (OnlyLayerIndex != INDEX_NONE) ? OnlyLayerIndex : TileMap->SelectedLayerIndex;

					if (bShowPerLayerGrid)
					{
						if (OnlyLayerIndex == INDEX_NONE)
						{
							// Draw a bound for every layer but the selected one (and even that one if the per-tile grid is off)
							for (int32 LayerIndex = 0; LayerIndex < TileMap->TileLayers.Num(); ++LayerIndex)
							{
								if ((LayerIndex != SelectedLayerIndex) || !bShowPerTileGrid)
								{
									DrawBoundsForLayer(PDI, OverrideColor, LayerIndex);
								}
							}
						}
						else if (!bShowPerTileGrid)
						{
							DrawBoundsForLayer(PDI, OverrideColor, OnlyLayerIndex);
						}
					}

					if (bShowPerTileGrid && (SelectedLayerIndex != INDEX_NONE))
					{
						switch (TileMap->ProjectionMode)
						{
						default:
						case ETileMapProjectionMode::Orthogonal:
						case ETileMapProjectionMode::IsometricDiamond:
							DrawNormalGridLines(PDI, OverrideColor, SelectedLayerIndex);
							break;
						case ETileMapProjectionMode::IsometricStaggered:
							DrawStaggeredGridLines(PDI, OverrideColor, SelectedLayerIndex);
							break;
						case ETileMapProjectionMode::HexagonalStaggered:
							DrawHexagonalGridLines(PDI, OverrideColor, SelectedLayerIndex);
							break;
						}
					}
				}
				else if (View->Family->EngineShowFlags.Grid && bShowOutlineWhenUnselected)
				{
					// Draw a layer rectangle even when not selected, so you can see where the tile map is in the editor
					DrawBoundsForLayer(PDI, WireframeColor, /*LayerIndex=*/ (OnlyLayerIndex != INDEX_NONE) ? OnlyLayerIndex : 0);
				}
#endif
			}
		}
	}

	// Draw all of the queued up sprites
	FPaperRenderSceneProxy::GetDynamicMeshElements(Views, ViewFamily, VisibilityMap, Collector);
}