void SetParameters(const FRenderingCompositePassContext& Context) { const FPixelShaderRHIParamRef ShaderRHI = GetPixelShader(); FGlobalShader::SetParameters(Context.RHICmdList, ShaderRHI, Context.View); DeferredParameters.Set(Context.RHICmdList, ShaderRHI, Context.View); { bool bFiltered = false; #if !(UE_BUILD_SHIPPING || UE_BUILD_TEST) bFiltered = CVarMotionBlurFiltering.GetValueOnRenderThread() != 0; #endif // !(UE_BUILD_SHIPPING || UE_BUILD_TEST) if(bFiltered) { //PostprocessParameter.SetPS(ShaderRHI, Context, TStaticSamplerState<SF_Bilinear,AM_Border,AM_Border,AM_Clamp>::GetRHI()); FSamplerStateRHIParamRef Filters[] = { TStaticSamplerState<SF_Bilinear,AM_Clamp,AM_Clamp,AM_Clamp>::GetRHI(), TStaticSamplerState<SF_Point,AM_Clamp,AM_Clamp,AM_Clamp>::GetRHI(), TStaticSamplerState<SF_Point,AM_Clamp,AM_Clamp,AM_Clamp>::GetRHI(), TStaticSamplerState<SF_Point,AM_Clamp,AM_Clamp,AM_Clamp>::GetRHI(), }; PostprocessParameter.SetPS( ShaderRHI, Context, 0, false, Filters ); } else if( CVarMotionBlurSmoothMax.GetValueOnRenderThread() ) { FSamplerStateRHIParamRef Filters[] = { TStaticSamplerState<SF_Point,AM_Clamp,AM_Clamp,AM_Clamp>::GetRHI(), TStaticSamplerState<SF_Point,AM_Clamp,AM_Clamp,AM_Clamp>::GetRHI(), TStaticSamplerState<SF_Point,AM_Clamp,AM_Clamp,AM_Clamp>::GetRHI(), TStaticSamplerState<SF_Bilinear,AM_Clamp,AM_Clamp,AM_Clamp>::GetRHI(), }; PostprocessParameter.SetPS( ShaderRHI, Context, 0, false, Filters ); } else { PostprocessParameter.SetPS(ShaderRHI, Context, TStaticSamplerState<SF_Point,AM_Clamp,AM_Clamp,AM_Clamp>::GetRHI()); } } TRefCountPtr<IPooledRenderTarget> InputPooledElement = Context.Pass->GetInput(ePId_Input0)->GetOutput()->RequestInput(); { const float SizeX = Context.View.ViewRect.Width(); const float SizeY = Context.View.ViewRect.Height(); const float AspectRatio = SizeX / SizeY; const float InvAspectRatio = SizeY / SizeX; const FSceneViewState* ViewState = (FSceneViewState*) Context.View.State; const float MotionBlurTimeScale = ViewState ? ViewState->MotionBlurTimeScale : 1.0f; const float ViewMotionBlurScale = 0.5f * MotionBlurTimeScale * Context.View.FinalPostProcessSettings.MotionBlurAmount; // 0:no 1:full screen width float MaxVelocity = Context.View.FinalPostProcessSettings.MotionBlurMax / 100.0f; float InvMaxVelocity = 1.0f / MaxVelocity; // *2 to convert to -1..1 -1..1 screen space // / MaxFraction to map screenpos to -1..1 normalized MaxFraction FVector4 MotionBlurParametersValue( ViewMotionBlurScale, AspectRatio, MaxVelocity, InvMaxVelocity); SetShaderValue(Context.RHICmdList, ShaderRHI, MotionBlurParameters, MotionBlurParametersValue); } }
void FRCPassPostProcessSubsurfaceExtractSpecular::Process(FRenderingCompositePassContext& Context) { const FPooledRenderTargetDesc* InputDesc = GetInputDesc(ePId_Input0); check(InputDesc); const FSceneView& View = Context.View; const FSceneViewFamily& ViewFamily = *(View.Family); FIntPoint SrcSize = InputDesc->Extent; FIntPoint DestSize = PassOutputs[0].RenderTargetDesc.Extent; check(DestSize.X); check(DestSize.Y); check(SrcSize.X); check(SrcSize.Y); // FIntRect SrcRect = View.ViewRect / ScaleFactor; FIntRect SrcRect = View.ViewRect; FIntRect DestRect = View.ViewRect; TRefCountPtr<IPooledRenderTarget> NewSceneColor; const FSceneRenderTargetItem& DestRenderTarget = PassOutputs[0].RequestSurface(Context); // Set the view family's render target/viewport. SetRenderTarget(Context.RHICmdList, DestRenderTarget.TargetableTexture, FTextureRHIRef()); Context.SetViewportAndCallRHI(0, 0, 0.0f, DestSize.X, DestSize.Y, 1.0f ); Context.RHICmdList.SetBlendState(TStaticBlendState<>::GetRHI()); Context.RHICmdList.SetRasterizerState(TStaticRasterizerState<>::GetRHI()); Context.RHICmdList.SetDepthStencilState(TStaticDepthStencilState<false, CF_Always>::GetRHI()); TShaderMapRef<FPostProcessVS> VertexShader(Context.GetShaderMap()); bool bDoSpecularCorrection = DoSpecularCorrection(); SCOPED_DRAW_EVENTF(Context.RHICmdList, SubsurfacePass, TEXT("SubsurfacePassExtractSpecular#%d"), (int32)bDoSpecularCorrection); uint32 SampleSet = FMath::Clamp(CVarSSSSampleSet.GetValueOnRenderThread(), 0, 2); if(bDoSpecularCorrection) { SetSubsurfaceExtractSpecular<1>(Context, SampleSet); } else { SetSubsurfaceExtractSpecular<0>(Context, SampleSet); } DrawRectangle( Context.RHICmdList, DestRect.Min.X, DestRect.Min.Y, DestRect.Width(), DestRect.Height(), SrcRect.Min.X, SrcRect.Min.Y, SrcRect.Width(), SrcRect.Height(), DestSize, SrcSize, *VertexShader, EDRF_UseTriangleOptimization); Context.RHICmdList.CopyToResolveTarget(DestRenderTarget.TargetableTexture, DestRenderTarget.ShaderResourceTexture, false, FResolveParams()); }
void ScreenSpaceReflections(FRHICommandListImmediate& RHICmdList, FViewInfo& View, TRefCountPtr<IPooledRenderTarget>& SSROutput) { BuildHZB(RHICmdList, View); FRenderingCompositePassContext CompositeContext(RHICmdList, View); FPostprocessContext Context( CompositeContext.Graph, View ); FSceneViewState* ViewState = (FSceneViewState*)Context.View.State; FRenderingCompositePass* SceneColorInput = Context.Graph.RegisterPass( new FRCPassPostProcessInput( GSceneRenderTargets.GetSceneColor() ) ); FRenderingCompositePass* HZBInput = Context.Graph.RegisterPass( new FRCPassPostProcessInput( ViewState->HZB.Texture ) ); bool bPrevFrame = 0; if( ViewState && ViewState->TemporalAAHistoryRT && !Context.View.bCameraCut ) { SceneColorInput = Context.Graph.RegisterPass( new FRCPassPostProcessInput( ViewState->TemporalAAHistoryRT ) ); bPrevFrame = 1; } { FRenderingCompositePass* TracePass = Context.Graph.RegisterPass( new FRCPassPostProcessScreenSpaceReflections( bPrevFrame ) ); TracePass->SetInput( ePId_Input0, SceneColorInput ); TracePass->SetInput( ePId_Input1, HZBInput ); Context.FinalOutput = FRenderingCompositeOutputRef( TracePass ); } const bool bTemporalFilter = View.FinalPostProcessSettings.AntiAliasingMethod != AAM_TemporalAA || CVarSSRTemporal.GetValueOnRenderThread() != 0; if( ViewState && bTemporalFilter ) { { FRenderingCompositeOutputRef HistoryInput; if( ViewState && ViewState->SSRHistoryRT && !Context.View.bCameraCut ) { HistoryInput = Context.Graph.RegisterPass( new FRCPassPostProcessInput( ViewState->SSRHistoryRT ) ); } else { // No history, use black HistoryInput = Context.Graph.RegisterPass(new FRCPassPostProcessInput(GSystemTextures.BlackDummy)); } FRenderingCompositePass* TemporalAAPass = Context.Graph.RegisterPass( new FRCPassPostProcessSSRTemporalAA ); TemporalAAPass->SetInput( ePId_Input0, Context.FinalOutput ); TemporalAAPass->SetInput( ePId_Input1, HistoryInput ); //TemporalAAPass->SetInput( ePId_Input2, VelocityInput ); Context.FinalOutput = FRenderingCompositeOutputRef( TemporalAAPass ); } if( ViewState ) { FRenderingCompositePass* HistoryOutput = Context.Graph.RegisterPass( new FRCPassPostProcessOutput( &ViewState->SSRHistoryRT ) ); HistoryOutput->SetInput( ePId_Input0, Context.FinalOutput ); Context.FinalOutput = FRenderingCompositeOutputRef( HistoryOutput ); } } { FRenderingCompositePass* ReflectionOutput = Context.Graph.RegisterPass( new FRCPassPostProcessOutput( &SSROutput ) ); ReflectionOutput->SetInput( ePId_Input0, Context.FinalOutput ); Context.FinalOutput = FRenderingCompositeOutputRef( ReflectionOutput ); } CompositeContext.Root->AddDependency( Context.FinalOutput ); CompositeContext.Process(TEXT("ReflectionEnvironments")); }
void FForwardShadingSceneRenderer::RenderForwardShadingBasePass(FRHICommandListImmediate& RHICmdList) { SCOPED_DRAW_EVENT(RHICmdList, BasePass, DEC_SCENE_ITEMS); SCOPE_CYCLE_COUNTER(STAT_BasePassDrawTime); EBasePassSort::Type SortMode = GetSortMode(); int32 MaxDraws = GMaxBasePassDraws.GetValueOnRenderThread(); if (MaxDraws <= 0) { MaxDraws = MAX_int32; } if (SortMode == EBasePassSort::SortStateBuckets) { SCOPE_CYCLE_COUNTER(STAT_SortStaticDrawLists); for (int32 DrawType = 0; DrawType < FScene::EBasePass_MAX; DrawType++) { Scene->BasePassForForwardShadingLowQualityLightMapDrawList[DrawType].SortFrontToBack(Views[0].ViewLocation); Scene->BasePassForForwardShadingDistanceFieldShadowMapLightMapDrawList[DrawType].SortFrontToBack(Views[0].ViewLocation); Scene->BasePassForForwardShadingDirectionalLightAndSHIndirectDrawList[DrawType].SortFrontToBack(Views[0].ViewLocation); Scene->BasePassForForwardShadingMovableDirectionalLightCSMDrawList[DrawType].SortFrontToBack(Views[0].ViewLocation); Scene->BasePassForForwardShadingMovableDirectionalLightDrawList[DrawType].SortFrontToBack(Views[0].ViewLocation); Scene->BasePassForForwardShadingNoLightMapDrawList[DrawType].SortFrontToBack(Views[0].ViewLocation); } } // Draw the scene's emissive and light-map color. for (int32 ViewIndex = 0; ViewIndex < Views.Num(); ViewIndex++) { SCOPED_CONDITIONAL_DRAW_EVENTF(RHICmdList, EventView, Views.Num() > 1, DEC_SCENE_ITEMS, TEXT("View%d"), ViewIndex); FViewInfo& View = Views[ViewIndex]; // Opaque blending RHICmdList.SetBlendState(TStaticBlendStateWriteMask<CW_RGBA>::GetRHI()); // Note, this is a reversed Z depth surface, using CF_GreaterEqual. RHICmdList.SetDepthStencilState(TStaticDepthStencilState<true, CF_GreaterEqual>::GetRHI()); RHICmdList.SetViewport(View.ViewRect.Min.X, View.ViewRect.Min.Y, 0, View.ViewRect.Max.X, View.ViewRect.Max.Y, 1); { // Render the base pass static data if (SortMode == EBasePassSort::SortPerMesh) { SCOPE_CYCLE_COUNTER(STAT_StaticDrawListDrawTime); MaxDraws -= Scene->BasePassForForwardShadingLowQualityLightMapDrawList[FScene::EBasePass_Default].DrawVisibleFrontToBack(RHICmdList, View, View.StaticMeshVisibilityMap, View.StaticMeshBatchVisibility, MaxDraws); MaxDraws -= Scene->BasePassForForwardShadingDistanceFieldShadowMapLightMapDrawList[FScene::EBasePass_Default].DrawVisibleFrontToBack(RHICmdList, View, View.StaticMeshVisibilityMap, View.StaticMeshBatchVisibility, MaxDraws); MaxDraws -= Scene->BasePassForForwardShadingDirectionalLightAndSHIndirectDrawList[FScene::EBasePass_Default].DrawVisibleFrontToBack(RHICmdList, View, View.StaticMeshVisibilityMap, View.StaticMeshBatchVisibility, MaxDraws); MaxDraws -= Scene->BasePassForForwardShadingMovableDirectionalLightCSMDrawList[FScene::EBasePass_Default].DrawVisibleFrontToBack(RHICmdList, View, View.StaticMeshVisibilityMap, View.StaticMeshBatchVisibility, MaxDraws); MaxDraws -= Scene->BasePassForForwardShadingMovableDirectionalLightDrawList[FScene::EBasePass_Default].DrawVisibleFrontToBack(RHICmdList, View, View.StaticMeshVisibilityMap, View.StaticMeshBatchVisibility, MaxDraws); MaxDraws -= Scene->BasePassForForwardShadingNoLightMapDrawList[FScene::EBasePass_Default].DrawVisibleFrontToBack(RHICmdList, View, View.StaticMeshVisibilityMap, View.StaticMeshBatchVisibility, MaxDraws); } else { SCOPE_CYCLE_COUNTER(STAT_StaticDrawListDrawTime); Scene->BasePassForForwardShadingLowQualityLightMapDrawList[FScene::EBasePass_Default].DrawVisible(RHICmdList, View, View.StaticMeshVisibilityMap, View.StaticMeshBatchVisibility); Scene->BasePassForForwardShadingDistanceFieldShadowMapLightMapDrawList[FScene::EBasePass_Default].DrawVisible(RHICmdList, View, View.StaticMeshVisibilityMap, View.StaticMeshBatchVisibility); Scene->BasePassForForwardShadingDirectionalLightAndSHIndirectDrawList[FScene::EBasePass_Default].DrawVisible(RHICmdList, View, View.StaticMeshVisibilityMap, View.StaticMeshBatchVisibility); Scene->BasePassForForwardShadingMovableDirectionalLightCSMDrawList[FScene::EBasePass_Default].DrawVisible(RHICmdList, View, View.StaticMeshVisibilityMap, View.StaticMeshBatchVisibility); Scene->BasePassForForwardShadingMovableDirectionalLightDrawList[FScene::EBasePass_Default].DrawVisible(RHICmdList, View, View.StaticMeshVisibilityMap, View.StaticMeshBatchVisibility); Scene->BasePassForForwardShadingNoLightMapDrawList[FScene::EBasePass_Default].DrawVisible(RHICmdList, View, View.StaticMeshVisibilityMap, View.StaticMeshBatchVisibility); } } { SCOPE_CYCLE_COUNTER(STAT_DynamicPrimitiveDrawTime); SCOPED_DRAW_EVENT(RHICmdList, Dynamic, DEC_SCENE_ITEMS); const bool bUseGetMeshElements = ShouldUseGetDynamicMeshElements(); if (bUseGetMeshElements) { FBasePassForwardOpaqueDrawingPolicyFactory::ContextType Context(ESceneRenderTargetsMode::DontSet); for (int32 MeshBatchIndex = 0; MeshBatchIndex < View.DynamicMeshElements.Num(); MeshBatchIndex++) { const FMeshBatchAndRelevance& MeshBatchAndRelevance = View.DynamicMeshElements[MeshBatchIndex]; if (MeshBatchAndRelevance.bHasOpaqueOrMaskedMaterial || ViewFamily.EngineShowFlags.Wireframe) { const FMeshBatch& MeshBatch = *MeshBatchAndRelevance.Mesh; FBasePassForwardOpaqueDrawingPolicyFactory::DrawDynamicMesh(RHICmdList, View, Context, MeshBatch, false, true, MeshBatchAndRelevance.PrimitiveSceneProxy, MeshBatch.BatchHitProxyId); } } View.SimpleElementCollector.DrawBatchedElements(RHICmdList, View, NULL, EBlendModeFilter::OpaqueAndMasked); } else if (View.VisibleDynamicPrimitives.Num() > 0) { // Draw the dynamic non-occluded primitives using a base pass drawing policy. TDynamicPrimitiveDrawer<FBasePassForwardOpaqueDrawingPolicyFactory> Drawer(RHICmdList, &View, FBasePassForwardOpaqueDrawingPolicyFactory::ContextType(ESceneRenderTargetsMode::DontSet), true); for (int32 PrimitiveIndex = 0; PrimitiveIndex < View.VisibleDynamicPrimitives.Num(); PrimitiveIndex++) { const FPrimitiveSceneInfo* PrimitiveSceneInfo = View.VisibleDynamicPrimitives[PrimitiveIndex]; int32 PrimitiveId = PrimitiveSceneInfo->GetIndex(); const FPrimitiveViewRelevance& PrimitiveViewRelevance = View.PrimitiveViewRelevanceMap[PrimitiveId]; const bool bVisible = View.PrimitiveVisibilityMap[PrimitiveId]; // Only draw the primitive if it's visible if (bVisible && // only draw opaque and masked primitives if wireframe is disabled (PrimitiveViewRelevance.bOpaqueRelevance || ViewFamily.EngineShowFlags.Wireframe)) { FScopeCycleCounter Context(PrimitiveSceneInfo->Proxy->GetStatId()); Drawer.SetPrimitive(PrimitiveSceneInfo->Proxy); PrimitiveSceneInfo->Proxy->DrawDynamicElements(&Drawer, &View); } } } const bool bNeedToSwitchVerticalAxis = RHINeedsToSwitchVerticalAxis(GShaderPlatformForFeatureLevel[FeatureLevel]); // Draw the base pass for the view's batched mesh elements. DrawViewElements<FBasePassForwardOpaqueDrawingPolicyFactory>(RHICmdList, View, FBasePassForwardOpaqueDrawingPolicyFactory::ContextType(ESceneRenderTargetsMode::DontSet), SDPG_World, true); // Draw the view's batched simple elements(lines, sprites, etc). View.BatchedViewElements.Draw(RHICmdList, FeatureLevel, bNeedToSwitchVerticalAxis, View.ViewProjectionMatrix, View.ViewRect.Width(), View.ViewRect.Height(), false); // Draw foreground objects last DrawViewElements<FBasePassForwardOpaqueDrawingPolicyFactory>(RHICmdList, View, FBasePassForwardOpaqueDrawingPolicyFactory::ContextType(ESceneRenderTargetsMode::DontSet), SDPG_Foreground, true); // Draw the view's batched simple elements(lines, sprites, etc). View.TopBatchedViewElements.Draw(RHICmdList, FeatureLevel, bNeedToSwitchVerticalAxis, View.ViewProjectionMatrix, View.ViewRect.Width(), View.ViewRect.Height(), false); } // Issue static draw list masked draw calls last, as PVR wants it if (SortMode == EBasePassSort::SortPerMesh) { SCOPE_CYCLE_COUNTER(STAT_StaticDrawListDrawTime); MaxDraws -= Scene->BasePassForForwardShadingNoLightMapDrawList[FScene::EBasePass_Masked].DrawVisibleFrontToBack(RHICmdList, View,View.StaticMeshVisibilityMap,View.StaticMeshBatchVisibility,MaxDraws); MaxDraws -= Scene->BasePassForForwardShadingLowQualityLightMapDrawList[FScene::EBasePass_Masked].DrawVisibleFrontToBack(RHICmdList, View,View.StaticMeshVisibilityMap,View.StaticMeshBatchVisibility,MaxDraws); MaxDraws -= Scene->BasePassForForwardShadingDistanceFieldShadowMapLightMapDrawList[FScene::EBasePass_Masked].DrawVisibleFrontToBack(RHICmdList, View,View.StaticMeshVisibilityMap,View.StaticMeshBatchVisibility,MaxDraws); MaxDraws -= Scene->BasePassForForwardShadingDirectionalLightAndSHIndirectDrawList[FScene::EBasePass_Masked].DrawVisibleFrontToBack(RHICmdList, View,View.StaticMeshVisibilityMap,View.StaticMeshBatchVisibility,MaxDraws); MaxDraws -= Scene->BasePassForForwardShadingMovableDirectionalLightCSMDrawList[FScene::EBasePass_Masked].DrawVisibleFrontToBack(RHICmdList, View, View.StaticMeshVisibilityMap, View.StaticMeshBatchVisibility, MaxDraws); MaxDraws -= Scene->BasePassForForwardShadingMovableDirectionalLightDrawList[FScene::EBasePass_Masked].DrawVisibleFrontToBack(RHICmdList, View,View.StaticMeshVisibilityMap,View.StaticMeshBatchVisibility,MaxDraws); } else { SCOPE_CYCLE_COUNTER(STAT_StaticDrawListDrawTime); Scene->BasePassForForwardShadingNoLightMapDrawList[FScene::EBasePass_Masked].DrawVisible(RHICmdList, View,View.StaticMeshVisibilityMap,View.StaticMeshBatchVisibility); Scene->BasePassForForwardShadingLowQualityLightMapDrawList[FScene::EBasePass_Masked].DrawVisible(RHICmdList, View,View.StaticMeshVisibilityMap,View.StaticMeshBatchVisibility); Scene->BasePassForForwardShadingDistanceFieldShadowMapLightMapDrawList[FScene::EBasePass_Masked].DrawVisible(RHICmdList, View,View.StaticMeshVisibilityMap,View.StaticMeshBatchVisibility); Scene->BasePassForForwardShadingDirectionalLightAndSHIndirectDrawList[FScene::EBasePass_Masked].DrawVisible(RHICmdList, View,View.StaticMeshVisibilityMap,View.StaticMeshBatchVisibility); Scene->BasePassForForwardShadingMovableDirectionalLightCSMDrawList[FScene::EBasePass_Masked].DrawVisible(RHICmdList, View, View.StaticMeshVisibilityMap, View.StaticMeshBatchVisibility); Scene->BasePassForForwardShadingMovableDirectionalLightDrawList[FScene::EBasePass_Masked].DrawVisible(RHICmdList, View,View.StaticMeshVisibilityMap,View.StaticMeshBatchVisibility); } } }
void GetContactOffsetParams(float& ContactOffsetFactor, float& MaxContactOffset) { // Get contact offset params ContactOffsetFactor = CVarContactOffsetFactor.GetValueOnGameThread(); MaxContactOffset = CVarMaxContactOffset.GetValueOnGameThread(); }
//////// GAME-LEVEL RIGID BODY PHYSICS STUFF /////// void InitGamePhys() { #if WITH_BOX2D FPhysicsIntegration2D::InitializePhysics(); #endif #if WITH_PHYSX // Do nothing if SDK already exists if(GPhysXFoundation != NULL) { return; } // Make sure LoadPhysXModules(); // Create Foundation GPhysXAllocator = new FPhysXAllocator(); FPhysXErrorCallback* ErrorCallback = new FPhysXErrorCallback(); GPhysXFoundation = PxCreateFoundation(PX_FOUNDATION_VERSION, *GPhysXAllocator, *ErrorCallback); check(GPhysXFoundation); #if PHYSX_MEMORY_STATS // Want names of PhysX allocations GPhysXFoundation->setReportAllocationNames(true); #endif // Create profile manager GPhysXVisualDebugger = PxCreatePvd(*GPhysXFoundation); check(GPhysXVisualDebugger); // Create Physics PxTolerancesScale PScale; PScale.length = CVarToleranceScaleLength.GetValueOnGameThread(); PScale.speed = CVarToleranceScaleSpeed.GetValueOnGameThread(); GPhysXSDK = PxCreatePhysics(PX_PHYSICS_VERSION, *GPhysXFoundation, PScale, false, GPhysXVisualDebugger); check(GPhysXSDK); FPhysxSharedData::Initialize(); GPhysCommandHandler = new FPhysCommandHandler(); GPreGarbageCollectDelegateHandle = FCoreUObjectDelegates::PreGarbageCollect.AddRaw(GPhysCommandHandler, &FPhysCommandHandler::Flush); // Init Extensions PxInitExtensions(*GPhysXSDK, GPhysXVisualDebugger); #if WITH_VEHICLE PxInitVehicleSDK(*GPhysXSDK); #endif if (CVarUseUnifiedHeightfield.GetValueOnGameThread()) { //Turn on PhysX 3.3 unified height field collision detection. //This approach shares the collision detection code between meshes and height fields such that height fields behave identically to the equivalent terrain created as a mesh. //This approach facilitates mixing the use of height fields and meshes in the application with no tangible difference in collision behavior between the two approaches except that //heightfield thickness is not supported for unified heightfields. PxRegisterUnifiedHeightFields(*GPhysXSDK); } else { PxRegisterHeightFields(*GPhysXSDK); } if( FParse::Param( FCommandLine::Get(), TEXT( "PVD" ) ) ) { PvdConnect(TEXT("localhost"), true); } #if WITH_PHYSICS_COOKING || WITH_RUNTIME_PHYSICS_COOKING // Create Cooking PxCookingParams PCookingParams(PScale); PCookingParams.meshWeldTolerance = 0.1f; // Weld to 1mm precision PCookingParams.meshPreprocessParams = PxMeshPreprocessingFlags(PxMeshPreprocessingFlag::eWELD_VERTICES); // Force any cooking in PhysX or APEX to use older incremental hull method // This is because the new 'quick hull' method can generate degenerate geometry in some cases (very thin meshes etc.) //PCookingParams.convexMeshCookingType = PxConvexMeshCookingType::eINFLATION_INCREMENTAL_HULL; PCookingParams.targetPlatform = PxPlatform::ePC; //PCookingParams.meshCookingHint = PxMeshCookingHint::eCOOKING_PERFORMANCE; //PCookingParams.meshSizePerformanceTradeOff = 0.0f; GPhysXCooking = PxCreateCooking(PX_PHYSICS_VERSION, *GPhysXFoundation, PCookingParams); check(GPhysXCooking); #endif #if WITH_APEX // Build the descriptor for the APEX SDK apex::ApexSDKDesc ApexDesc; ApexDesc.foundation = GPhysXFoundation; // Pointer to the PxFoundation ApexDesc.physXSDK = GPhysXSDK; // Pointer to the PhysXSDK ApexDesc.cooking = GPhysXCooking; // Pointer to the cooking library ApexDesc.renderResourceManager = &GApexNullRenderResourceManager; // We will not be using the APEX rendering API, so just use a dummy render resource manager ApexDesc.resourceCallback = &GApexResourceCallback; // The resource callback is how APEX asks the application to find assets when it needs them #if PLATFORM_MAC FString DylibFolder = FPaths::EngineDir() / TEXT("Binaries/ThirdParty/PhysX/"); ANSICHAR* DLLLoadPath = (ANSICHAR*)FMemory::Malloc(DylibFolder.Len() + 1); FCStringAnsi::Strcpy(DLLLoadPath, DylibFolder.Len() + 1, TCHAR_TO_UTF8(*DylibFolder)); ApexDesc.dllLoadPath = DLLLoadPath; #endif // Create the APEX SDK apex::ApexCreateError ErrorCode; GApexSDK = apex::CreateApexSDK(ApexDesc, &ErrorCode); check(ErrorCode == APEX_CE_NO_ERROR); check(GApexSDK); #if PLATFORM_MAC FMemory::Free(DLLLoadPath); #endif #if UE_BUILD_SHIPPING GApexSDK->setEnableApexStats(false); #endif #if APEX_STATICALLY_LINKED // We need to instantiate the module if we have statically linked them // Otherwise all createModule functions will fail instantiateModuleDestructible(); #if WITH_APEX_CLOTHING instantiateModuleClothing(); #endif #if WITH_APEX_LEGACY instantiateModuleLegacy(); #endif #endif // 1 legacy module for all in APEX 1.3 // Load the only 1 legacy module #if WITH_APEX_LEGACY GApexModuleLegacy = GApexSDK->createModule("Legacy"); check(GApexModuleLegacy); #endif // WITH_APEX_LEGACY // Load APEX Destruction module GApexModuleDestructible = static_cast<apex::ModuleDestructible*>(GApexSDK->createModule("Destructible")); check(GApexModuleDestructible); // Set Destructible module parameters NvParameterized::Interface* ModuleParams = GApexModuleDestructible->getDefaultModuleDesc(); // ModuleParams contains the default module descriptor, which may be modified here before calling the module init function GApexModuleDestructible->init(*ModuleParams); // Set chunk report for fracture effect callbacks GApexModuleDestructible->setChunkReport(&GApexChunkReport); GApexModuleDestructible->setMaxDynamicChunkIslandCount((physx::PxU32)FMath::Max(CVarAPEXMaxDestructibleDynamicChunkIslandCount.GetValueOnGameThread(), 0)); GApexModuleDestructible->setMaxChunkCount((physx::PxU32)FMath::Max(CVarAPEXMaxDestructibleDynamicChunkCount.GetValueOnGameThread(), 0)); GApexModuleDestructible->setSortByBenefit(CVarAPEXSortDynamicChunksByBenefit.GetValueOnGameThread() != 0); GApexModuleDestructible->scheduleChunkStateEventCallback(apex::DestructibleCallbackSchedule::FetchResults); // APEX 1.3 to preserve 1.2 behavior GApexModuleDestructible->setUseLegacyDamageRadiusSpread(true); GApexModuleDestructible->setUseLegacyChunkBoundsTesting(true); #if WITH_APEX_CLOTHING // Load APEX Clothing module GApexModuleClothing = static_cast<apex::ModuleClothing*>(GApexSDK->createModule("Clothing")); check(GApexModuleClothing); // Set Clothing module parameters ModuleParams = GApexModuleClothing->getDefaultModuleDesc(); // Can be tuned for switching between more memory and more spikes. NvParameterized::setParamU32(*ModuleParams, "maxUnusedPhysXResources", 5); // If true, let fetch results tasks run longer than the fetchResults call. // Setting to true could not ensure same finish timing with Physx simulation phase NvParameterized::setParamBool(*ModuleParams, "asyncFetchResults", false); // ModuleParams contains the default module descriptor, which may be modified here before calling the module init function GApexModuleClothing->init(*ModuleParams); #endif //WITH_APEX_CLOTHING #endif // #if WITH_APEX #endif // WITH_PHYSX }
void FSceneView::StartFinalPostprocessSettings(FVector InViewLocation) { check(IsInGameThread()); // The final settings for the current viewer position (blended together from many volumes). // Setup by the main thread, passed to the render thread and never touched again by the main thread. // Set values before any override happens. FinalPostProcessSettings.SetBaseValues(); // project settings might want to have different defaults { if(!CVarDefaultBloom.GetValueOnGameThread()) { FinalPostProcessSettings.BloomIntensity = 0; } if (!CVarDefaultAmbientOcclusion.GetValueOnGameThread()) { FinalPostProcessSettings.AmbientOcclusionIntensity = 0; } if (!CVarDefaultAutoExposure.GetValueOnGameThread()) { FinalPostProcessSettings.AutoExposureMinBrightness = 1; FinalPostProcessSettings.AutoExposureMaxBrightness = 1; } if (!CVarDefaultMotionBlur.GetValueOnGameThread()) { FinalPostProcessSettings.MotionBlurAmount = 0; } if (!CVarDefaultLensFlare.GetValueOnGameThread()) { FinalPostProcessSettings.LensFlareIntensity = 0; } { int32 Value = CVarDefaultAntiAliasing.GetValueOnGameThread(); if (Value >= 0 && Value < AAM_MAX) { FinalPostProcessSettings.AntiAliasingMethod = (EAntiAliasingMethod)Value; } } { int32 Value = CVarDefaultAmbientOcclusionStaticFraction.GetValueOnGameThread(); if(!Value) { FinalPostProcessSettings.AmbientOcclusionStaticFraction = 0.0f; } } } if(State) { State->OnStartPostProcessing(*this); } UWorld* World = Family->Scene->GetWorld(); // Some views have no world (e.g. material preview) if (World) { for (auto VolumeIt = World->PostProcessVolumes.CreateIterator(); VolumeIt; ++VolumeIt) { DoPostProcessVolume(*VolumeIt, InViewLocation, this); } } }
/** Util to convert an overlapped shape into a sweep hit result, returns whether it was a blocking hit. */ static bool ConvertOverlappedShapeToImpactHit(const UWorld* World, const PxLocationHit& PHit, const FVector& StartLoc, const FVector& EndLoc, FHitResult& OutResult, const PxGeometry& Geom, const PxTransform& QueryTM, const PxFilterData& QueryFilter, bool bReturnPhysMat) { SCOPE_CYCLE_COUNTER(STAT_CollisionConvertOverlapToHit); const PxShape* PShape = PHit.shape; const PxRigidActor* PActor = PHit.actor; const uint32 FaceIdx = PHit.faceIndex; // See if this is a 'blocking' hit PxFilterData PShapeFilter = PShape->getQueryFilterData(); PxSceneQueryHitType::Enum HitType = FPxQueryFilterCallback::CalcQueryHitType(QueryFilter, PShapeFilter); const bool bBlockingHit = (HitType == PxSceneQueryHitType::eBLOCK); OutResult.bBlockingHit = bBlockingHit; // Time of zero because initially overlapping OutResult.bStartPenetrating = true; OutResult.Time = 0.f; // Return start location as 'safe location' OutResult.Location = P2UVector(QueryTM.p); OutResult.ImpactPoint = OutResult.Location; // @todo not really sure of a better thing to do here... OutResult.TraceStart = StartLoc; OutResult.TraceEnd = EndLoc; const bool bFiniteNormal = PHit.normal.isFinite(); const bool bValidNormal = (PHit.flags & PxHitFlag::eNORMAL) && bFiniteNormal; // Use MTD result if possible. We interpret the MTD vector as both the direction to move and the opposing normal. if (bValidNormal) { OutResult.ImpactNormal = P2UVector(PHit.normal); OutResult.PenetrationDepth = FMath::Abs(PHit.distance); } else { // Fallback normal if we can't find it with MTD or otherwise. OutResult.ImpactNormal = FVector::UpVector; OutResult.PenetrationDepth = 0.f; if (!bFiniteNormal) { UE_LOG(LogPhysics, Verbose, TEXT("Warning: ConvertOverlappedShapeToImpactHit: MTD returned NaN :( normal: (X:%f, Y:%f, Z:%f)"), PHit.normal.x, PHit.normal.y, PHit.normal.z); } } #if DRAW_OVERLAPPING_TRIS if (CVarShowInitialOverlaps.GetValueOnAnyThread() != 0 && World && World->IsGameWorld()) { FVector DummyNormal(0.f); const PxTransform PShapeWorldPose = PxShapeExt::getGlobalPose(*PShape, *PActor); FindOverlappedTriangleNormal(World, Geom, QueryTM, PShape, PShapeWorldPose, DummyNormal, 0.f, true); } #endif if (bBlockingHit) { // Zero-distance hits are often valid hits and we can extract the hit normal. // For invalid normals we can try other methods as well (get overlapping triangles). if (PHit.distance == 0.f || !bValidNormal) { const PxTransform PShapeWorldPose = PxShapeExt::getGlobalPose(*PShape, *PActor); // Try MTD with a small inflation for better accuracy, then a larger one in case the first one fails due to precision issues. static const float SmallMtdInflation = 0.250f; static const float LargeMtdInflation = 1.750f; if (ComputeInflatedMTD(SmallMtdInflation, PHit, OutResult, QueryTM, Geom, PShapeWorldPose) || ComputeInflatedMTD(LargeMtdInflation, PHit, OutResult, QueryTM, Geom, PShapeWorldPose)) { // Success } else { static const float SmallOverlapInflation = 0.250f; if (FindOverlappedTriangleNormal(World, Geom, QueryTM, PShape, PShapeWorldPose, OutResult.ImpactNormal, 0.f, false) || FindOverlappedTriangleNormal(World, Geom, QueryTM, PShape, PShapeWorldPose, OutResult.ImpactNormal, SmallOverlapInflation, false)) { // Success } else { // MTD failed, use point distance. This is not ideal. // Note: faceIndex seems to be unreliable for convex meshes in these cases, so not using FindGeomOpposingNormal() for them here. PxGeometry& PGeom = PShape->getGeometry().any(); PxVec3 PClosestPoint; const float Distance = PxGeometryQuery::pointDistance(QueryTM.p, PGeom, PShapeWorldPose, &PClosestPoint); if (Distance < KINDA_SMALL_NUMBER) { UE_LOG(LogCollision, Verbose, TEXT("Warning: ConvertOverlappedShapeToImpactHit: Query origin inside shape, giving poor MTD.")); PClosestPoint = PxShapeExt::getWorldBounds(*PShape, *PActor).getCenter(); } OutResult.ImpactNormal = (OutResult.Location - P2UVector(PClosestPoint)).GetSafeNormal(); } } } } else { // non blocking hit (overlap). if (!bValidNormal) { OutResult.ImpactNormal = (StartLoc - EndLoc).GetSafeNormal(); ensure(OutResult.ImpactNormal.IsNormalized()); } } OutResult.Normal = OutResult.ImpactNormal; SetHitResultFromShapeAndFaceIndex(PShape, PActor, FaceIdx, OutResult, bReturnPhysMat); return bBlockingHit; }
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); } } }
FSceneView::FSceneView(const FSceneViewInitOptions& InitOptions) : Family(InitOptions.ViewFamily) , State(InitOptions.SceneViewStateInterface) , ViewActor(InitOptions.ViewActor) , Drawer(InitOptions.ViewElementDrawer) , ViewRect(InitOptions.GetConstrainedViewRect()) , UnscaledViewRect(InitOptions.GetConstrainedViewRect()) , UnconstrainedViewRect(InitOptions.GetViewRect()) , MaxShadowCascades(10) , WorldToMetersScale(InitOptions.WorldToMetersScale) , ProjectionMatrixUnadjustedForRHI(InitOptions.ProjectionMatrix) , BackgroundColor(InitOptions.BackgroundColor) , OverlayColor(InitOptions.OverlayColor) , ColorScale(InitOptions.ColorScale) , StereoPass(InitOptions.StereoPass) , DiffuseOverrideParameter(FVector4(0,0,0,1)) , SpecularOverrideParameter(FVector4(0,0,0,1)) , NormalOverrideParameter(FVector4(0,0,0,1)) , RoughnessOverrideParameter(FVector2D(0,1)) , HiddenPrimitives(InitOptions.HiddenPrimitives) , LODDistanceFactor(InitOptions.LODDistanceFactor) , bCameraCut(InitOptions.bInCameraCut) , bOriginOffsetThisFrame(InitOptions.bOriginOffsetThisFrame) , CursorPos(InitOptions.CursorPos) , bIsGameView(false) , bForceShowMaterials(false) , bIsViewInfo(false) , bIsSceneCapture(false) , bIsReflectionCapture(false) , bIsLocked(false) , bStaticSceneOnly(false) #if WITH_EDITOR , OverrideLODViewOrigin(InitOptions.OverrideLODViewOrigin) , bAllowTranslucentPrimitivesInHitProxy( true ) , bHasSelectedComponents( false ) #endif , FeatureLevel(InitOptions.ViewFamily ? InitOptions.ViewFamily->GetFeatureLevel() : GMaxRHIFeatureLevel) { check(UnscaledViewRect.Min.X >= 0); check(UnscaledViewRect.Min.Y >= 0); check(UnscaledViewRect.Width() > 0); check(UnscaledViewRect.Height() > 0); ViewMatrices.ViewMatrix = InitOptions.ViewMatrix; // Adjust the projection matrix for the current RHI. ViewMatrices.ProjMatrix = AdjustProjectionMatrixForRHI(ProjectionMatrixUnadjustedForRHI); // Compute the view projection matrix and its inverse. ViewProjectionMatrix = ViewMatrices.GetViewProjMatrix(); // For precision reasons the view matrix inverse is calculated independently. InvViewMatrix = ViewMatrices.ViewMatrix.Inverse(); InvViewProjectionMatrix = ViewMatrices.GetInvProjMatrix() * InvViewMatrix; bool ApplyPreViewTranslation = true; // Calculate the view origin from the view/projection matrices. if(IsPerspectiveProjection()) { ViewMatrices.ViewOrigin = InvViewMatrix.GetOrigin(); } #if WITH_EDITOR else if (InitOptions.bUseFauxOrthoViewPos) { float DistanceToViewOrigin = WORLD_MAX; ViewMatrices.ViewOrigin = FVector4(InvViewMatrix.TransformVector(FVector(0,0,-1)).GetSafeNormal()*DistanceToViewOrigin,1) + InvViewMatrix.GetOrigin(); } #endif else { ViewMatrices.ViewOrigin = FVector4(InvViewMatrix.TransformVector(FVector(0,0,-1)).GetSafeNormal(),0); // to avoid issues with view dependent effect (e.g. Frensel) ApplyPreViewTranslation = false; } // Translate world-space so its origin is at ViewOrigin for improved precision. // Note that this isn't exactly right for orthogonal projections (See the above special case), but we still use ViewOrigin // in that case so the same value may be used in shaders for both the world-space translation and the camera's world position. if(ApplyPreViewTranslation) { ViewMatrices.PreViewTranslation = -FVector(ViewMatrices.ViewOrigin); #if !(UE_BUILD_SHIPPING || UE_BUILD_TEST) { // console variable override static const auto CVar = IConsoleManager::Get().FindTConsoleVariableDataInt(TEXT("r.PreViewTranslation")); int32 Value = CVar->GetValueOnGameThread(); static FVector PreViewTranslationBackup; if(Value) { PreViewTranslationBackup = ViewMatrices.PreViewTranslation; } else { ViewMatrices.PreViewTranslation = PreViewTranslationBackup; } } #endif // !(UE_BUILD_SHIPPING || UE_BUILD_TEST) } /** The view transform, starting from world-space points translated by -ViewOrigin. */ FMatrix TranslatedViewMatrix = FTranslationMatrix(-ViewMatrices.PreViewTranslation) * ViewMatrices.ViewMatrix; // Compute a transform from view origin centered world-space to clip space. ViewMatrices.TranslatedViewProjectionMatrix = TranslatedViewMatrix * ViewMatrices.ProjMatrix; ViewMatrices.InvTranslatedViewProjectionMatrix = ViewMatrices.TranslatedViewProjectionMatrix.Inverse(); // Compute screen scale factors. // Stereo renders at half horizontal resolution, but compute shadow resolution based on full resolution. const bool bStereo = StereoPass != eSSP_FULL; const float ScreenXScale = bStereo ? 2.0f : 1.0f; ViewMatrices.ProjectionScale.X = ScreenXScale * FMath::Abs(ViewMatrices.ProjMatrix.M[0][0]); ViewMatrices.ProjectionScale.Y = FMath::Abs(ViewMatrices.ProjMatrix.M[1][1]); ViewMatrices.ScreenScale = FMath::Max( ViewRect.Size().X * 0.5f * ViewMatrices.ProjectionScale.X, ViewRect.Size().Y * 0.5f * ViewMatrices.ProjectionScale.Y ); ShadowViewMatrices = ViewMatrices; #if !(UE_BUILD_SHIPPING || UE_BUILD_TEST) { // console variable override int32 Value = CVarShadowFreezeCamera.GetValueOnAnyThread(); static FViewMatrices Backup = ShadowViewMatrices; if(Value) { ShadowViewMatrices = Backup; } else { Backup = ShadowViewMatrices; } } #endif // !(UE_BUILD_SHIPPING || UE_BUILD_TEST) if (InitOptions.OverrideFarClippingPlaneDistance > 0.0f) { const FPlane FarPlane(ViewMatrices.ViewOrigin + GetViewDirection() * InitOptions.OverrideFarClippingPlaneDistance, GetViewDirection()); // Derive the view frustum from the view projection matrix, overriding the far plane GetViewFrustumBounds(ViewFrustum,ViewProjectionMatrix,FarPlane,true,false); } else { // Derive the view frustum from the view projection matrix. GetViewFrustumBounds(ViewFrustum,ViewProjectionMatrix,false); } // Derive the view's near clipping distance and plane. // The GetFrustumFarPlane() is the near plane because of reverse Z projection. bHasNearClippingPlane = ViewProjectionMatrix.GetFrustumFarPlane(NearClippingPlane); if(ViewMatrices.ProjMatrix.M[2][3] > DELTA) { // Infinite projection with reversed Z. NearClippingDistance = ViewMatrices.ProjMatrix.M[3][2]; } else { // Ortho projection with reversed Z. NearClippingDistance = (1.0f - ViewMatrices.ProjMatrix.M[3][2]) / ViewMatrices.ProjMatrix.M[2][2]; } // Determine whether the view should reverse the cull mode due to a negative determinant. Only do this for a valid scene bReverseCulling = (Family && Family->Scene) ? FMath::IsNegativeFloat(ViewMatrices.ViewMatrix.Determinant()) : false; // OpenGL Gamma space output in GLSL flips Y when rendering directly to the back buffer (so not needed on PC, as we never render directly into the back buffer) auto ShaderPlatform = GShaderPlatformForFeatureLevel[FeatureLevel]; static bool bPlatformRequiresReverseCulling = (IsOpenGLPlatform(ShaderPlatform) && !IsPCPlatform(ShaderPlatform)); static auto* MobileHDRCvar = IConsoleManager::Get().FindTConsoleVariableDataInt(TEXT("r.MobileHDR")); check(MobileHDRCvar); bReverseCulling = (bPlatformRequiresReverseCulling && MobileHDRCvar->GetValueOnAnyThread() == 0) ? !bReverseCulling : bReverseCulling; // Setup transformation constants to be used by the graphics hardware to transform device normalized depth samples // into world oriented z. InvDeviceZToWorldZTransform = CreateInvDeviceZToWorldZTransform(ProjectionMatrixUnadjustedForRHI); static TConsoleVariableData<int32>* SortPolicyCvar = IConsoleManager::Get().FindTConsoleVariableDataInt(TEXT("r.TranslucentSortPolicy")); TranslucentSortPolicy = static_cast<ETranslucentSortPolicy::Type>(SortPolicyCvar->GetValueOnAnyThread()); TranslucentSortAxis = GetDefault<URendererSettings>()->TranslucentSortAxis; // As the world is only accessable from the game thread, bIsGameView should be explicitly // set on any other thread. if(IsInGameThread()) { bIsGameView = (Family && Family->Scene && Family->Scene->GetWorld() ) ? Family->Scene->GetWorld()->IsGameWorld() : false; } #if WITH_EDITOR EditorViewBitflag = InitOptions.EditorViewBitflag; SelectionOutlineColor = GEngine->GetSelectionOutlineColor(); #endif }
/** * Sets the filter shaders with the provided filter samples. * @param SamplerStateRHI - The sampler state to use for the source texture. * @param FilterTextureRHI - The source texture. * @param AdditiveTextureRHI - The additional source texture, used in CombineMethod=1 * @param CombineMethodInt 0:weighted filtering, 1: weighted filtering + additional texture, 2: max magnitude * @param SampleOffsets - A pointer to an array of NumSamples UV offsets * @param SampleWeights - A pointer to an array of NumSamples 4-vector weights * @param NumSamples - The number of samples used by the filter. * @param OutVertexShader - The vertex shader used for the filter */ void SetFilterShaders( FRHICommandListImmediate& RHICmdList, ERHIFeatureLevel::Type FeatureLevel, FSamplerStateRHIParamRef SamplerStateRHI, FTextureRHIParamRef FilterTextureRHI, FTextureRHIParamRef AdditiveTextureRHI, uint32 CombineMethodInt, FVector2D* SampleOffsets, FLinearColor* SampleWeights, uint32 NumSamples, FShader** OutVertexShader ) { check(CombineMethodInt <= 2); check(NumSamples <= MAX_FILTER_SAMPLES && NumSamples > 0); auto ShaderMap = GetGlobalShaderMap(FeatureLevel); const auto DynamicNumSample = CVarLoopMode.GetValueOnRenderThread(); if ((NumSamples > MAX_FILTER_COMPILE_TIME_SAMPLES && DynamicNumSample != 0) || (DynamicNumSample == 2)) { // there is to many samples, so we use the dynamic sample count shader TShaderMapRef<FPostProcessVS> VertexShader(ShaderMap); *OutVertexShader = *VertexShader; if(CombineMethodInt == 0) { TShaderMapRef<TFilterPS<0, 0> > PixelShader(ShaderMap); { static FGlobalBoundShaderState BoundShaderState; SetGlobalBoundShaderState(RHICmdList, FeatureLevel, BoundShaderState, GFilterVertexDeclaration.VertexDeclarationRHI, *VertexShader, *PixelShader); } PixelShader->SetParameters(RHICmdList, SamplerStateRHI, FilterTextureRHI, AdditiveTextureRHI, SampleWeights, SampleOffsets, NumSamples); } else if(CombineMethodInt == 1) { TShaderMapRef<TFilterPS<0, 1> > PixelShader(ShaderMap); { static FGlobalBoundShaderState BoundShaderState; SetGlobalBoundShaderState(RHICmdList, FeatureLevel, BoundShaderState, GFilterVertexDeclaration.VertexDeclarationRHI, *VertexShader, *PixelShader); } PixelShader->SetParameters(RHICmdList, SamplerStateRHI, FilterTextureRHI, AdditiveTextureRHI, SampleWeights, SampleOffsets, NumSamples); } else\ { TShaderMapRef<TFilterPS<0, 2> > PixelShader(ShaderMap); { static FGlobalBoundShaderState BoundShaderState; SetGlobalBoundShaderState(RHICmdList, FeatureLevel, BoundShaderState, GFilterVertexDeclaration.VertexDeclarationRHI, *VertexShader, *PixelShader); } PixelShader->SetParameters(RHICmdList, SamplerStateRHI, FilterTextureRHI, AdditiveTextureRHI, SampleWeights, SampleOffsets, NumSamples); } return; } // A macro to handle setting the filter shader for a specific number of samples. #define SET_FILTER_SHADER_TYPE(CompileTimeNumSamples) \ case CompileTimeNumSamples: \ { \ TShaderMapRef<TFilterVS<CompileTimeNumSamples> > VertexShader(ShaderMap); \ *OutVertexShader = *VertexShader; \ if(CombineMethodInt == 0) \ { \ TShaderMapRef<TFilterPS<CompileTimeNumSamples, 0> > PixelShader(ShaderMap); \ { \ static FGlobalBoundShaderState BoundShaderState; \ SetGlobalBoundShaderState(RHICmdList, FeatureLevel, BoundShaderState, GFilterVertexDeclaration.VertexDeclarationRHI, *VertexShader, *PixelShader); \ } \ PixelShader->SetParameters(RHICmdList, SamplerStateRHI, FilterTextureRHI, AdditiveTextureRHI, SampleWeights, SampleOffsets, NumSamples); \ } \ else if(CombineMethodInt == 1) \ { \ TShaderMapRef<TFilterPS<CompileTimeNumSamples, 1> > PixelShader(ShaderMap); \ { \ static FGlobalBoundShaderState BoundShaderState; \ SetGlobalBoundShaderState(RHICmdList, FeatureLevel, BoundShaderState, GFilterVertexDeclaration.VertexDeclarationRHI, *VertexShader, *PixelShader); \ } \ PixelShader->SetParameters(RHICmdList, SamplerStateRHI, FilterTextureRHI, AdditiveTextureRHI, SampleWeights, SampleOffsets, NumSamples); \ } \ else\ { \ TShaderMapRef<TFilterPS<CompileTimeNumSamples, 2> > PixelShader(ShaderMap); \ { \ static FGlobalBoundShaderState BoundShaderState; \ SetGlobalBoundShaderState(RHICmdList, FeatureLevel, BoundShaderState, GFilterVertexDeclaration.VertexDeclarationRHI, *VertexShader, *PixelShader); \ } \ PixelShader->SetParameters(RHICmdList, SamplerStateRHI, FilterTextureRHI, AdditiveTextureRHI, SampleWeights, SampleOffsets, NumSamples); \ } \ VertexShader->SetParameters(RHICmdList, SampleOffsets); \ break; \ }; check(NumSamples <= MAX_FILTER_COMPILE_TIME_SAMPLES); // Set the appropriate filter shader for the given number of samples. switch(NumSamples) { SET_FILTER_SHADER_TYPE(1); SET_FILTER_SHADER_TYPE(2); SET_FILTER_SHADER_TYPE(3); SET_FILTER_SHADER_TYPE(4); SET_FILTER_SHADER_TYPE(5); SET_FILTER_SHADER_TYPE(6); SET_FILTER_SHADER_TYPE(7); SET_FILTER_SHADER_TYPE(8); SET_FILTER_SHADER_TYPE(9); SET_FILTER_SHADER_TYPE(10); SET_FILTER_SHADER_TYPE(11); SET_FILTER_SHADER_TYPE(12); SET_FILTER_SHADER_TYPE(13); SET_FILTER_SHADER_TYPE(14); SET_FILTER_SHADER_TYPE(15); SET_FILTER_SHADER_TYPE(16); SET_FILTER_SHADER_TYPE(17); SET_FILTER_SHADER_TYPE(18); SET_FILTER_SHADER_TYPE(19); SET_FILTER_SHADER_TYPE(20); SET_FILTER_SHADER_TYPE(21); SET_FILTER_SHADER_TYPE(22); SET_FILTER_SHADER_TYPE(23); SET_FILTER_SHADER_TYPE(24); SET_FILTER_SHADER_TYPE(25); SET_FILTER_SHADER_TYPE(26); SET_FILTER_SHADER_TYPE(27); SET_FILTER_SHADER_TYPE(28); SET_FILTER_SHADER_TYPE(29); SET_FILTER_SHADER_TYPE(30); SET_FILTER_SHADER_TYPE(31); SET_FILTER_SHADER_TYPE(32); default: UE_LOG(LogRenderer, Fatal,TEXT("Invalid number of samples: %u"),NumSamples); } #undef SET_FILTER_SHADER_TYPE }
void FSystemSettings::ApplyOverrides() { EConsoleVariableFlags SetBy = ECVF_SetByMask; if (FPlatformProperties::SupportsWindowedMode()) { if (CVarUseMaxQualityMode.GetValueOnGameThread() != 0) { SetBy = (EConsoleVariableFlags)(CVarUseMaxQualityMode.AsVariable()->GetFlags() & ECVF_SetByMask); } if (FParse::Param(FCommandLine::Get(),TEXT("MAXQUALITYMODE"))) { SetBy = ECVF_SetByCommandline; } } if (SetBy != ECVF_SetByMask) { // Modify various system settings to get the best quality regardless of performance impact { static auto CVar = IConsoleManager::Get().FindConsoleVariable(TEXT("r.Shadow.MinResolution")); CVar->Set(16, SetBy); } // Disable shadow fading out over distance { static auto CVar = IConsoleManager::Get().FindConsoleVariable(TEXT("r.Shadow.FadeResolution")); CVar->Set(1, SetBy); } // Increase minimum preshadow resolution { static auto CVar = IConsoleManager::Get().FindConsoleVariable(TEXT("r.Shadow.MinPreShadowResolution")); CVar->Set(16, SetBy); } // Disable preshadow fading out over distance { static auto CVar = IConsoleManager::Get().FindConsoleVariable(TEXT("r.Shadow.PreShadowFadeResolution")); CVar->Set(1, SetBy); } // Increase shadow texel density { static auto CVar = IConsoleManager::Get().FindConsoleVariable(TEXT("r.Shadow.TexelsPerPixel")); CVar->Set(4.0f, SetBy); } // Don't downsample preshadows { static auto CVar = IConsoleManager::Get().FindConsoleVariable(TEXT("r.Shadow.PreShadowResolutionFactor")); CVar->Set(1.0f, SetBy); } for (int32 GroupIndex = 0; GroupIndex < TEXTUREGROUP_MAX; GroupIndex++) { FTextureLODSettings::FTextureLODGroup& CurrentGroup = TextureLODSettings.GetTextureLODGroup(GroupIndex); // Use the best quality texture filtering CurrentGroup.Filter = SF_AnisotropicLinear; // Raise texture max sizes to 4096 CurrentGroup.MinLODMipCount = 12; CurrentGroup.MaxLODMipCount = 12; CurrentGroup.LODBias = -1000; } } }
void FRCPassPostProcessSubsurface::Process(FRenderingCompositePassContext& Context) { const FPooledRenderTargetDesc* InputDesc = GetInputDesc(ePId_Input0); check(InputDesc); { const IPooledRenderTarget* PooledRT = GetSubsufaceProfileTexture_RT(Context.RHICmdList); check(PooledRT); // for debugging GRenderTargetPool.VisualizeTexture.SetCheckPoint(Context.RHICmdList, PooledRT); } const FSceneView& View = Context.View; const FSceneViewFamily& ViewFamily = *(View.Family); FIntPoint SrcSize = InputDesc->Extent; FIntPoint DestSize = PassOutputs[0].RenderTargetDesc.Extent; check(DestSize.X); check(DestSize.Y); check(SrcSize.X); check(SrcSize.Y); FIntRect SrcRect = FIntRect(0, 0, DestSize.X, DestSize.Y); FIntRect DestRect = SrcRect; TRefCountPtr<IPooledRenderTarget> NewSceneColor; const FSceneRenderTargetItem* DestRenderTarget; { DestRenderTarget = &PassOutputs[0].RequestSurface(Context); check(DestRenderTarget); } // Set the view family's render target/viewport. SetRenderTarget(Context.RHICmdList, DestRenderTarget->TargetableTexture, FTextureRHIRef()); Context.SetViewportAndCallRHI(0, 0, 0.0f, DestSize.X, DestSize.Y, 1.0f ); Context.RHICmdList.SetBlendState(TStaticBlendState<>::GetRHI()); Context.RHICmdList.SetRasterizerState(TStaticRasterizerState<>::GetRHI()); Context.RHICmdList.SetDepthStencilState(TStaticDepthStencilState<false, CF_Always>::GetRHI()); TShaderMapRef<FPostProcessVS> VertexShader(Context.GetShaderMap()); SCOPED_DRAW_EVENTF(Context.RHICmdList, SubsurfacePass, TEXT("SubsurfaceDirection#%d"), Direction); uint32 SampleSet = FMath::Clamp(CVarSSSSampleSet.GetValueOnRenderThread(), 0, 2); if (Direction == 0) { SetSubsurfaceShaderSampleSet<0>(Context, VertexShader, SampleSet); } else { SetSubsurfaceShaderSampleSet<1>(Context, VertexShader, SampleSet); } DrawPostProcessPass( Context.RHICmdList, DestRect.Min.X, DestRect.Min.Y, DestRect.Width(), DestRect.Height(), SrcRect.Min.X, SrcRect.Min.Y, SrcRect.Width(), SrcRect.Height(), DestSize, SrcSize, *VertexShader, View.StereoPass, Context.HasHmdMesh(), EDRF_UseTriangleOptimization); Context.RHICmdList.CopyToResolveTarget(DestRenderTarget->TargetableTexture, DestRenderTarget->ShaderResourceTexture, false, FResolveParams()); }
void SetParameters(FRHICommandList& RHICmdList, const FSceneView& View, FTextureRHIParamRef SSRTexture, TArray<FReflectionCaptureSortData>& SortData, FUnorderedAccessViewRHIParamRef OutSceneColorUAV, const TRefCountPtr<IPooledRenderTarget>& DynamicBentNormalAO) { const FComputeShaderRHIParamRef ShaderRHI = GetComputeShader(); FGlobalShader::SetParameters(RHICmdList, ShaderRHI, View); DeferredParameters.Set(RHICmdList, ShaderRHI, View); FScene* Scene = (FScene*)View.Family->Scene; check(Scene->ReflectionSceneData.CubemapArray.IsValid()); check(Scene->ReflectionSceneData.CubemapArray.GetRenderTarget().IsValid()); FSceneRenderTargetItem& CubemapArray = Scene->ReflectionSceneData.CubemapArray.GetRenderTarget(); SetTextureParameter( RHICmdList, ShaderRHI, ReflectionEnvironmentColorTexture, ReflectionEnvironmentColorSampler, TStaticSamplerState<SF_Trilinear, AM_Clamp, AM_Clamp, AM_Clamp>::GetRHI(), CubemapArray.ShaderResourceTexture); SetTextureParameter(RHICmdList, ShaderRHI, ScreenSpaceReflections, SSRTexture ); SetTextureParameter(RHICmdList, ShaderRHI, InSceneColor, GSceneRenderTargets.GetSceneColor()->GetRenderTargetItem().ShaderResourceTexture ); OutSceneColor.SetTexture(RHICmdList, ShaderRHI, NULL, OutSceneColorUAV); SetShaderValue(RHICmdList, ShaderRHI, ViewDimensionsParameter, View.ViewRect); FReflectionCaptureData SamplePositionsBuffer; for (int32 CaptureIndex = 0; CaptureIndex < SortData.Num(); CaptureIndex++) { SamplePositionsBuffer.PositionAndRadius[CaptureIndex] = SortData[CaptureIndex].PositionAndRadius; SamplePositionsBuffer.CaptureProperties[CaptureIndex] = SortData[CaptureIndex].CaptureProperties; SamplePositionsBuffer.BoxTransform[CaptureIndex] = SortData[CaptureIndex].BoxTransform; SamplePositionsBuffer.BoxScales[CaptureIndex] = SortData[CaptureIndex].BoxScales; } SetUniformBufferParameterImmediate(RHICmdList, ShaderRHI, GetUniformBufferParameter<FReflectionCaptureData>(), SamplePositionsBuffer); SetShaderValue(RHICmdList, ShaderRHI, NumCaptures, SortData.Num()); SetTextureParameter(RHICmdList, ShaderRHI, PreIntegratedGF, PreIntegratedGFSampler, TStaticSamplerState<SF_Bilinear,AM_Clamp,AM_Clamp,AM_Clamp>::GetRHI(), GSystemTextures.PreintegratedGF->GetRenderTargetItem().ShaderResourceTexture); SkyLightParameters.SetParameters(RHICmdList, ShaderRHI, Scene, View.Family->EngineShowFlags.SkyLighting); const float MinOcclusion = Scene->SkyLight ? Scene->SkyLight->MinOcclusion : 0; SpecularOcclusionParameters.SetParameters(RHICmdList, ShaderRHI, DynamicBentNormalAO, CVarSkySpecularOcclusionStrength.GetValueOnRenderThread(), MinOcclusion); }
FMeshElementCollector::FMeshElementCollector() : PrimitiveSceneProxy(NULL), FeatureLevel(ERHIFeatureLevel::Num), bUseAsyncTasks(FApp::ShouldUseThreadingForPerformance() && CVarUseParallelGetDynamicMeshElementsTasks.GetValueOnAnyThread() > 0) { }
void FAndroidOpenGL::ProcessExtensions(const FString& ExtensionsString) { FOpenGLES2::ProcessExtensions(ExtensionsString); FString VersionString = FString(ANSI_TO_TCHAR((const ANSICHAR*)glGetString(GL_VERSION))); bES30Support = VersionString.Contains(TEXT("OpenGL ES 3.")); // Get procedures if (bSupportsOcclusionQueries || bSupportsDisjointTimeQueries) { glGenQueriesEXT = (PFNGLGENQUERIESEXTPROC) ((void*)eglGetProcAddress("glGenQueriesEXT")); glDeleteQueriesEXT = (PFNGLDELETEQUERIESEXTPROC) ((void*)eglGetProcAddress("glDeleteQueriesEXT")); glIsQueryEXT = (PFNGLISQUERYEXTPROC) ((void*)eglGetProcAddress("glIsQueryEXT")); glBeginQueryEXT = (PFNGLBEGINQUERYEXTPROC) ((void*)eglGetProcAddress("glBeginQueryEXT")); glEndQueryEXT = (PFNGLENDQUERYEXTPROC) ((void*)eglGetProcAddress("glEndQueryEXT")); glGetQueryivEXT = (PFNGLGETQUERYIVEXTPROC) ((void*)eglGetProcAddress("glGetQueryivEXT")); glGetQueryObjectivEXT = (PFNGLGETQUERYOBJECTIVEXTPROC) ((void*)eglGetProcAddress("glGetQueryObjectivEXT")); glGetQueryObjectuivEXT = (PFNGLGETQUERYOBJECTUIVEXTPROC)((void*)eglGetProcAddress("glGetQueryObjectuivEXT")); } if (bSupportsDisjointTimeQueries) { glQueryCounterEXT = (PFNGLQUERYCOUNTEREXTPROC) ((void*)eglGetProcAddress("glQueryCounterEXT")); glGetQueryObjectui64vEXT = (PFNGLGETQUERYOBJECTUI64VEXTPROC) ((void*)eglGetProcAddress("glGetQueryObjectui64vEXT")); // If EXT_disjoint_timer_query wasn't found, NV_timer_query might be available if (glQueryCounterEXT == NULL) { glQueryCounterEXT = (PFNGLQUERYCOUNTEREXTPROC)eglGetProcAddress("glQueryCounterNV"); } if (glGetQueryObjectui64vEXT == NULL) { glGetQueryObjectui64vEXT = (PFNGLGETQUERYOBJECTUI64VEXTPROC)eglGetProcAddress("glGetQueryObjectui64vNV"); } } glDiscardFramebufferEXT = (PFNGLDISCARDFRAMEBUFFEREXTPROC)((void*)eglGetProcAddress("glDiscardFramebufferEXT")); glFramebufferTexture2DMultisampleEXT = (PFNGLFRAMEBUFFERTEXTURE2DMULTISAMPLEEXTPROC)((void*)eglGetProcAddress("glFramebufferTexture2DMultisampleEXT")); glRenderbufferStorageMultisampleEXT = (PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC)((void*)eglGetProcAddress("glRenderbufferStorageMultisampleEXT")); glPushGroupMarkerEXT = (PFNGLPUSHGROUPMARKEREXTPROC)((void*)eglGetProcAddress("glPushGroupMarkerEXT")); glPopGroupMarkerEXT = (PFNGLPOPGROUPMARKEREXTPROC)((void*)eglGetProcAddress("glPopGroupMarkerEXT")); glLabelObjectEXT = (PFNGLLABELOBJECTEXTPROC)((void*)eglGetProcAddress("glLabelObjectEXT")); glGetObjectLabelEXT = (PFNGLGETOBJECTLABELEXTPROC)((void*)eglGetProcAddress("glGetObjectLabelEXT")); bSupportsETC2 = bES30Support; bUseES30ShadingLanguage = bES30Support; FString RendererString = FString(ANSI_TO_TCHAR((const ANSICHAR*)glGetString(GL_RENDERER))); if (RendererString.Contains(TEXT("SGX 540"))) { UE_LOG(LogRHI, Warning, TEXT("Disabling support for GL_OES_packed_depth_stencil on SGX 540")); bSupportsPackedDepthStencil = false; bRequiresTexture2DPrecisionHack = true; } const bool bIsAdrenoBased = RendererString.Contains(TEXT("Adreno")); if (bIsAdrenoBased) { // This is to avoid a bug in Adreno drivers that define GL_EXT_shader_framebuffer_fetch even when device does not support this extension // OpenGL ES 3.1 [email protected] (GIT@I1af360237c) bRequiresShaderFramebufferFetchUndef = !bSupportsShaderFramebufferFetch; bRequiresARMShaderFramebufferFetchDepthStencilUndef = !bSupportsShaderDepthStencilFetch; // Adreno 2xx doesn't work with packed depth stencil enabled if (RendererString.Contains(TEXT("Adreno (TM) 2"))) { UE_LOG(LogRHI, Warning, TEXT("Disabling support for GL_OES_packed_depth_stencil on Adreno 2xx")); bSupportsPackedDepthStencil = false; } } if (bES30Support) { glDrawElementsInstanced = (PFNGLDRAWELEMENTSINSTANCEDPROC)((void*)eglGetProcAddress("glDrawElementsInstanced")); glDrawArraysInstanced = (PFNGLDRAWARRAYSINSTANCEDPROC)((void*)eglGetProcAddress("glDrawArraysInstanced")); glVertexAttribDivisor = (PFNGLVERTEXATTRIBDIVISORPROC)((void*)eglGetProcAddress("glVertexAttribDivisor")); bSupportsInstancing = true; } if (bES30Support || bIsAdrenoBased) { // Attempt to find ES 3.0 glTexStorage2D if we're on an ES 3.0 device glTexStorage2D = (PFNGLTEXSTORAGE2DPROC)((void*)eglGetProcAddress("glTexStorage2D")); if( glTexStorage2D != NULL ) { bUseHalfFloatTexStorage = true; } else { // need to disable GL_EXT_color_buffer_half_float support because we have no way to allocate the storage and the driver doesn't work without it. UE_LOG(LogRHI,Warning,TEXT("Disabling support for GL_EXT_color_buffer_half_float as we cannot bind glTexStorage2D")); bSupportsColorBufferHalfFloat = false; } } //@todo android: need GMSAAAllowed ? if (bSupportsNVFrameBufferBlit) { glBlitFramebufferNV = (PFNBLITFRAMEBUFFERNVPROC)((void*)eglGetProcAddress("glBlitFramebufferNV")); } glMapBufferOES = (PFNGLMAPBUFFEROESPROC)((void*)eglGetProcAddress("glMapBufferOES")); glUnmapBufferOES = (PFNGLUNMAPBUFFEROESPROC)((void*)eglGetProcAddress("glUnmapBufferOES")); //On Android, there are problems compiling shaders with textureCubeLodEXT calls in the glsl code, // so we set this to false to modify the glsl manually at compile-time. bSupportsTextureCubeLodEXT = false; // On some Android devices with Mali GPUs textureCubeLod is not available. if (RendererString.Contains(TEXT("Mali-400"))) { bSupportsShaderTextureCubeLod = false; } // Nexus 5 (Android 4.4.2) doesn't like glVertexAttribDivisor(index, 0) called when not using a glDrawElementsInstanced if (bIsAdrenoBased && VersionString.Contains(TEXT("OpenGL ES 3.0 [email protected] AU@ (CL@)"))) { UE_LOG(LogRHI, Warning, TEXT("Disabling support for hardware instancing on Adreno 330 OpenGL ES 3.0 [email protected] AU@ (CL@)")); bSupportsInstancing = false; } if (bSupportsBGRA8888 && CVarAndroidDisableTextureFormatBGRA8888.GetValueOnAnyThread() == 1) { UE_LOG(LogRHI, Warning, TEXT("Disabling support for GL_EXT_texture_format_BGRA8888")); bSupportsBGRA8888 = false; } }
void FGridWidget::DrawNewGrid(const FSceneView* View, FPrimitiveDrawInterface* PDI) { if(LevelGridMaterial->IsCompilingOrHadCompileError() || LevelGridMaterial2->IsCompilingOrHadCompileError()) { // The material would appear to be black (because we don't use a MaterialDomain but a UsageFlag - we should change that). // Here we rather want to hide it. return; } bool bUseTextureSolution = CVarEditorNewLevelGrid.GetValueOnGameThread() > 1; UMaterialInstanceDynamic *MaterialInst = bUseTextureSolution ? LevelGridMaterialInst2 : LevelGridMaterialInst; if(!MaterialInst) { return; } bool bMSAA = IsEditorCompositingMSAAEnabled(); bool bIsPerspective = ( View->ViewMatrices.ProjMatrix.M[3][3] < 1.0f ); // 0: off, in unreal units float SnapGridSize = 0.0f; if(GetDefault<ULevelEditorViewportSettings>()->GridEnabled) { SnapGridSize = GEditor->GetGridSize(); } float SnapAlphaMultiplier = 1.0f; if(SnapGridSize <= 0.0f) { // to hide the snap in the texture based solution SnapAlphaMultiplier = 0; } // to get a light grid in a black level but use a high opacity value to be able to see it in a bright level const float Darken = 0.11f; if(bIsPerspective) { MaterialInst->SetVectorParameterValue("GridColor", FLinearColor(0.6f * Darken, 0.6f * Darken, 0.6f * Darken, CVarEditor3DGridFade.GetValueOnGameThread())); MaterialInst->SetVectorParameterValue("SnapColor", FLinearColor(0.5f, 0.0f, 0.0f, SnapAlphaMultiplier * CVarEditor3DSnapFade.GetValueOnGameThread())); } else { MaterialInst->SetVectorParameterValue("GridColor", FLinearColor(0.6f * Darken, 0.6f * Darken, 0.6f * Darken, CVarEditor2DGridFade.GetValueOnGameThread())); MaterialInst->SetVectorParameterValue("SnapColor", FLinearColor(0.5f, 0.0f, 0.0f, SnapAlphaMultiplier * CVarEditor2DSnapFade.GetValueOnGameThread())); } // true:1m, false:1dm ios smallest grid size bool bLarger1mGrid = true; const int Exponent = 10; // 2 is the default so we need to set it MaterialInst->SetScalarParameterValue("Exponent", (float)Exponent); // without MSAA we need the grid to be more see through so lines behind it can be recognized MaterialInst->SetScalarParameterValue("AlphaBias", bMSAA ? 0.0f : 0.05f); // grid for size float GridSplit = 0.5f; // red dots to visualize the snap float SnapSplit = 0.075f; float WorldToUVScale = 0.001f; if(bLarger1mGrid) { WorldToUVScale *= 0.1f; GridSplit *= 0.1f; } // in 2D all grid lines are same size in world space (they are at different scale so we need to adjust here) FLinearColor GridSplitTriple(GridSplit * 0.01f, GridSplit * 0.1f, GridSplit); if(bIsPerspective) { // largest grid lines GridSplitTriple.R *= 8.0f; // medium grid lines GridSplitTriple.G *= 3.0f; // fine grid lines GridSplitTriple.B *= 1.0f; } if(!bIsPerspective) { // screenspace size looks better in 2d float ScaleX = View->ViewMatrices.ProjMatrix.M[0][0] * View->ViewRect.Width(); float ScaleY = View->ViewMatrices.ProjMatrix.M[1][1] * View->ViewRect.Height(); float Scale = FMath::Min(ScaleX, ScaleY); float GridScale = CVarEditor2DSnapScale.GetValueOnGameThread(); float GridMin = CVarEditor2DSnapMin.GetValueOnGameThread(); // we need to account for a larger grids setting SnapSplit = 1.25f * FMath::Min(GridScale / SnapGridSize / Scale, GridMin); // hack test GridSplitTriple.R = 0.25f * FMath::Min(GridScale / 100 / Scale * 0.01f, GridMin); GridSplitTriple.G = 0.25f * FMath::Min(GridScale / 100 / Scale * 0.1f, GridMin); GridSplitTriple.B = 0.25f * FMath::Min(GridScale / 100 / Scale, GridMin); } // if snap is not enabled and we want to hide it in this view port if(SnapGridSize <= 0.0f || !View->Family->EngineShowFlags.Snap) { // 0.0f is off SnapSplit = 0.0f; } float SnapTile = (1.0f / WorldToUVScale) / FMath::Max(1.0f, SnapGridSize); MaterialInst->SetVectorParameterValue("GridSplit", GridSplitTriple); MaterialInst->SetScalarParameterValue("SnapSplit", SnapSplit); MaterialInst->SetScalarParameterValue("SnapTile", SnapTile); FMatrix ObjectToWorld = FMatrix::Identity; FVector CameraPos = View->ViewMatrices.ViewOrigin; FVector2D UVCameraPos = FVector2D(CameraPos.X, CameraPos.Y); ObjectToWorld.SetOrigin(FVector(CameraPos.X, CameraPos.Y, 0)); FLinearColor UAxisColor = FLinearColor::Green; FLinearColor VAxisColor = FLinearColor::Red; if(!bIsPerspective) { float FarZ = 100000.0f; if(View->ViewMatrices.ViewMatrix.M[1][1] == -1.f ) // Top { ObjectToWorld.SetOrigin(FVector(CameraPos.X, CameraPos.Y, -FarZ)); } if(View->ViewMatrices.ViewMatrix.M[1][2] == -1.f ) // Front { UVCameraPos = FVector2D(CameraPos.Z, CameraPos.X); ObjectToWorld.SetAxis(0, FVector(0,0,1)); ObjectToWorld.SetAxis(1, FVector(1,0,0)); ObjectToWorld.SetAxis(2, FVector(0,1,0)); ObjectToWorld.SetOrigin(FVector(CameraPos.X, -FarZ, CameraPos.Z)); UAxisColor = FLinearColor::Red; VAxisColor = FLinearColor::Blue; } else if(View->ViewMatrices.ViewMatrix.M[1][0] == 1.f ) // Side { UVCameraPos = FVector2D(CameraPos.Y, CameraPos.Z); ObjectToWorld.SetAxis(0, FVector(0,1,0)); ObjectToWorld.SetAxis(1, FVector(0,0,1)); ObjectToWorld.SetAxis(2, FVector(1,0,0)); ObjectToWorld.SetOrigin(FVector(FarZ, CameraPos.Y, CameraPos.Z)); UAxisColor = FLinearColor::Blue; VAxisColor = FLinearColor::Green; } } // less prominent axis lines { // desaturate UAxisColor += FLinearColor(0.5f, 0.5f, 0.5f, 0); VAxisColor += FLinearColor(0.5f, 0.5f, 0.5f, 0); // darker UAxisColor *= 0.1f; VAxisColor *= 0.1f; } MaterialInst->SetVectorParameterValue("UAxisColor", UAxisColor); MaterialInst->SetVectorParameterValue("VAxisColor", VAxisColor); // We don't want to affect the mouse interaction. PDI->SetHitProxy(0); // good enough to avoid the AMD artifacts, horizon still appears to be a line float Radii = 100000; if(bIsPerspective) { // the higher we get the larger we make the geometry to give the illusion of an infinite grid while maintains the precision nearby Radii *= FMath::Max( 1.0f, FMath::Abs(CameraPos.Z) / 1000.0f ); } else { float ScaleX = View->ViewMatrices.ProjMatrix.M[0][0]; float ScaleY = View->ViewMatrices.ProjMatrix.M[1][1]; float Scale = FMath::Min(ScaleX, ScaleY); Scale *= View->ViewRect.Width(); // We render a larger grid if we are zoomed out more (good precision at any scale) Radii *= 1.0f / Scale; } FVector2D UVMid = UVCameraPos * WorldToUVScale; float UVRadi = Radii * WorldToUVScale; FVector2D UVMin = UVMid + FVector2D(-UVRadi, -UVRadi); FVector2D UVMax = UVMid + FVector2D(UVRadi, UVRadi); // vertex pos is in -1..1 range DrawPlane10x10(PDI, ObjectToWorld, Radii, UVMin, UVMax, MaterialInst->GetRenderProxy(false), SDPG_World ); }
void RHIDetectAndWarnOfBadDrivers() { int32 CVarValue = CVarWarnOfBadDrivers.GetValueOnGameThread(); if(!GIsRHIInitialized || !CVarValue || GRHIVendorId == 0) { return; } FGPUDriverInfo DriverInfo; // later we should make the globals use the struct directly DriverInfo.VendorId = GRHIVendorId; DriverInfo.DeviceDescription = GRHIAdapterName; DriverInfo.ProviderName = TEXT("Unknown"); DriverInfo.InternalDriverVersion = GRHIAdapterInternalDriverVersion; DriverInfo.UserDriverVersion = GRHIAdapterUserDriverVersion; DriverInfo.DriverDate = GRHIAdapterDriverDate; #if !(UE_BUILD_SHIPPING || UE_BUILD_TEST) // for testing if(CVarValue == 2) { DriverInfo.SetNVIDIA(); DriverInfo.DeviceDescription = TEXT("Test NVIDIA (bad)"); DriverInfo.UserDriverVersion = TEXT("346.43"); DriverInfo.InternalDriverVersion = TEXT("9.18.134.643"); DriverInfo.DriverDate = TEXT("01-01-1900"); } else if(CVarValue == 3) { DriverInfo.SetAMD(); DriverInfo.DeviceDescription = TEXT("Test AMD (bad)"); DriverInfo.UserDriverVersion = TEXT("Test Catalyst Version"); DriverInfo.InternalDriverVersion = TEXT("13.152.1.1000"); DriverInfo.DriverDate = TEXT("09-10-13"); } else if(CVarValue == 4) { DriverInfo.SetAMD(); DriverInfo.DeviceDescription = TEXT("Test AMD (good)"); DriverInfo.UserDriverVersion = TEXT("Test Catalyst Version"); DriverInfo.InternalDriverVersion = TEXT("15.30.1025.1001"); DriverInfo.DriverDate = TEXT("01-01-16"); } else if(CVarValue == 5) { DriverInfo.SetIntel(); DriverInfo.DeviceDescription = TEXT("Test Intel (good)"); DriverInfo.UserDriverVersion = TEXT("Test Intel Version"); DriverInfo.InternalDriverVersion = TEXT("8.15.10.2302"); DriverInfo.DriverDate = TEXT("01-01-15"); } #endif // !(UE_BUILD_SHIPPING || UE_BUILD_TEST) FGPUHardware DetectedGPUHardware(DriverInfo); if (DriverInfo.IsValid()) { FBlackListEntry BlackListEntry = DetectedGPUHardware.FindDriverBlacklistEntry(); if (BlackListEntry.IsValid()) { bool bLatestBlacklisted = DetectedGPUHardware.IsLatestBlacklisted(); // Note: we don't localize the vendor's name. FString VendorString = DriverInfo.ProviderName; if (DriverInfo.IsNVIDIA()) { VendorString = TEXT("NVIDIA"); } else if (DriverInfo.IsAMD()) { VendorString = TEXT("AMD"); } else if (DriverInfo.IsIntel()) { VendorString = TEXT("Intel"); } // format message box UI FFormatNamedArguments Args; Args.Add(TEXT("AdapterName"), FText::FromString(DriverInfo.DeviceDescription)); Args.Add(TEXT("Vendor"), FText::FromString(VendorString)); Args.Add(TEXT("RecommendedVer"), FText::FromString(DetectedGPUHardware.GetSuggestedDriverVersion())); Args.Add(TEXT("InstalledVer"), FText::FromString(DriverInfo.UserDriverVersion)); // this message can be suppressed with r.WarnOfBadDrivers=0 FText LocalizedMsg; if (bLatestBlacklisted) { LocalizedMsg = FText::Format(NSLOCTEXT("MessageDialog", "LatestVideoCardDriverIssueReport","The latest version of the {Vendor} graphics driver has known issues.\n\nPlease install the last known good driver version.\n\n{AdapterName}\n{RecommendedVer} is the last known good\n{InstalledVer} is installed"),Args); } else { LocalizedMsg = FText::Format(NSLOCTEXT("MessageDialog", "VideoCardDriverIssueReport","Your {Vendor} graphics driver has known issues.\n\nPlease update to the latest driver version.\n\n{AdapterName}\n{RecommendedVer} is recommended\n{InstalledVer} is installed"),Args); } FPlatformMisc::MessageBoxExt(EAppMsgType::Ok, *LocalizedMsg.ToString(), *NSLOCTEXT("MessageDialog", "TitleVideoCardDriverIssue", "WARNING: Known issues with graphics driver").ToString()); } } }
void FRCPassPostProcessCircleDOFSetup::Process(FRenderingCompositePassContext& Context) { SCOPED_DRAW_EVENT(Context.RHICmdList, CircleDOFSetup); const FPooledRenderTargetDesc* InputDesc = GetInputDesc(ePId_Input0); if(!InputDesc) { // input is not hooked up correctly return; } uint32 NumRenderTargets = bNearBlurEnabled ? 2 : 1; const FSceneView& View = Context.View; const FSceneViewFamily& ViewFamily = *(View.Family); const auto FeatureLevel = Context.GetFeatureLevel(); auto ShaderMap = Context.GetShaderMap(); FIntPoint SrcSize = InputDesc->Extent; FIntPoint DestSize = PassOutputs[0].RenderTargetDesc.Extent; // e.g. 4 means the input texture is 4x smaller than the buffer size uint32 ScaleFactor = FSceneRenderTargets::Get(Context.RHICmdList).GetBufferSizeXY().X / SrcSize.X; FIntRect SrcRect = View.ViewRect / ScaleFactor; FIntRect DestRect = SrcRect / 2; const FSceneRenderTargetItem& DestRenderTarget0 = PassOutputs[0].RequestSurface(Context); const FSceneRenderTargetItem& DestRenderTarget1 = bNearBlurEnabled ? PassOutputs[1].RequestSurface(Context) : FSceneRenderTargetItem(); // Set the view family's render target/viewport. FTextureRHIParamRef RenderTargets[2] = { DestRenderTarget0.TargetableTexture, DestRenderTarget1.TargetableTexture }; SetRenderTargets(Context.RHICmdList, NumRenderTargets, RenderTargets, FTextureRHIParamRef(), 0, NULL); FLinearColor ClearColors[2] = { FLinearColor(0, 0, 0, 0), FLinearColor(0, 0, 0, 0) }; // is optimized away if possible (RT size=view size, ) Context.RHICmdList.ClearMRT(true, NumRenderTargets, ClearColors, false, 1.0f, false, 0, DestRect); Context.SetViewportAndCallRHI(0, 0, 0.0f, DestSize.X, DestSize.Y, 1.0f ); // set the state Context.RHICmdList.SetBlendState(TStaticBlendState<>::GetRHI()); Context.RHICmdList.SetRasterizerState(TStaticRasterizerState<>::GetRHI()); Context.RHICmdList.SetDepthStencilState(TStaticDepthStencilState<false, CF_Always>::GetRHI()); TShaderMapRef<FPostProcessVS> VertexShader(ShaderMap); if(CVarDepthOfFieldFarBlur.GetValueOnRenderThread()) { static FGlobalBoundShaderState BoundShaderState; TShaderMapRef< FPostProcessCircleDOFSetupPS<1> > PixelShader(ShaderMap); SetGlobalBoundShaderState(Context.RHICmdList, FeatureLevel, BoundShaderState, GFilterVertexDeclaration.VertexDeclarationRHI, *VertexShader, *PixelShader); PixelShader->SetParameters(Context); } else { static FGlobalBoundShaderState BoundShaderState; TShaderMapRef< FPostProcessCircleDOFSetupPS<0> > PixelShader(ShaderMap); SetGlobalBoundShaderState(Context.RHICmdList, FeatureLevel, BoundShaderState, GFilterVertexDeclaration.VertexDeclarationRHI, *VertexShader, *PixelShader); PixelShader->SetParameters(Context); } VertexShader->SetParameters(Context); DrawPostProcessPass( Context.RHICmdList, DestRect.Min.X, DestRect.Min.Y, DestRect.Width() + 1, DestRect.Height() + 1, SrcRect.Min.X, SrcRect.Min.Y, SrcRect.Width() + 1, SrcRect.Height() + 1, DestSize, SrcSize, *VertexShader, View.StereoPass, Context.HasHmdMesh(), EDRF_UseTriangleOptimization); Context.RHICmdList.CopyToResolveTarget(DestRenderTarget0.TargetableTexture, DestRenderTarget0.ShaderResourceTexture, false, FResolveParams()); if (DestRenderTarget1.TargetableTexture) { Context.RHICmdList.CopyToResolveTarget(DestRenderTarget1.TargetableTexture, DestRenderTarget1.ShaderResourceTexture, false, FResolveParams()); } }
void FSceneRenderer::InitFogConstants() { // console command override float FogDensityOverride = -1.0f; float FogStartDistanceOverride = -1.0f; #if !(UE_BUILD_SHIPPING || UE_BUILD_TEST) { // console variable overrides FogDensityOverride = CVarFogDensity.GetValueOnAnyThread(); FogStartDistanceOverride = CVarFogStartDistance.GetValueOnAnyThread(); } #endif // !(UE_BUILD_SHIPPING || UE_BUILD_TEST) for(int32 ViewIndex = 0;ViewIndex < Views.Num();ViewIndex++) { FViewInfo& View = Views[ViewIndex]; InitAtmosphereConstantsInView(View); // set fog consts based on height fog components if(ShouldRenderFog(*View.Family)) { if (Scene->ExponentialFogs.Num() > 0) { const FExponentialHeightFogSceneInfo& FogInfo = Scene->ExponentialFogs[0]; const float CosTerminatorAngle = FMath::Clamp(FMath::Cos(FogInfo.LightTerminatorAngle * PI / 180.0f), -1.0f + DELTA, 1.0f - DELTA); const float CollapsedFogParameterPower = FMath::Clamp( -FogInfo.FogHeightFalloff * (View.ViewMatrices.ViewOrigin.Z - FogInfo.FogHeight), -126.f + 1.f, // min and max exponent values for IEEE floating points (http://en.wikipedia.org/wiki/IEEE_floating_point) +127.f - 1.f ); const float CollapsedFogParameter = FogInfo.FogDensity * FMath::Pow(2.0f, CollapsedFogParameterPower); View.ExponentialFogParameters = FVector4(CollapsedFogParameter, FogInfo.FogHeightFalloff, CosTerminatorAngle, FogInfo.StartDistance); View.ExponentialFogColor = FVector(FogInfo.FogColor.R, FogInfo.FogColor.G, FogInfo.FogColor.B); View.FogMaxOpacity = FogInfo.FogMaxOpacity; View.ExponentialFogParameters3 = FVector2D(FogInfo.FogDensity, FogInfo.FogHeight); View.DirectionalInscatteringExponent = FogInfo.DirectionalInscatteringExponent; View.DirectionalInscatteringStartDistance = FogInfo.DirectionalInscatteringStartDistance; View.bUseDirectionalInscattering = false; View.InscatteringLightDirection = FVector(0); for (TSparseArray<FLightSceneInfoCompact>::TConstIterator It(Scene->Lights); It; ++It) { const FLightSceneInfoCompact& LightInfo = *It; // This will find the first directional light that is set to be used as an atmospheric sun light of sufficient brightness. // If you have more than one directional light with these properties then all subsequent lights will be ignored. if (LightInfo.LightSceneInfo->Proxy->GetLightType() == LightType_Directional && LightInfo.LightSceneInfo->Proxy->IsUsedAsAtmosphereSunLight() && LightInfo.LightSceneInfo->Proxy->GetColor().ComputeLuminance() > KINDA_SMALL_NUMBER && FogInfo.DirectionalInscatteringColor.ComputeLuminance() > KINDA_SMALL_NUMBER) { View.InscatteringLightDirection = -LightInfo.LightSceneInfo->Proxy->GetDirection(); View.bUseDirectionalInscattering = true; View.DirectionalInscatteringColor = FogInfo.DirectionalInscatteringColor * LightInfo.LightSceneInfo->Proxy->GetColor().ComputeLuminance(); break; } } } } } }
void FAnimNode_AimOffsetLookAt::UpdateFromLookAtTarget(FPoseContext& LocalPoseContext) { const FBoneContainer& RequiredBones = LocalPoseContext.Pose.GetBoneContainer(); if (RequiredBones.GetSkeletalMeshAsset()) { const USkeletalMeshSocket* Socket = RequiredBones.GetSkeletalMeshAsset()->FindSocket(SourceSocketName); if (Socket) { const FTransform SocketLocalTransform = Socket->GetSocketLocalTransform(); FBoneReference SocketBoneReference; SocketBoneReference.BoneName = Socket->BoneName; SocketBoneReference.Initialize(RequiredBones); if (SocketBoneReference.IsValid(RequiredBones)) { const FCompactPoseBoneIndex SocketBoneIndex = SocketBoneReference.GetCompactPoseIndex(RequiredBones); FCSPose<FCompactPose> GlobalPose; GlobalPose.InitPose(LocalPoseContext.Pose); USkeletalMeshComponent* Component = LocalPoseContext.AnimInstanceProxy->GetSkelMeshComponent(); AActor* Actor = Component ? Component->GetOwner() : nullptr; if (Component && Actor && BlendSpace) { const FTransform ActorTransform = Actor->GetTransform(); const FTransform BoneTransform = GlobalPose.GetComponentSpaceTransform(SocketBoneIndex); const FTransform SocketWorldTransform = SocketLocalTransform * BoneTransform * Component->ComponentToWorld; // Convert Target to Actor Space const FTransform TargetWorldTransform(LookAtLocation); const FVector DirectionToTarget = ActorTransform.InverseTransformVectorNoScale(TargetWorldTransform.GetLocation() - SocketWorldTransform.GetLocation()).GetSafeNormal(); const FVector CurrentDirection = ActorTransform.InverseTransformVectorNoScale(SocketWorldTransform.GetUnitAxis(EAxis::X)); const FVector AxisX = FVector::ForwardVector; const FVector AxisY = FVector::RightVector; const FVector AxisZ = FVector::UpVector; const FVector2D CurrentCoords = FMath::GetAzimuthAndElevation(CurrentDirection, AxisX, AxisY, AxisZ); const FVector2D TargetCoords = FMath::GetAzimuthAndElevation(DirectionToTarget, AxisX, AxisY, AxisZ); const FVector BlendInput( FRotator::NormalizeAxis(FMath::RadiansToDegrees(TargetCoords.X - CurrentCoords.X)), FRotator::NormalizeAxis(FMath::RadiansToDegrees(TargetCoords.Y - CurrentCoords.Y)), 0.f); // Set X and Y, so ticking next frame is based on correct weights. X = BlendInput.X; Y = BlendInput.Y; // Generate BlendSampleDataCache from inputs. BlendSpace->GetSamplesFromBlendInput(BlendInput, BlendSampleDataCache); if (CVarAimOffsetLookAtDebug.GetValueOnAnyThread() == 1) { DrawDebugLine(Component->GetWorld(), SocketWorldTransform.GetLocation(), TargetWorldTransform.GetLocation(), FColor::Green); DrawDebugLine(Component->GetWorld(), SocketWorldTransform.GetLocation(), SocketWorldTransform.GetLocation() + SocketWorldTransform.GetUnitAxis(EAxis::X) * (TargetWorldTransform.GetLocation() - SocketWorldTransform.GetLocation()).Size(), FColor::Red); DrawDebugCoordinateSystem(Component->GetWorld(), ActorTransform.GetLocation(), ActorTransform.GetRotation().Rotator(), 100.f); FString DebugString = FString::Printf(TEXT("Socket (X:%f, Y:%f), Target (X:%f, Y:%f), Result (X:%f, Y:%f)") , FMath::RadiansToDegrees(CurrentCoords.X) , FMath::RadiansToDegrees(CurrentCoords.Y) , FMath::RadiansToDegrees(TargetCoords.X) , FMath::RadiansToDegrees(TargetCoords.Y) , BlendInput.X , BlendInput.Y); GEngine->AddOnScreenDebugMessage(INDEX_NONE, 0.f, FColor::Red, DebugString, false); } } } } } }
void UDemoNetDriver::TickDemoRecord( float DeltaSeconds ) { if ( ClientConnections.Num() == 0 ) { return; } if ( FileAr == NULL ) { return; } DemoDeltaTime += DeltaSeconds; const double CurrentSeconds = FPlatformTime::Seconds(); const double RECORD_HZ = CVarDemoRecordHz.GetValueOnGameThread(); const double RECORD_DELAY = 1.0 / RECORD_HZ; if ( CurrentSeconds - LastRecordTime < RECORD_DELAY ) { return; // Not enough real-time has passed to record another frame } LastRecordTime = CurrentSeconds; // Save out a frame DemoFrameNum++; ReplicationFrame++; // Save elapsed game time *FileAr << DemoDeltaTime; #if DEMO_CHECKSUMS == 1 uint32 DeltaTimeChecksum = FCrc::MemCrc32( &DemoDeltaTime, sizeof( DemoDeltaTime ), 0 ); *FileAr << DeltaTimeChecksum; #endif DemoDeltaTime = 0; // Make sure we don't have anything in the buffer for this new frame check( ClientConnections[0]->SendBuffer.GetNumBits() == 0 ); bIsRecordingDemoFrame = true; // Dump any queued packets UDemoNetConnection * ClientDemoConnection = CastChecked< UDemoNetConnection >( ClientConnections[0] ); for ( int32 i = 0; i < ClientDemoConnection->QueuedDemoPackets.Num(); i++ ) { ClientDemoConnection->LowLevelSend( (char*)&ClientDemoConnection->QueuedDemoPackets[i].Data[0], ClientDemoConnection->QueuedDemoPackets[i].Data.Num() ); } ClientDemoConnection->QueuedDemoPackets.Empty(); const bool IsNetClient = ( GetWorld()->GetNetDriver() != NULL && GetWorld()->GetNetDriver()->GetNetMode() == NM_Client ); DemoReplicateActor( World->GetWorldSettings(), ClientConnections[0], IsNetClient ); for ( int32 i = 0; i < World->NetworkActors.Num(); i++ ) { AActor* Actor = World->NetworkActors[i]; Actor->PreReplication( *FindOrCreateRepChangedPropertyTracker( Actor ).Get() ); DemoReplicateActor( Actor, ClientConnections[0], IsNetClient ); } // Make sure nothing is left over ClientConnections[0]->FlushNet(); check( ClientConnections[0]->SendBuffer.GetNumBits() == 0 ); bIsRecordingDemoFrame = false; // Write a count of 0 to signal the end of the frame int32 EndCount = 0; *FileAr << EndCount; }
void FDecalRendering::BuildVisibleDecalList(const FScene& Scene, const FViewInfo& View, EDecalRenderStage DecalRenderStage, FTransientDecalRenderDataList& OutVisibleDecals) { QUICK_SCOPE_CYCLE_COUNTER(BuildVisibleDecalList); OutVisibleDecals.Empty(Scene.Decals.Num()); const float FadeMultiplier = CVarDecalFadeScreenSizeMultiplier.GetValueOnRenderThread(); const EShaderPlatform ShaderPlatform = View.GetShaderPlatform(); const bool bIsPerspectiveProjection = View.IsPerspectiveProjection(); // Build a list of decals that need to be rendered for this view in SortedDecals for (const FDeferredDecalProxy* DecalProxy : Scene.Decals) { bool bIsShown = true; // Handle the decal actor having bHidden set when we are in the editor, in G mode #if WITH_EDITOR if (View.Family->EngineShowFlags.Editor) #endif { if (!DecalProxy->DrawInGame) { bIsShown = false; } } const FMatrix ComponentToWorldMatrix = DecalProxy->ComponentTrans.ToMatrixWithScale(); // can be optimized as we test against a sphere around the box instead of the box itself const float ConservativeRadius = FMath::Sqrt( ComponentToWorldMatrix.GetScaledAxis(EAxis::X).SizeSquared() + ComponentToWorldMatrix.GetScaledAxis(EAxis::Y).SizeSquared() + ComponentToWorldMatrix.GetScaledAxis(EAxis::Z).SizeSquared()); // can be optimized as the test is too conservative (sphere instead of OBB) if(ConservativeRadius < SMALL_NUMBER || !View.ViewFrustum.IntersectSphere(ComponentToWorldMatrix.GetOrigin(), ConservativeRadius)) { bIsShown = false; } if (bIsShown) { FTransientDecalRenderData Data(Scene, DecalProxy, ConservativeRadius); // filter out decals with blend modes that are not supported on current platform if (IsBlendModeSupported(ShaderPlatform, Data.DecalBlendMode)) { if (bIsPerspectiveProjection && Data.DecalProxy->Component->FadeScreenSize != 0.0f) { float Distance = (View.ViewMatrices.ViewOrigin - ComponentToWorldMatrix.GetOrigin()).Size(); float Radius = ComponentToWorldMatrix.GetMaximumAxisScale(); float CurrentScreenSize = ((Radius / Distance) * FadeMultiplier); // fading coefficient needs to increase with increasing field of view and decrease with increasing resolution // FadeCoeffScale is an empirically determined constant to bring us back roughly to fraction of screen size for FadeScreenSize const float FadeCoeffScale = 600.0f; float FOVFactor = ((2.0f/View.ViewMatrices.ProjMatrix.M[0][0]) / View.ViewRect.Width()) * FadeCoeffScale; float FadeCoeff = Data.DecalProxy->Component->FadeScreenSize * FOVFactor; float FadeRange = FadeCoeff * 0.5f; float Alpha = (CurrentScreenSize - FadeCoeff) / FadeRange; Data.FadeAlpha = FMath::Min(Alpha, 1.0f); } EDecalRenderStage LocalDecalRenderStage = ComputeRenderStage(ShaderPlatform, Data.DecalBlendMode); // we could do this test earlier to avoid the decal intersection but getting DecalBlendMode also costs if (View.Family->EngineShowFlags.ShaderComplexity || (DecalRenderStage == LocalDecalRenderStage && Data.FadeAlpha>0.0f) ) { OutVisibleDecals.Add(Data); } } } } if (OutVisibleDecals.Num() > 0) { // Sort by sort order to allow control over composited result // Then sort decals by state to reduce render target switches // Also sort by component since Sort() is not stable struct FCompareFTransientDecalRenderData { FORCEINLINE bool operator()(const FTransientDecalRenderData& A, const FTransientDecalRenderData& B) const { if (B.DecalProxy->SortOrder != A.DecalProxy->SortOrder) { return A.DecalProxy->SortOrder < B.DecalProxy->SortOrder; } // bHasNormal here is more important then blend mode because we want to render every decals that output normals before those that read normal. if (B.bHasNormal != A.bHasNormal) { return B.bHasNormal < A.bHasNormal; // < so that those outputting normal are first. } if (B.DecalBlendMode != A.DecalBlendMode) { return (int32)B.DecalBlendMode < (int32)A.DecalBlendMode; } // Batch decals with the same material together if (B.MaterialProxy != A.MaterialProxy) { return B.MaterialProxy < A.MaterialProxy; } return (PTRINT)B.DecalProxy->Component < (PTRINT)A.DecalProxy->Component; } }; // Sort decals by blend mode to reduce render target switches OutVisibleDecals.Sort(FCompareFTransientDecalRenderData()); } }
bool UseSelectiveBasePassOutputs() { return CVarSelectiveBasePassOutputs.GetValueOnAnyThread() == 1; }
void FSystemSettings::ApplyOverrides() { bool bUseMaxQualityMode = CVarUseMaxQualityMode.GetValueOnGameThread() != 0; if (FParse::Param(FCommandLine::Get(),TEXT("MAXQUALITYMODE"))) { bUseMaxQualityMode = true; } if (FParse::Param(FCommandLine::Get(),TEXT("MSAA"))) { check(0); // todo: set console variable to activate MSAA } if (!FPlatformProperties::SupportsWindowedMode()) { bUseMaxQualityMode = false; } else { // Dump(TEXT("Startup System Settings:")); } if (bUseMaxQualityMode) { // Modify various system settings to get the best quality regardless of performance impact { auto CVar = IConsoleManager::Get().FindConsoleVariable(TEXT("r.Shadow.MinResolution")); CVar->Set(16); } // Disable shadow fading out over distance { auto CVar = IConsoleManager::Get().FindConsoleVariable(TEXT("r.Shadow.FadeResolution")); CVar->Set(1); } // Increase minimum preshadow resolution { auto CVar = IConsoleManager::Get().FindConsoleVariable(TEXT("r.Shadow.MinPreShadowResolution")); CVar->Set(16); } // Disable preshadow fading out over distance { auto CVar = IConsoleManager::Get().FindConsoleVariable(TEXT("r.Shadow.PreShadowFadeResolution")); CVar->Set(1); } // Increase shadow texel density { auto CVar = IConsoleManager::Get().FindConsoleVariable(TEXT("r.Shadow.TexelsPerPixel")); CVar->Set(4.0f); } // Don't downsample preshadows { auto CVar = IConsoleManager::Get().FindConsoleVariable(TEXT("r.Shadow.PreShadowResolutionFactor")); CVar->Set(1.0f); } for (int32 GroupIndex = 0; GroupIndex < TEXTUREGROUP_MAX; GroupIndex++) { FTextureLODSettings::FTextureLODGroup& CurrentGroup = TextureLODSettings.GetTextureLODGroup(GroupIndex); // Use the best quality texture filtering CurrentGroup.Filter = SF_AnisotropicLinear; // Raise texture max sizes to 4096 CurrentGroup.MinLODMipCount = 12; CurrentGroup.MaxLODMipCount = 12; CurrentGroup.LODBias = -1000; } } }
bool FOpenGLES31::SupportsDisjointTimeQueries() { bool bAllowDisjointTimerQueries = false; bAllowDisjointTimerQueries = (CVarDisjointTimerQueries.GetValueOnRenderThread() == 1); return bSupportsDisjointTimeQueries && bAllowDisjointTimerQueries; }
void FCompositionLighting::ProcessAfterLighting(FRHICommandListImmediate& RHICmdList, FViewInfo& View) { check(IsInRenderingThread()); FSceneRenderTargets& SceneContext = FSceneRenderTargets::Get(RHICmdList); GRenderTargetPool.VisualizeTexture.SetCheckPoint(RHICmdList, SceneContext.ReflectiveShadowMapDiffuse); GRenderTargetPool.VisualizeTexture.SetCheckPoint(RHICmdList, SceneContext.ReflectiveShadowMapNormal); GRenderTargetPool.VisualizeTexture.SetCheckPoint(RHICmdList, SceneContext.ReflectiveShadowMapDepth); { FMemMark Mark(FMemStack::Get()); FRenderingCompositePassContext CompositeContext(RHICmdList, View); FPostprocessContext Context(CompositeContext.Graph, View); FRenderingCompositeOutputRef AmbientOcclusion; // Screen Space Subsurface Scattering { float Radius = CVarSSSScale.GetValueOnRenderThread(); bool bSimpleDynamicLighting = IsSimpleDynamicLightingEnabled(); bool bScreenSpaceSubsurfacePassNeeded = (View.ShadingModelMaskInView & (1 << MSM_SubsurfaceProfile)) != 0; if (bScreenSpaceSubsurfacePassNeeded && Radius > 0 && !bSimpleDynamicLighting && View.Family->EngineShowFlags.SubsurfaceScattering && //@todo-rco: Remove this when we fix the cross-compiler !IsOpenGLPlatform(View.GetShaderPlatform())) { // can be optimized out if we don't do split screen/stereo rendering (should be done after we some post process refactoring) FRenderingCompositePass* PassExtractSpecular = Context.Graph.RegisterPass(new(FMemStack::Get()) FRCPassPostProcessSubsurfaceExtractSpecular()); PassExtractSpecular->SetInput(ePId_Input0, Context.FinalOutput); FRenderingCompositePass* PassSetup = Context.Graph.RegisterPass(new(FMemStack::Get()) FRCPassPostProcessSubsurfaceSetup(View)); PassSetup->SetInput(ePId_Input0, Context.FinalOutput); FRenderingCompositePass* Pass0 = Context.Graph.RegisterPass(new(FMemStack::Get()) FRCPassPostProcessSubsurface(0)); Pass0->SetInput(ePId_Input0, PassSetup); FRenderingCompositePass* Pass1 = Context.Graph.RegisterPass(new(FMemStack::Get()) FRCPassPostProcessSubsurface(1)); Pass1->SetInput(ePId_Input0, Pass0); Pass1->SetInput(ePId_Input1, PassSetup); // full res composite pass, no blurring (Radius=0) FRenderingCompositePass* RecombinePass = Context.Graph.RegisterPass(new(FMemStack::Get()) FRCPassPostProcessSubsurfaceRecombine()); RecombinePass->SetInput(ePId_Input0, Pass1); RecombinePass->SetInput(ePId_Input1, PassExtractSpecular); SCOPED_DRAW_EVENT(RHICmdList, CompositionLighting_SSSSS); CompositeContext.Process(RecombinePass, TEXT("CompositionLighting_SSSSS")); } } // The graph setup should be finished before this line ---------------------------------------- SCOPED_DRAW_EVENT(RHICmdList, CompositionAfterLighting); // we don't replace the final element with the scenecolor because this is what those passes should do by themself CompositeContext.Process(Context.FinalOutput.GetPass(), TEXT("CompositionLighting")); } // We only release the after the last view was processed (SplitScreen) if(View.Family->Views[View.Family->Views.Num() - 1] == &View) { // The RT should be released as early as possible to allow sharing of that memory for other purposes. // This becomes even more important with some limited VRam (XBoxOne). SceneContext.SetLightAttenuation(0); } }
void SetParameters(const FRenderingCompositePassContext& Context) { const FPixelShaderRHIParamRef ShaderRHI = GetPixelShader(); FGlobalShader::SetParameters(Context.RHICmdList, ShaderRHI, Context.View); DeferredParameters.Set(Context.RHICmdList, ShaderRHI, Context.View); { bool bFiltered = false; #if !(UE_BUILD_SHIPPING || UE_BUILD_TEST) bFiltered = CVarMotionBlurFiltering.GetValueOnRenderThread() != 0; #endif // !(UE_BUILD_SHIPPING || UE_BUILD_TEST) if(bFiltered) { PostprocessParameter.SetPS(ShaderRHI, Context, TStaticSamplerState<SF_Bilinear,AM_Border,AM_Border,AM_Clamp>::GetRHI()); } else { PostprocessParameter.SetPS(ShaderRHI, Context, TStaticSamplerState<SF_Point,AM_Border,AM_Border,AM_Clamp>::GetRHI()); } } if( Context.View.Family->EngineShowFlags.CameraInterpolation ) { // Instead of finding the world space position of the current pixel, calculate the world space position offset by the camera position, // then translate by the difference between last frame's camera position and this frame's camera position, // then apply the rest of the transforms. This effectively avoids precision issues near the extents of large levels whose world space position is very large. FVector ViewOriginDelta = Context.View.ViewMatrices.ViewOrigin - Context.View.PrevViewMatrices.ViewOrigin; SetShaderValue(Context.RHICmdList, ShaderRHI, PrevViewProjMatrix, FTranslationMatrix(ViewOriginDelta) * Context.View.PrevViewRotationProjMatrix); } else { SetShaderValue(Context.RHICmdList, ShaderRHI, PrevViewProjMatrix, Context.View.ViewMatrices.GetViewRotationProjMatrix()); } TRefCountPtr<IPooledRenderTarget> InputPooledElement = Context.Pass->GetInput(ePId_Input0)->GetOutput()->RequestInput(); // to mask out samples from outside of the view { FIntPoint BufferSize = GSceneRenderTargets.GetBufferSizeXY(); FVector2D InvBufferSize(1.0f / BufferSize.X, 1.0f / BufferSize.Y); FIntRect ClipRect = Context.View.ViewRect; // to avoid leaking in content from the outside because of bilinear filtering, shrink ClipRect.InflateRect(-1); FVector2D MinUV(ClipRect.Min.X * InvBufferSize.X, ClipRect.Min.Y * InvBufferSize.Y); FVector2D MaxUV(ClipRect.Max.X * InvBufferSize.X, ClipRect.Max.Y * InvBufferSize.Y); FVector2D SizeUV = MaxUV - MinUV; FVector2D Mul(1.0f / SizeUV.X, 1.0f / SizeUV.Y); FVector2D Add = - MinUV * Mul; FVector4 TextureViewMadValue(Mul.X, Mul.Y, Add.X, Add.Y); SetShaderValue(Context.RHICmdList, ShaderRHI, TextureViewMad, TextureViewMadValue); } { const float SizeX = Context.View.ViewRect.Width(); const float SizeY = Context.View.ViewRect.Height(); const float AspectRatio = SizeX / SizeY; const float InvAspectRatio = SizeY / SizeX; const FSceneViewState* ViewState = (FSceneViewState*) Context.View.State; float MotionBlurTimeScale = ViewState ? ViewState->MotionBlurTimeScale : 1.0f; float ViewMotionBlurScale = 0.5f * MotionBlurTimeScale * Context.View.FinalPostProcessSettings.MotionBlurAmount; // MotionBlurInstanceScale was needed to hack some cases where motion blur wasn't working well, this shouldn't be needed any more, can clean this up later float MotionBlurInstanceScale = 1; float ObjectMotionBlurScale = MotionBlurInstanceScale * ViewMotionBlurScale; // 0:no 1:full screen width, percent conversion float MaxVelocity = Context.View.FinalPostProcessSettings.MotionBlurMax / 100.0f; float InvMaxVelocity = 1.0f / MaxVelocity; // *2 to convert to -1..1 -1..1 screen space // / MaxFraction to map screenpos to -1..1 normalized MaxFraction FVector4 MotionBlurParametersValue( ObjectMotionBlurScale * InvMaxVelocity, - ObjectMotionBlurScale * InvMaxVelocity * InvAspectRatio, MaxVelocity * 2, - MaxVelocity * 2 * AspectRatio); SetShaderValue(Context.RHICmdList, ShaderRHI, MotionBlurParameters, MotionBlurParametersValue); } }
void FRCPassPostProcessDeferredDecals::Process(FRenderingCompositePassContext& Context) { FRHICommandListImmediate& RHICmdList = Context.RHICmdList; const bool bShaderComplexity = Context.View.Family->EngineShowFlags.ShaderComplexity; const bool bDBuffer = IsDBufferEnabled(); const bool bStencilSizeThreshold = CVarStencilSizeThreshold.GetValueOnRenderThread() >= 0; SCOPED_DRAW_EVENT(RHICmdList, PostProcessDeferredDecals); if(RenderStage == 0) { // before BasePass, only if DBuffer is enabled check(bDBuffer); // DBuffer: Decal buffer FPooledRenderTargetDesc Desc(FPooledRenderTargetDesc::Create2DDesc(GSceneRenderTargets.GBufferA->GetDesc().Extent, PF_B8G8R8A8, TexCreate_None, TexCreate_ShaderResource | TexCreate_RenderTargetable, false)); if(!GSceneRenderTargets.DBufferA) { GRenderTargetPool.FindFreeElement(Desc, GSceneRenderTargets.DBufferA, TEXT("DBufferA")); } if(!GSceneRenderTargets.DBufferB) { GRenderTargetPool.FindFreeElement(Desc, GSceneRenderTargets.DBufferB, TEXT("DBufferB")); } Desc.Format = PF_R8G8; if(!GSceneRenderTargets.DBufferC) { GRenderTargetPool.FindFreeElement(Desc, GSceneRenderTargets.DBufferC, TEXT("DBufferC")); } // we assume views are non overlapping, then we need to clear only once in the beginning, otherwise we would need to set scissor rects // and don't get FastClear any more. bool bFirstView = Context.View.Family->Views[0] == &Context.View; if(bFirstView) { SCOPED_DRAW_EVENT(RHICmdList, DBufferClear); // could be optimized SetRenderTarget(RHICmdList, GSceneRenderTargets.DBufferA->GetRenderTargetItem().TargetableTexture, FTextureRHIParamRef()); RHICmdList.Clear(true, FLinearColor(0, 0, 0, 1), false, (float)ERHIZBuffer::FarPlane, false, 0, FIntRect()); SetRenderTarget(RHICmdList, GSceneRenderTargets.DBufferB->GetRenderTargetItem().TargetableTexture, FTextureRHIParamRef()); // todo: some hardware would like to have 0 or 1 for faster clear, we chose 128/255 to represent 0 (8 bit cannot represent 0.5f) RHICmdList.Clear(true, FLinearColor(128.0f / 255.0f, 128.0f / 255.0f, 128.0f / 255.0f, 1), false, (float)ERHIZBuffer::FarPlane, false, 0, FIntRect()); SetRenderTarget(RHICmdList, GSceneRenderTargets.DBufferC->GetRenderTargetItem().TargetableTexture, FTextureRHIParamRef()); // R:roughness, G:roughness opacity RHICmdList.Clear(true, FLinearColor(0, 1, 0, 1), false, (float)ERHIZBuffer::FarPlane, false, 0, FIntRect()); } } // this cast is safe as only the dedicated server implements this differently and this pass should not be executed on the dedicated server const FViewInfo& View = Context.View; const FSceneViewFamily& ViewFamily = *(View.Family); FScene& Scene = *(FScene*)ViewFamily.Scene; if(!Scene.Decals.Num()) { // to avoid the stats showing up return; } TArray<FTransientDecalRenderData, SceneRenderingAllocator> SortedDecals; SortedDecals.Empty(Scene.Decals.Num()); // Build a list of decals that need to be rendered for this view in SortedDecals for (TSparseArray<FDeferredDecalProxy*>::TConstIterator It(Scene.Decals); It; ++It) { FDeferredDecalProxy* DecalProxy = *It; bool bIsShown = true; // Handle the decal actor having bHidden set when we are in the editor, in G mode #if WITH_EDITOR if (View.Family->EngineShowFlags.Editor) #endif { if (!DecalProxy->DrawInGame) { bIsShown = false; } } const FMatrix ComponentToWorldMatrix = DecalProxy->ComponentTrans.ToMatrixWithScale(); // can be optimized as we test against a sphere around the box instead of the box itself const float ConservativeRadius = FMath::Sqrt( ComponentToWorldMatrix.GetScaledAxis( EAxis::X ).SizeSquared() * FMath::Square(GDefaultDecalSize.X) + ComponentToWorldMatrix.GetScaledAxis( EAxis::Y ).SizeSquared() * FMath::Square(GDefaultDecalSize.Y) + ComponentToWorldMatrix.GetScaledAxis( EAxis::Z ).SizeSquared() * FMath::Square(GDefaultDecalSize.Z)); // can be optimized as the test is too conservative (sphere instead of OBB) if(ConservativeRadius < SMALL_NUMBER || !View.ViewFrustum.IntersectSphere(ComponentToWorldMatrix.GetOrigin(), ConservativeRadius)) { bIsShown = false; } if (bIsShown) { FTransientDecalRenderData Data(Scene, DecalProxy); uint32 DecalRenderStage = ComputeRenderStage(Data.DecalBlendMode); // we could do this test earlier to avoid the decal intersection but getting DecalBlendMode also costs if (Context.View.Family->EngineShowFlags.ShaderComplexity || RenderStage == DecalRenderStage) { SortedDecals.Add(Data); } } } if(SortedDecals.Num() > 0) { FIntRect SrcRect = View.ViewRect; FIntRect DestRect = View.ViewRect; bool bStencilDecals = true; #if DBUFFER_DONT_USE_STENCIL_YET if(RenderStage == 0) { bStencilDecals = false; } #endif // Setup a stencil mask to prevent certain pixels from receiving deferred decals if(bStencilDecals) { StencilDecalMask(RHICmdList, View); } // Sort by sort order to allow control over composited result // Then sort decals by state to reduce render target switches // Also sort by component since Sort() is not stable struct FCompareFTransientDecalRenderData { FORCEINLINE bool operator()( const FTransientDecalRenderData& A, const FTransientDecalRenderData& B ) const { if (B.DecalProxy->SortOrder != A.DecalProxy->SortOrder) { return A.DecalProxy->SortOrder < B.DecalProxy->SortOrder; } if (B.DecalBlendMode != A.DecalBlendMode) { return (int32)B.DecalBlendMode < (int32)A.DecalBlendMode; } if (B.bHasNormal != A.bHasNormal) { return B.bHasNormal < A.bHasNormal; } // Batch decals with the same material together if (B.MaterialProxy != A.MaterialProxy ) { return B.MaterialProxy < A.MaterialProxy; } return (PTRINT)B.DecalProxy->Component < (PTRINT)A.DecalProxy->Component; } }; // Sort decals by blend mode to reduce render target switches SortedDecals.Sort( FCompareFTransientDecalRenderData() ); // optimization to have less state changes int32 LastDecalBlendMode = -1; int32 LastDecalHasNormal = -1; // Decal state can change based on its normal property.(SM5) ERenderTargetMode LastRenderTargetMode = RTM_Unknown; int32 WasInsideDecal = -1; const ERHIFeatureLevel::Type SMFeatureLevel = Context.GetFeatureLevel(); SCOPED_DRAW_EVENT(RHICmdList, Decals); INC_DWORD_STAT_BY(STAT_Decals, SortedDecals.Num()); enum EDecalResolveBufferIndex { SceneColorIndex, GBufferAIndex, GBufferBIndex, GBufferCIndex, DBufferAIndex, DBufferBIndex, DBufferCIndex, ResolveBufferMax, }; FTextureRHIParamRef TargetsToResolve[ResolveBufferMax] = { nullptr }; for (int32 DecalIndex = 0, DecalCount = SortedDecals.Num(); DecalIndex < DecalCount; DecalIndex++) { const FTransientDecalRenderData& DecalData = SortedDecals[DecalIndex]; const FDeferredDecalProxy& DecalProxy = *DecalData.DecalProxy; const FMatrix ComponentToWorldMatrix = DecalProxy.ComponentTrans.ToMatrixWithScale(); // Set vertex shader params const FMaterialShaderMap* MaterialShaderMap = DecalData.MaterialResource->GetRenderingThreadShaderMap(); FScaleMatrix DecalScaleTransform(GDefaultDecalSize); FTranslationMatrix PreViewTranslation(View.ViewMatrices.PreViewTranslation); FMatrix FrustumComponentToClip = DecalScaleTransform * ComponentToWorldMatrix * PreViewTranslation * View.ViewMatrices.TranslatedViewProjectionMatrix; // can be optimized as we test against a sphere around the box instead of the box itself const float ConservativeRadius = FMath::Sqrt( ComponentToWorldMatrix.GetScaledAxis( EAxis::X ).SizeSquared() * FMath::Square(GDefaultDecalSize.X) + ComponentToWorldMatrix.GetScaledAxis( EAxis::Y ).SizeSquared() * FMath::Square(GDefaultDecalSize.Y) + ComponentToWorldMatrix.GetScaledAxis( EAxis::Z ).SizeSquared() * FMath::Square(GDefaultDecalSize.Z)); EDecalBlendMode DecalBlendMode = DecalData.DecalBlendMode; bool bStencilThisDecal = bStencilDecals; #if DBUFFER_DONT_USE_STENCIL_YET if(ComputeRenderStage(DecalBlendMode) == 0) { bStencilThisDecal = false; } #endif ERenderTargetMode CurrentRenderTargetMode = ComputeRenderTargetMode(DecalBlendMode); if(bShaderComplexity) { CurrentRenderTargetMode = RTM_SceneColor; // we want additive blending for the ShaderComplexity mode DecalBlendMode = DBM_Emissive; } // fewer rendertarget switches if possible if(CurrentRenderTargetMode != LastRenderTargetMode) { LastRenderTargetMode = CurrentRenderTargetMode; switch(CurrentRenderTargetMode) { case RTM_SceneColorAndGBuffer: { TargetsToResolve[SceneColorIndex] = GSceneRenderTargets.GetSceneColor()->GetRenderTargetItem().TargetableTexture; TargetsToResolve[GBufferAIndex] = GSceneRenderTargets.GBufferA->GetRenderTargetItem().TargetableTexture; TargetsToResolve[GBufferBIndex] = GSceneRenderTargets.GBufferB->GetRenderTargetItem().TargetableTexture; TargetsToResolve[GBufferCIndex] = GSceneRenderTargets.GBufferC->GetRenderTargetItem().TargetableTexture; SetRenderTargets(RHICmdList, 4, TargetsToResolve, GSceneRenderTargets.GetSceneDepthSurface(), ESimpleRenderTargetMode::EExistingColorAndDepth, FExclusiveDepthStencil::DepthRead_StencilWrite); } break; case RTM_GBufferNormal: TargetsToResolve[GBufferAIndex] = GSceneRenderTargets.GBufferA->GetRenderTargetItem().TargetableTexture; SetRenderTarget(RHICmdList, TargetsToResolve[GBufferAIndex], GSceneRenderTargets.GetSceneDepthSurface(), ESimpleRenderTargetMode::EExistingColorAndDepth, FExclusiveDepthStencil::DepthRead_StencilWrite); break; case RTM_SceneColor: TargetsToResolve[SceneColorIndex] = GSceneRenderTargets.GetSceneColor()->GetRenderTargetItem().TargetableTexture; SetRenderTarget(RHICmdList, TargetsToResolve[SceneColorIndex], GSceneRenderTargets.GetSceneDepthSurface(), ESimpleRenderTargetMode::EExistingColorAndDepth, FExclusiveDepthStencil::DepthRead_StencilWrite); break; case RTM_DBuffer: { TargetsToResolve[DBufferAIndex] = GSceneRenderTargets.DBufferA->GetRenderTargetItem().TargetableTexture; TargetsToResolve[DBufferBIndex] = GSceneRenderTargets.DBufferB->GetRenderTargetItem().TargetableTexture; TargetsToResolve[DBufferCIndex] = GSceneRenderTargets.DBufferC->GetRenderTargetItem().TargetableTexture; SetRenderTargets(RHICmdList, 3, &TargetsToResolve[DBufferAIndex], GSceneRenderTargets.GetSceneDepthSurface(), ESimpleRenderTargetMode::EExistingColorAndDepth, FExclusiveDepthStencil::DepthRead_StencilWrite); } break; default: check(0); break; } Context.SetViewportAndCallRHI(DestRect); // we need to reset the stream source after any call to SetRenderTarget (at least for Metal, which doesn't queue up VB assignments) RHICmdList.SetStreamSource(0, GUnitCubeVertexBuffer.VertexBufferRHI, sizeof(FVector4), 0); } bool bThisDecalUsesStencil = false; if (bStencilThisDecal) { if (bStencilSizeThreshold) { // note this is after a SetStreamSource (in if CurrentRenderTargetMode != LastRenderTargetMode) call as it needs to get the VB input bThisDecalUsesStencil = RenderPreStencil(Context, MaterialShaderMap, ComponentToWorldMatrix, FrustumComponentToClip); WasInsideDecal = -1; LastDecalBlendMode = -1; } } const bool bBlendStateChange = DecalBlendMode != LastDecalBlendMode;// Has decal mode changed. const bool bDecalNormalChanged = GSupportsSeparateRenderTargetBlendState && // has normal changed for SM5 stain/translucent decals? (DecalBlendMode == DBM_Translucent || DecalBlendMode == DBM_Stain) && (int32)DecalData.bHasNormal != LastDecalHasNormal; // fewer blend state changes if possible if (bBlendStateChange || bDecalNormalChanged) { LastDecalBlendMode = DecalBlendMode; LastDecalHasNormal = (int32)DecalData.bHasNormal; SetDecalBlendState(RHICmdList, SMFeatureLevel, RenderStage, (EDecalBlendMode)LastDecalBlendMode, DecalData.bHasNormal); } { TShaderMapRef<FDeferredDecalVS> VertexShader(Context.GetShaderMap()); SetShader(Context, bShaderComplexity, DecalData, *VertexShader); VertexShader->SetParameters(RHICmdList, View, FrustumComponentToClip); const int32 IsInsideDecal = ((FVector)View.ViewMatrices.ViewOrigin - ComponentToWorldMatrix.GetOrigin()).SizeSquared() < FMath::Square(ConservativeRadius * 1.05f + View.NearClippingDistance * 2.0f) + ( bThisDecalUsesStencil ) ? 2 : 0; if ( WasInsideDecal != IsInsideDecal ) { WasInsideDecal = IsInsideDecal; if ( !(IsInsideDecal & 1) ) { // Render backfaces with depth tests disabled since the camera is inside (or close to inside) the light function geometry RHICmdList.SetRasterizerState(View.bReverseCulling ? TStaticRasterizerState<FM_Solid, CM_CCW>::GetRHI() : TStaticRasterizerState<FM_Solid, CM_CW>::GetRHI()); if(bStencilDecals) { // Enable stencil testing, only write to pixels with stencil of 0 if ( bThisDecalUsesStencil ) { RHICmdList.SetDepthStencilState(TStaticDepthStencilState< false,CF_Always, true,CF_Equal,SO_Zero,SO_Zero,SO_Zero, true,CF_Equal,SO_Zero,SO_Zero,SO_Zero, 0xff, 0x7f >::GetRHI(), 1); } else { RHICmdList.SetDepthStencilState(TStaticDepthStencilState< false,CF_Always, true,CF_Equal,SO_Keep,SO_Keep,SO_Keep, false,CF_Always,SO_Keep,SO_Keep,SO_Keep, 0x80,0x00>::GetRHI(), 0); } } else { RHICmdList.SetDepthStencilState(TStaticDepthStencilState<false, CF_Always, true>::GetRHI(), 0); } } else { // Render frontfaces with depth tests on to get the speedup from HiZ since the camera is outside the light function geometry if(bStencilDecals) { // Render frontfaces with depth tests on to get the speedup from HiZ since the camera is outside the light function geometry // Enable stencil testing, only write to pixels with stencil of 0 if ( bThisDecalUsesStencil ) { RHICmdList.SetDepthStencilState(TStaticDepthStencilState< false,CF_DepthNearOrEqual, true,CF_Equal,SO_Zero,SO_Zero,SO_Zero, true,CF_Equal,SO_Zero,SO_Zero,SO_Zero, 0xff, 0x7f >::GetRHI(), 1); } else { RHICmdList.SetDepthStencilState(TStaticDepthStencilState< false,CF_DepthNearOrEqual, true,CF_Equal,SO_Keep,SO_Keep,SO_Keep, false,CF_Always,SO_Keep,SO_Keep,SO_Keep, 0x80,0x00>::GetRHI(), 0); } RHICmdList.SetRasterizerState(View.bReverseCulling ? TStaticRasterizerState<FM_Solid, CM_CW>::GetRHI() : TStaticRasterizerState<FM_Solid, CM_CCW>::GetRHI()); } else { RHICmdList.SetDepthStencilState(TStaticDepthStencilState<false, CF_DepthNearOrEqual>::GetRHI(), 0); } RHICmdList.SetRasterizerState(View.bReverseCulling ? TStaticRasterizerState<FM_Solid, CM_CW>::GetRHI() : TStaticRasterizerState<FM_Solid, CM_CCW>::GetRHI()); } } RHICmdList.DrawIndexedPrimitive(GUnitCubeIndexBuffer.IndexBufferRHI, PT_TriangleList, 0, 0, 8, 0, GUnitCubeIndexBuffer.GetIndexCount() / 3, 1); } } // we don't modify stencil but if out input was having stencil for us (after base pass - we need to clear) // Clear stencil to 0, which is the assumed default by other passes RHICmdList.Clear(false, FLinearColor::White, false, (float)ERHIZBuffer::FarPlane, true, 0, FIntRect()); // resolve the targets we wrote to. FResolveParams ResolveParams; for (int32 i = 0; i < ResolveBufferMax; ++i) { if (TargetsToResolve[i]) { RHICmdList.CopyToResolveTarget(TargetsToResolve[i], TargetsToResolve[i], true, ResolveParams); } } } if(RenderStage == 0) { // before BasePass GRenderTargetPool.VisualizeTexture.SetCheckPoint(RHICmdList, GSceneRenderTargets.DBufferA); GRenderTargetPool.VisualizeTexture.SetCheckPoint(RHICmdList, GSceneRenderTargets.DBufferB); GRenderTargetPool.VisualizeTexture.SetCheckPoint(RHICmdList, GSceneRenderTargets.DBufferC); } }