FShadowMap2D* FShadowMap2D::AllocateInstancedShadowMap(UInstancedStaticMeshComponent* Component, TArray<TMap<ULightComponent*, TUniquePtr<FShadowMapData2D>>> InstancedShadowMapData, const FBoxSphereBounds& Bounds, ELightMapPaddingType InPaddingType, EShadowMapFlags InShadowmapFlags) { #if WITH_EDITOR check(InstancedShadowMapData.Num() > 0); // Verify all instance shadowmaps are the same size, and build complete list of shadow lights int32 SizeX = -1; int32 SizeY = -1; TSet<ULightComponent*> AllLights; for (auto& ShadowMapData : InstancedShadowMapData) { for (const auto& ShadowDataPair : ShadowMapData) { if (SizeX == -1) { SizeX = ShadowDataPair.Value->GetSizeX(); SizeY = ShadowDataPair.Value->GetSizeY(); } else { check(ShadowDataPair.Value->GetSizeX() == SizeX); check(ShadowDataPair.Value->GetSizeY() == SizeY); } AllLights.Add(ShadowDataPair.Key); } } check(SizeX != -1 && SizeY != -1); // No valid shadowmaps TArray<FGuid> LightGuids; LightGuids.Reserve(AllLights.Num()); for (ULightComponent* Light : AllLights) { LightGuids.Add(Light->LightGuid); } // Unify all the shadow map data to contain the same lights in the same order for (auto& ShadowMapData : InstancedShadowMapData) { for (ULightComponent* Light : AllLights) { if (!ShadowMapData.Contains(Light)) { ShadowMapData.Add(Light, MakeUnique<FQuantizedShadowSignedDistanceFieldData2D>(SizeX, SizeY)); } } } FShadowMapAllocationGroup AllocationGroup; AllocationGroup.TextureOuter = Component->GetOutermost(); AllocationGroup.ShadowmapFlags = InShadowmapFlags; AllocationGroup.Bounds = Bounds; if (!GAllowStreamingLightmaps) { AllocationGroup.ShadowmapFlags = EShadowMapFlags(AllocationGroup.ShadowmapFlags & ~SMF_Streamed); } FShadowMap2D* BaseShadowmap = nullptr; for (int32 InstanceIndex = 0; InstanceIndex < InstancedShadowMapData.Num(); ++InstanceIndex) { auto& ShadowMapData = InstancedShadowMapData[InstanceIndex]; check(ShadowMapData.Num() > 0); // Create a new shadow-map. FShadowMap2D* ShadowMap = new FShadowMap2D(LightGuids); if (InstanceIndex == 0) { BaseShadowmap = ShadowMap; } // Add a pending allocation for this shadow-map. TUniquePtr<FShadowMapAllocation> Allocation = MakeUnique<FShadowMapAllocation>(); Allocation->PaddingType = InPaddingType; Allocation->ShadowMap = ShadowMap; Allocation->TotalSizeX = SizeX; Allocation->TotalSizeY = SizeY; Allocation->MappedRect = FIntRect(0, 0, SizeX, SizeY); Allocation->Primitive = Component; Allocation->InstanceIndex = InstanceIndex; for (auto& ShadowDataPair : ShadowMapData) { auto& RawData = ShadowDataPair.Value; auto& DistanceFieldShadowData = Allocation->ShadowMapData.Add(ShadowDataPair.Key, TArray<FQuantizedSignedDistanceFieldShadowSample>()); switch (RawData->GetType()) { case FShadowMapData2D::SHADOW_SIGNED_DISTANCE_FIELD_DATA: case FShadowMapData2D::SHADOW_SIGNED_DISTANCE_FIELD_DATA_QUANTIZED: // If the data is already quantized, this will just copy the data RawData->Quantize(DistanceFieldShadowData); break; default: check(0); } RawData.Reset(); // Track the size of pending light-maps. PendingShadowMapSize += Allocation->TotalSizeX * Allocation->TotalSizeY; } // Assumes bAlignByFour AllocationGroup.TotalTexels += ((Allocation->MappedRect.Width() + 3) & ~3) * ((Allocation->MappedRect.Height() + 3) & ~3); AllocationGroup.Allocations.Add(MoveTemp(Allocation)); } PendingShadowMaps.Add(MoveTemp(AllocationGroup)); return BaseShadowmap; #else return nullptr; #endif }
void ComputeDiffuseIrradiance(FRHICommandListImmediate& RHICmdList, ERHIFeatureLevel::Type FeatureLevel, FTextureRHIRef LightingSource, int32 LightingSourceMipIndex, FSHVectorRGB3* OutIrradianceEnvironmentMap) { auto ShaderMap = GetGlobalShaderMap(FeatureLevel); FSceneRenderTargets& SceneContext = FSceneRenderTargets::Get(RHICmdList); for (int32 CoefficientIndex = 0; CoefficientIndex < FSHVector3::MaxSHBasis; CoefficientIndex++) { // Copy the starting mip from the lighting texture, apply texel area weighting and appropriate SH coefficient { const int32 MipIndex = 0; const int32 MipSize = GDiffuseIrradianceCubemapSize; FSceneRenderTargetItem& EffectiveRT = GetEffectiveDiffuseIrradianceRenderTarget(SceneContext, MipIndex); for (int32 CubeFace = 0; CubeFace < CubeFace_MAX; CubeFace++) { SetRenderTarget(RHICmdList, EffectiveRT.TargetableTexture, 0, CubeFace, NULL); const FIntRect ViewRect(0, 0, MipSize, MipSize); RHICmdList.SetViewport(0, 0, 0.0f, MipSize, MipSize, 1.0f); RHICmdList.SetRasterizerState(TStaticRasterizerState<FM_Solid, CM_None>::GetRHI()); RHICmdList.SetDepthStencilState(TStaticDepthStencilState<false, CF_Always>::GetRHI()); RHICmdList.SetBlendState(TStaticBlendState<>::GetRHI()); TShaderMapRef<FCopyDiffuseIrradiancePS> PixelShader(ShaderMap); TShaderMapRef<FScreenVS> VertexShader(GetGlobalShaderMap(FeatureLevel)); SetGlobalBoundShaderState(RHICmdList, FeatureLevel, CopyDiffuseIrradianceShaderState, GFilterVertexDeclaration.VertexDeclarationRHI, *VertexShader, *PixelShader); PixelShader->SetParameters(RHICmdList, CubeFace, LightingSourceMipIndex, CoefficientIndex, MipSize, LightingSource); DrawRectangle( RHICmdList, ViewRect.Min.X, ViewRect.Min.Y, ViewRect.Width(), ViewRect.Height(), ViewRect.Min.X, ViewRect.Min.Y, ViewRect.Width(), ViewRect.Height(), FIntPoint(ViewRect.Width(), ViewRect.Height()), FIntPoint(MipSize, MipSize), *VertexShader); RHICmdList.CopyToResolveTarget(EffectiveRT.TargetableTexture, EffectiveRT.ShaderResourceTexture, true, FResolveParams(FResolveRect(), (ECubeFace)CubeFace, MipIndex)); } } const int32 NumMips = FMath::CeilLogTwo(GDiffuseIrradianceCubemapSize) + 1; { // Accumulate all the texel values through downsampling to 1x1 mip for (int32 MipIndex = 1; MipIndex < NumMips; MipIndex++) { const int32 SourceMipIndex = FMath::Max(MipIndex - 1, 0); const int32 MipSize = 1 << (NumMips - MipIndex - 1); FSceneRenderTargetItem& EffectiveRT = GetEffectiveDiffuseIrradianceRenderTarget(SceneContext, MipIndex); FSceneRenderTargetItem& EffectiveSource = GetEffectiveDiffuseIrradianceSourceTexture(SceneContext, MipIndex); check(EffectiveRT.TargetableTexture != EffectiveSource.ShaderResourceTexture); for (int32 CubeFace = 0; CubeFace < CubeFace_MAX; CubeFace++) { SetRenderTarget(RHICmdList, EffectiveRT.TargetableTexture, MipIndex, CubeFace, NULL); const FIntRect ViewRect(0, 0, MipSize, MipSize); RHICmdList.SetViewport(0, 0, 0.0f, MipSize, MipSize, 1.0f); RHICmdList.SetRasterizerState(TStaticRasterizerState<FM_Solid, CM_None>::GetRHI()); RHICmdList.SetDepthStencilState(TStaticDepthStencilState<false, CF_Always>::GetRHI()); RHICmdList.SetBlendState(TStaticBlendState<>::GetRHI()); TShaderMapRef<FAccumulateDiffuseIrradiancePS> PixelShader(ShaderMap); TShaderMapRef<FScreenVS> VertexShader(GetGlobalShaderMap(FeatureLevel)); SetGlobalBoundShaderState(RHICmdList, FeatureLevel, DiffuseIrradianceAccumulateShaderState, GFilterVertexDeclaration.VertexDeclarationRHI, *VertexShader, *PixelShader); PixelShader->SetParameters(RHICmdList, CubeFace, NumMips, SourceMipIndex, CoefficientIndex, EffectiveSource.ShaderResourceTexture); DrawRectangle( RHICmdList, ViewRect.Min.X, ViewRect.Min.Y, ViewRect.Width(), ViewRect.Height(), ViewRect.Min.X, ViewRect.Min.Y, ViewRect.Width(), ViewRect.Height(), FIntPoint(ViewRect.Width(), ViewRect.Height()), FIntPoint(MipSize, MipSize), *VertexShader); RHICmdList.CopyToResolveTarget(EffectiveRT.TargetableTexture, EffectiveRT.ShaderResourceTexture, true, FResolveParams(FResolveRect(), (ECubeFace)CubeFace, MipIndex)); } } } { // Gather the cubemap face results and normalize, copy this coefficient to FSceneRenderTargets::Get(RHICmdList).SkySHIrradianceMap FSceneRenderTargetItem& EffectiveRT = FSceneRenderTargets::Get(RHICmdList).SkySHIrradianceMap->GetRenderTargetItem(); //load/store actions so we don't lose results as we render one pixel at a time on tile renderers. FRHIRenderTargetView RTV(EffectiveRT.TargetableTexture, 0, -1, ERenderTargetLoadAction::ELoad, ERenderTargetStoreAction::EStore); RHICmdList.SetRenderTargets(1, &RTV, nullptr, 0, nullptr); const FIntRect ViewRect(CoefficientIndex, 0, CoefficientIndex + 1, 1); RHICmdList.SetViewport(0, 0, 0.0f, FSHVector3::MaxSHBasis, 1, 1.0f); RHICmdList.SetRasterizerState(TStaticRasterizerState<FM_Solid, CM_None>::GetRHI()); RHICmdList.SetDepthStencilState(TStaticDepthStencilState<false, CF_Always>::GetRHI()); RHICmdList.SetBlendState(TStaticBlendState<>::GetRHI()); TShaderMapRef<FScreenVS> VertexShader(ShaderMap); TShaderMapRef<FAccumulateCubeFacesPS> PixelShader(ShaderMap); SetGlobalBoundShaderState(RHICmdList, FeatureLevel, AccumulateCubeFacesBoundShaderState, GFilterVertexDeclaration.VertexDeclarationRHI, *VertexShader, *PixelShader); const int32 SourceMipIndex = NumMips - 1; const int32 MipSize = 1; FSceneRenderTargetItem& EffectiveSource = GetEffectiveDiffuseIrradianceRenderTarget(SceneContext, SourceMipIndex); PixelShader->SetParameters(RHICmdList, SourceMipIndex, EffectiveSource.ShaderResourceTexture); DrawRectangle( RHICmdList, ViewRect.Min.X, ViewRect.Min.Y, ViewRect.Width(), ViewRect.Height(), 0, 0, MipSize, MipSize, FIntPoint(FSHVector3::MaxSHBasis, 1), FIntPoint(MipSize, MipSize), *VertexShader); RHICmdList.CopyToResolveTarget(EffectiveRT.TargetableTexture, EffectiveRT.ShaderResourceTexture, true, FResolveParams()); } } { // Read back the completed SH environment map FSceneRenderTargetItem& EffectiveRT = FSceneRenderTargets::Get(RHICmdList).SkySHIrradianceMap->GetRenderTargetItem(); check(EffectiveRT.ShaderResourceTexture->GetFormat() == PF_FloatRGBA); TArray<FFloat16Color> SurfaceData; RHICmdList.ReadSurfaceFloatData(EffectiveRT.ShaderResourceTexture, FIntRect(0, 0, FSHVector3::MaxSHBasis, 1), SurfaceData, CubeFace_PosX, 0, 0); check(SurfaceData.Num() == FSHVector3::MaxSHBasis); for (int32 CoefficientIndex = 0; CoefficientIndex < FSHVector3::MaxSHBasis; CoefficientIndex++) { const FLinearColor CoefficientValue(SurfaceData[CoefficientIndex]); OutIrradianceEnvironmentMap->R.V[CoefficientIndex] = CoefficientValue.R; OutIrradianceEnvironmentMap->G.V[CoefficientIndex] = CoefficientValue.G; OutIrradianceEnvironmentMap->B.V[CoefficientIndex] = CoefficientValue.B; } } }
void FRCPassPostProcessDownsample::Process(FRenderingCompositePassContext& Context) { SCOPED_DRAW_EVENT(Context.RHICmdList, Downsample); const FPooledRenderTargetDesc* InputDesc = GetInputDesc(ePId_Input0); if(!InputDesc) { // input is not hooked up correctly return; } const FSceneView& View = Context.View; const FSceneViewFamily& ViewFamily = *(View.Family); 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; 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 ); // set the state Context.RHICmdList.SetBlendState(TStaticBlendState<>::GetRHI()); Context.RHICmdList.SetRasterizerState(TStaticRasterizerState<>::GetRHI()); Context.RHICmdList.SetDepthStencilState(TStaticDepthStencilState<false, CF_Always>::GetRHI()); // InflateSize increases the size of the source/dest rectangle to compensate for bilinear reads and UIBlur pass requirements. int32 InflateSize; // if second input is hooked up if (IsDepthInputAvailable()) { // also put depth in alpha InflateSize = 2; SetShader<2>(Context); } else { if (Quality == 0) { SetShader<0>(Context); InflateSize = 1; } else { SetShader<1>(Context); InflateSize = 2; } } bool bHasCleared = false; // check if we have to clear the whole surface. // Otherwise perform the clear when the dest rectangle has been computed. auto FeatureLevel = Context.View.GetFeatureLevel(); if (FeatureLevel == ERHIFeatureLevel::ES2 || FeatureLevel == ERHIFeatureLevel::ES3_1) { Context.RHICmdList.Clear(true, FLinearColor(0, 0, 0, 0), false, 1.0f, false, 0, FIntRect()); bHasCleared = true; } TShaderMapRef<FPostProcessDownsampleVS> VertexShader(Context.GetShaderMap()); FIntRect SrcRect = View.ViewRect / ScaleFactor; FIntRect DestRect = FIntRect::DivideAndRoundUp(SrcRect, 2); SrcRect = DestRect * 2; if (!bHasCleared) { Context.RHICmdList.Clear(true, FLinearColor(0, 0, 0, 0), false, 1.0f, false, 0, DestRect); } 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()); }
FShadowMap2D* FShadowMap2D::AllocateShadowMap( UObject* Outer, const TMap<ULightComponent*,FShadowMapData2D*>& ShadowMapData, const FBoxSphereBounds& Bounds, ELightMapPaddingType InPaddingType, EShadowMapFlags InShadowmapFlags) { #if WITH_EDITOR check(ShadowMapData.Num() > 0); FShadowMapAllocationGroup AllocationGroup; AllocationGroup.TextureOuter = Outer->GetOutermost(); AllocationGroup.ShadowmapFlags = InShadowmapFlags; AllocationGroup.Bounds = Bounds; if (!GAllowStreamingLightmaps) { AllocationGroup.ShadowmapFlags = EShadowMapFlags(AllocationGroup.ShadowmapFlags & ~SMF_Streamed); } // Create a new shadow-map. FShadowMap2D* ShadowMap = new FShadowMap2D(ShadowMapData); // Calculate Shadowmap size int32 SizeX = -1; int32 SizeY = -1; int32 LightIndex = 0; for (const auto& ShadowDataPair : ShadowMapData) { if (LightIndex == 0) { SizeX = ShadowDataPair.Value->GetSizeX(); SizeY = ShadowDataPair.Value->GetSizeY(); } else { check(SizeX == ShadowDataPair.Value->GetSizeX() && SizeY == ShadowDataPair.Value->GetSizeY()); } LightIndex++; } check(SizeX != -1 && SizeY != -1); // Add a pending allocation for this shadow-map. TUniquePtr<FShadowMapAllocation> Allocation = MakeUnique<FShadowMapAllocation>(); Allocation->PaddingType = InPaddingType; Allocation->ShadowMap = ShadowMap; Allocation->TotalSizeX = SizeX; Allocation->TotalSizeY = SizeY; Allocation->MappedRect = FIntRect(0, 0, SizeX, SizeY); Allocation->PaddingType = InPaddingType; for (const auto& ShadowDataPair : ShadowMapData) { const FShadowMapData2D* RawData = ShadowDataPair.Value; TArray<FQuantizedSignedDistanceFieldShadowSample>& DistanceFieldShadowData = Allocation->ShadowMapData.Add(ShadowDataPair.Key, TArray<FQuantizedSignedDistanceFieldShadowSample>()); switch (RawData->GetType()) { case FShadowMapData2D::SHADOW_SIGNED_DISTANCE_FIELD_DATA: case FShadowMapData2D::SHADOW_SIGNED_DISTANCE_FIELD_DATA_QUANTIZED: // If the data is already quantized, this will just copy the data RawData->Quantize(DistanceFieldShadowData); break; default: check(0); } delete RawData; // Track the size of pending light-maps. PendingShadowMapSize += Allocation->TotalSizeX * Allocation->TotalSizeY; } // Assumes bAlignByFour AllocationGroup.TotalTexels += ((Allocation->MappedRect.Width() + 3) & ~3) * ((Allocation->MappedRect.Height() + 3) & ~3); AllocationGroup.Allocations.Add(MoveTemp(Allocation)); PendingShadowMaps.Add(MoveTemp(AllocationGroup)); return ShadowMap; #else return nullptr; #endif }
void FRCPassPostProcessUpscale::Process(FRenderingCompositePassContext& Context) { SCOPED_DRAW_EVENT(Context.RHICmdList, PostProcessUpscale); const FPooledRenderTargetDesc* InputDesc = GetInputDesc(ePId_Input0); if(!InputDesc) { // input is not hooked up correctly return; } const FSceneView& View = Context.View; const FSceneViewFamily& ViewFamily = *(View.Family); FIntRect SrcRect = View.ViewRect; FIntRect DestRect = View.UnscaledViewRect; FIntPoint SrcSize = InputDesc->Extent; const FSceneRenderTargetItem& DestRenderTarget = PassOutputs[0].RequestSurface(Context); // Set the view family's render target/viewport. SetRenderTarget(Context.RHICmdList, DestRenderTarget.TargetableTexture, FTextureRHIRef()); Context.SetViewportAndCallRHI(DestRect); bool bTessellatedQuad = PaniniConfig.D >= 0.01f; // with distortion (bTessellatedQuad) we need to clear the background FIntRect ExcludeRect = bTessellatedQuad ? FIntRect() : DestRect; Context.RHICmdList.Clear(true, FLinearColor::Black, false, 1.0f, false, 0, ExcludeRect); // set the state Context.RHICmdList.SetBlendState(TStaticBlendState<>::GetRHI()); Context.RHICmdList.SetRasterizerState(TStaticRasterizerState<>::GetRHI()); Context.RHICmdList.SetDepthStencilState(TStaticDepthStencilState<false, CF_Always>::GetRHI()); FShader* VertexShader = 0; if(bTessellatedQuad) { switch (UpscaleQuality) { case 0: VertexShader = SetShader<0, 1>(Context, PaniniConfig); break; case 1: VertexShader = SetShader<1, 1>(Context, PaniniConfig); break; case 2: VertexShader = SetShader<2, 1>(Context, PaniniConfig); break; case 3: VertexShader = SetShader<3, 1>(Context, PaniniConfig); break; default: checkNoEntry(); break; } } else { switch (UpscaleQuality) { case 0: VertexShader = SetShader<0, 0>(Context, PaniniParams::Default); break; case 1: VertexShader = SetShader<1, 0>(Context, PaniniParams::Default); break; case 2: VertexShader = SetShader<2, 0>(Context, PaniniParams::Default); break; case 3: VertexShader = SetShader<3, 0>(Context, PaniniParams::Default); break; default: checkNoEntry(); break; } } // Draw a quad, a triangle or a tessellated quad DrawRectangle( Context.RHICmdList, 0, 0, DestRect.Width(), DestRect.Height(), SrcRect.Min.X, SrcRect.Min.Y, SrcRect.Width(), SrcRect.Height(), DestRect.Size(), SrcSize, VertexShader, bTessellatedQuad ? EDRF_UseTesselatedIndexBuffer: EDRF_UseTriangleOptimization); Context.RHICmdList.CopyToResolveTarget(DestRenderTarget.TargetableTexture, DestRenderTarget.ShaderResourceTexture, false, FResolveParams()); }
void FRCPassPostProcessSubsurfaceRecombine::Process(FRenderingCompositePassContext& Context) { FSceneRenderTargets& SceneContext = FSceneRenderTargets::Get(Context.RHICmdList); const FPooledRenderTargetDesc* InputDesc = GetInputDesc(ePId_Input0); check(InputDesc); const FSceneView& View = Context.View; const FSceneViewFamily& ViewFamily = *(View.Family); FIntPoint SrcSize = InputDesc->Extent; FIntPoint DestSize = SceneContext.GetBufferSizeXY(); check(DestSize.X); check(DestSize.Y); check(SrcSize.X); check(SrcSize.Y); FIntRect SrcRect = FIntRect(0, 0, InputDesc->Extent.X, InputDesc->Extent.Y); FIntRect DestRect = View.ViewRect; TRefCountPtr<IPooledRenderTarget>& SceneColor = SceneContext.GetSceneColor(); const FSceneRenderTargetItem& DestRenderTarget = SceneColor->GetRenderTargetItem(); // 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<CW_RGBA,BO_Add,BF_SourceAlpha,BF_InverseSourceAlpha,BO_Add,BF_SourceAlpha,BF_InverseSourceAlpha>::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("SubsurfacePassRecombine#%d"), (int32)bDoSpecularCorrection); if(bDoSpecularCorrection) { SetSubsurfaceRecombineShader<1>(Context, VertexShader); } else { SetSubsurfaceRecombineShader<0>(Context, VertexShader); } 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 FogWorker::Update(float time) { // Debug stuff static const FName TraceTag(TEXT("FOWTrace")); const UWorld* world = Manager.GetWorld(); if(!world) { return; } UpdateRenderOrigin(); FVector origin, SurfaceExtent; Manager.GetActorBounds(false, origin, SurfaceExtent); if(FMath::IsNearlyZero(SurfaceExtent.Size2D())) { return; } ForgetOldLocations(time); // Cache observers location TArray<FVector> observers; observers.Reserve(Manager.Observers.Num()); for(const auto& o : Manager.Observers) { if(o->IsValidLowLevel()) { observers.Add(o->GetActorLocation()); } } // iterate through observers to unveil fog for(auto& observerLocation : observers) { FVector2D observerTexLoc(observerLocation - Manager.CameraPosition); TArray<FVector2D> sightShape; observerTexLoc /= FVector2D(SurfaceExtent); observerTexLoc *= TextureSize / 2.0f; observerTexLoc += FVector2D(TextureSize / 2.0f, TextureSize / 2.0f); FCollisionQueryParams queryParams(TraceTag, true); for(float i = 0; i < 2 * PI; i += HALF_PI / 100.0f) { auto x = Manager.SightRange * FMath::Cos(i); auto y = Manager.SightRange * FMath::Sin(i); FVector sightLoc = observerLocation + FVector(x, y, 0); FHitResult hit; if(world->LineTraceSingleByChannel(hit, observerLocation, sightLoc, ECC_GameTraceChannel2, queryParams)) { sightLoc = hit.Location; } FVector2D hitTexLoc; if(FSceneView::ProjectWorldToScreen(sightLoc, FIntRect(0, 0, 1024, 768), FMatrix::Identity, hitTexLoc)) { // hitTexLoc = FVector2D(sightLoc - Manager.CameraPosition); hitTexLoc /= FVector2D(SurfaceExtent); hitTexLoc *= TextureSize / 2.0f; hitTexLoc += FVector2D(TextureSize / 2.0f, TextureSize / 2.0f); sightShape.AddUnique(hitTexLoc); } } // draw a unveil shape DrawUnveilShape(observerTexLoc, sightShape); // flood fill area // FloodFill(observerTexLoc.X, observerTexLoc.Y); } UpdateTextureData(); }
void FSlateOpenGLTexture::UpdateTexture(const TArray<uint8>& Bytes) { UpdateTextureRaw(Bytes.GetData(), FIntRect()); }
void FRCPassPostProcessSelectionOutlineColor::Process(FRenderingCompositePassContext& Context) { #if WITH_EDITOR SCOPED_DRAW_EVENT(Context.RHICmdList, PostProcessSelectionOutlineBuffer); const FPooledRenderTargetDesc* SceneColorInputDesc = GetInputDesc(ePId_Input0); if(!SceneColorInputDesc) { // input is not hooked up correctly return; } const FViewInfo& View = Context.View; FIntRect ViewRect = View.ViewRect; FIntPoint SrcSize = SceneColorInputDesc->Extent; // Get the output render target const FSceneRenderTargetItem& DestRenderTarget = PassOutputs[0].RequestSurface(Context); // Set the render target/viewport. SetRenderTarget(Context.RHICmdList, FTextureRHIParamRef(), DestRenderTarget.TargetableTexture); // This is a reversed Z depth surface, so 0.0f is the far plane. Context.RHICmdList.Clear(false, FLinearColor(0, 0, 0, 0), true, (float)ERHIZBuffer::FarPlane, true, 0, FIntRect()); Context.SetViewportAndCallRHI(ViewRect); if (View.Family->EngineShowFlags.Selection) { FHitProxyDrawingPolicyFactory::ContextType FactoryContext; Context.RHICmdList.SetRasterizerState(TStaticRasterizerState<>::GetRHI()); Context.RHICmdList.SetBlendState(TStaticBlendStateWriteMask<CW_NONE, CW_NONE, CW_NONE, CW_NONE>::GetRHI()); // Note that the stencil value will overflow with enough selected objects FEditorSelectionDrawingPolicy::ResetStencilValues(); // Run selection pass on static elements FScene* Scene = View.Family->Scene->GetRenderScene(); if(Scene) { Scene->EditorSelectionDrawList.DrawVisible(Context.RHICmdList, View, View.StaticMeshEditorSelectionMap, View.StaticMeshBatchVisibility); } for (int32 MeshBatchIndex = 0; MeshBatchIndex < View.DynamicMeshElements.Num(); MeshBatchIndex++) { const FMeshBatchAndRelevance& MeshBatchAndRelevance = View.DynamicMeshElements[MeshBatchIndex]; const FPrimitiveSceneProxy* PrimitiveSceneProxy = MeshBatchAndRelevance.PrimitiveSceneProxy; // Selected actors should be subdued if any component is individually selected bool bActorSelectionColorIsSubdued = View.bHasSelectedComponents; if (PrimitiveSceneProxy->IsSelected() && MeshBatchAndRelevance.Mesh->bUseSelectionOutline && PrimitiveSceneProxy->WantsSelectionOutline()) { int32 StencilValue = 1; if(PrimitiveSceneProxy->GetOwnerName() != NAME_BSP) { StencilValue = FEditorSelectionDrawingPolicy::GetStencilValue(View, PrimitiveSceneProxy); } // Note that the stencil value will overflow with enough selected objects Context.RHICmdList.SetDepthStencilState(TStaticDepthStencilState<true, CF_DepthNearOrEqual, true, CF_Always, SO_Keep, SO_Keep, SO_Replace>::GetRHI(), StencilValue); const FMeshBatch& MeshBatch = *MeshBatchAndRelevance.Mesh; FHitProxyDrawingPolicyFactory::DrawDynamicMesh(Context.RHICmdList, View, FactoryContext, MeshBatch, false, true, MeshBatchAndRelevance.PrimitiveSceneProxy, MeshBatch.BatchHitProxyId); } } // to get an outline around the objects if it's partly outside of the screen { FIntRect InnerRect = ViewRect; // 1 as we have an outline that is that thick InnerRect.InflateRect(-1); // We could use Clear with InnerRect but this is just an optimization - on some hardware it might do a full clear (and we cannot disable yet) // RHICmdList.Clear(false, FLinearColor(0, 0, 0, 0), true, 0.0f, true, 0, InnerRect); // so we to 4 clears - one for each border. // top Context.RHICmdList.SetScissorRect(true, ViewRect.Min.X, ViewRect.Min.Y, ViewRect.Max.X, InnerRect.Min.Y); Context.RHICmdList.Clear(false, FLinearColor(0, 0, 0, 0), true, (float)ERHIZBuffer::FarPlane, true, 0, FIntRect()); // bottom Context.RHICmdList.SetScissorRect(true, ViewRect.Min.X, InnerRect.Max.Y, ViewRect.Max.X, ViewRect.Max.Y); Context.RHICmdList.Clear(false, FLinearColor(0, 0, 0, 0), true, (float)ERHIZBuffer::FarPlane, true, 0, FIntRect()); // left Context.RHICmdList.SetScissorRect(true, ViewRect.Min.X, ViewRect.Min.Y, InnerRect.Min.X, ViewRect.Max.Y); Context.RHICmdList.Clear(false, FLinearColor(0, 0, 0, 0), true, (float)ERHIZBuffer::FarPlane, true, 0, FIntRect()); // right Context.RHICmdList.SetScissorRect(true, InnerRect.Max.X, ViewRect.Min.Y, ViewRect.Max.X, ViewRect.Max.Y); Context.RHICmdList.Clear(false, FLinearColor(0, 0, 0, 0), true, (float)ERHIZBuffer::FarPlane, true, 0, FIntRect()); Context.RHICmdList.SetScissorRect(false, 0, 0, 0, 0); } } // Resolve to the output Context.RHICmdList.CopyToResolveTarget(DestRenderTarget.TargetableTexture, DestRenderTarget.ShaderResourceTexture, false, FResolveParams()); #endif }
void RenderLandscapeMaterialForLightmass(const FLandscapeStaticLightingMesh* LandscapeMesh, FMaterialRenderProxy* MaterialProxy, const FRenderTarget* RenderTarget) { const ULandscapeComponent* LandscapeComponent = CastChecked<ULandscapeComponent>(LandscapeMesh->Component); const int32 SubsectionSizeQuads = LandscapeComponent->SubsectionSizeQuads; const int32 NumSubsections = LandscapeComponent->NumSubsections; const int32 ComponentSizeQuads = LandscapeComponent->ComponentSizeQuads; int32 PatchExpandCountX = 0; int32 PatchExpandCountY = 0; int32 DesiredSize = 1; const float LightMapOffset = 0.0f; const float LightMapRes = LandscapeComponent->StaticLightingResolution > 0.f ? LandscapeComponent->StaticLightingResolution : LandscapeComponent->GetLandscapeProxy()->StaticLightingResolution; const int32 LightingLOD = LandscapeComponent->GetLandscapeProxy()->StaticLightingLOD; const float LightMapRatio = ::GetTerrainExpandPatchCount(LightMapRes, PatchExpandCountX, PatchExpandCountY, ComponentSizeQuads, (NumSubsections * (SubsectionSizeQuads + 1)), DesiredSize, LightingLOD); const FVector2D PatchExpandOffset = FVector2D((float)PatchExpandCountX / (ComponentSizeQuads + 2 * PatchExpandCountX), (float)PatchExpandCountY / (ComponentSizeQuads + 2 * PatchExpandCountY)) * FVector2D(RenderTarget->GetSizeXY()); const FVector2D PatchExpandScale = FVector2D((float)ComponentSizeQuads / (ComponentSizeQuads + 2 * PatchExpandCountX), (float)ComponentSizeQuads / (ComponentSizeQuads + 2 * PatchExpandCountY)); TArray<FLightmassLandscapeVertex> Vertices; TArray<uint16> Indices; Vertices.Reserve(FMath::Square(NumSubsections) * 4); Indices.Reserve(FMath::Square(NumSubsections) * 6); const float fraction = 1.0f / NumSubsections; const FVector2D PositionScale = FVector2D(RenderTarget->GetSizeXY()) * fraction * PatchExpandScale; const float LayerScale = SubsectionSizeQuads; const float WeightmapSubsection = LandscapeComponent->WeightmapSubsectionOffset; const FVector2D WeightmapBias = FVector2D(LandscapeComponent->WeightmapScaleBias.Z, LandscapeComponent->WeightmapScaleBias.W); const FVector2D WeightmapScale = FVector2D(LandscapeComponent->WeightmapScaleBias.X, LandscapeComponent->WeightmapScaleBias.Y) * SubsectionSizeQuads; const int32 SubsectionX_Start = PatchExpandCountX > 0 ? -1 : 0; const int32 SubsectionX_End = NumSubsections + (PatchExpandCountX > 0 ? 1 : 0); const int32 SubsectionY_Start = PatchExpandCountY > 0 ? -1 : 0; const int32 SubsectionY_End = NumSubsections + (PatchExpandCountY > 0 ? 1 : 0); for (int32 SubsectionY = SubsectionY_Start; SubsectionY < SubsectionY_End; ++SubsectionY) { for (int32 SubsectionX = SubsectionX_Start; SubsectionX < SubsectionX_End; ++SubsectionX) { const FIntPoint UVSubsection = FIntPoint((SubsectionX >= 0 ? SubsectionX : 0), (SubsectionY >= 0 ? SubsectionY : 0)); const FVector2D UVScale = FVector2D((SubsectionX >= 0 && SubsectionX < NumSubsections ? 1 : 0), (SubsectionY >= 0 && SubsectionY < NumSubsections ? 1 : 0)); const FVector2D BasePosition = PatchExpandOffset + FVector2D(SubsectionX, SubsectionY) * PositionScale; const FVector2D BaseLayerCoords = FVector2D(UVSubsection) * LayerScale; const FVector2D BaseWeightmapCoords = WeightmapBias + FVector2D(UVSubsection) * WeightmapSubsection; int32 Index = Vertices.Add(FLightmassLandscapeVertex(FVector(BasePosition /*FVector2D(0, 0) * PositionScale*/, 0), FVector(BaseLayerCoords /*FVector2D(0, 0) * UVScale * LayerScale*/, 0), BaseWeightmapCoords /*FVector2D(0, 0) * UVScale * WeightmapScale*/)); verifySlow( Vertices.Add(FLightmassLandscapeVertex(FVector(BasePosition + FVector2D(1, 0) * PositionScale, 0), FVector(BaseLayerCoords + FVector2D(1, 0) * UVScale * LayerScale, 0), BaseWeightmapCoords + FVector2D(1, 0) * UVScale * WeightmapScale )) == Index + 1); verifySlow( Vertices.Add(FLightmassLandscapeVertex(FVector(BasePosition + FVector2D(0, 1) * PositionScale, 0), FVector(BaseLayerCoords + FVector2D(0, 1) * UVScale * LayerScale, 0), BaseWeightmapCoords + FVector2D(0, 1) * UVScale * WeightmapScale )) == Index + 2); verifySlow( Vertices.Add(FLightmassLandscapeVertex(FVector(BasePosition + FVector2D(1, 1) * PositionScale, 0), FVector(BaseLayerCoords + FVector2D(1, 1) * UVScale * LayerScale, 0), BaseWeightmapCoords + FVector2D(1, 1) * UVScale * WeightmapScale )) == Index + 3); checkSlow(Index + 3 <= MAX_uint16); Indices.Add(Index); Indices.Add(Index + 3); Indices.Add(Index + 1); Indices.Add(Index); Indices.Add(Index + 2); Indices.Add(Index + 3); } } FMeshBatch MeshElement; MeshElement.DynamicVertexStride = sizeof(FLightmassLandscapeVertex); MeshElement.UseDynamicData = true; MeshElement.bDisableBackfaceCulling = true; MeshElement.CastShadow = false; MeshElement.bWireframe = false; MeshElement.Type = PT_TriangleList; MeshElement.DepthPriorityGroup = SDPG_Foreground; MeshElement.bUseAsOccluder = false; MeshElement.bSelectable = false; MeshElement.DynamicVertexData = Vertices.GetData(); MeshElement.VertexFactory = &LightmassLandscapeVertexFactory; MeshElement.MaterialRenderProxy = MaterialProxy; FMeshBatchElement& BatchElement = MeshElement.Elements[0]; BatchElement.PrimitiveUniformBufferResource = &LightmassLandscapeUniformBuffer; BatchElement.DynamicIndexData = Indices.GetData(); BatchElement.FirstIndex = 0; BatchElement.NumPrimitives = Indices.Num() / 3; BatchElement.MinVertexIndex = 0; BatchElement.MaxVertexIndex = Vertices.Num() - 1; BatchElement.DynamicIndexStride = sizeof(uint16); FSceneViewFamily ViewFamily(FSceneViewFamily::ConstructionValues( RenderTarget, NULL, FEngineShowFlags(ESFIM_Game)) .SetWorldTimes(0, 0, 0) .SetGammaCorrection(RenderTarget->GetDisplayGamma())); const FIntRect ViewRect(FIntPoint(0, 0), RenderTarget->GetSizeXY()); // make a temporary view FSceneViewInitOptions ViewInitOptions; ViewInitOptions.ViewFamily = &ViewFamily; ViewInitOptions.SetViewRectangle(ViewRect); ViewInitOptions.ViewOrigin = FVector::ZeroVector; ViewInitOptions.ViewRotationMatrix = FMatrix::Identity; ViewInitOptions.ProjectionMatrix = FCanvas::CalcBaseTransform2D(RenderTarget->GetSizeXY().X, RenderTarget->GetSizeXY().Y); ViewInitOptions.BackgroundColor = FLinearColor::Black; ViewInitOptions.OverlayColor = FLinearColor::White; FSceneView View(ViewInitOptions); ENQUEUE_UNIQUE_RENDER_COMMAND_ONEPARAMETER( CanvasFlushSetupCommand, const FRenderTarget*, RenderTarget, RenderTarget, { //SCOPED_DRAW_EVENT(RHICmdList, CanvasFlush); // Set the RHI render target. ::SetRenderTarget(RHICmdList, RenderTarget->GetRenderTargetTexture(), FTextureRHIRef()); // disable depth test & writes RHICmdList.SetDepthStencilState(TStaticDepthStencilState<false,CF_Always>::GetRHI()); const FIntRect RTViewRect = FIntRect(0, 0, RenderTarget->GetRenderTargetTexture()->GetSizeX(), RenderTarget->GetRenderTargetTexture()->GetSizeY()); // set viewport to RT size RHICmdList.SetViewport(RTViewRect.Min.X, RTViewRect.Min.Y, 0.0f, RTViewRect.Max.X, RTViewRect.Max.Y, 1.0f); });
void FRCPassPostProcessSelectionOutlineColor::Process(FRenderingCompositePassContext& Context) { SCOPED_DRAW_EVENT(Context.RHICmdList, PostProcessSelectionOutlineBuffer, DEC_SCENE_ITEMS); const FPooledRenderTargetDesc* SceneColorInputDesc = GetInputDesc(ePId_Input0); if(!SceneColorInputDesc) { // input is not hooked up correctly return; } const FViewInfo& View = Context.View; FIntRect ViewRect = View.ViewRect; FIntPoint SrcSize = SceneColorInputDesc->Extent; // Get the output render target const FSceneRenderTargetItem& DestRenderTarget = PassOutputs[0].RequestSurface(Context); // Set the render target/viewport. SetRenderTarget(Context.RHICmdList, FTextureRHIParamRef(), DestRenderTarget.TargetableTexture); // This is a reversed Z depth surface, so 0.0f is the far plane. Context.RHICmdList.Clear(false, FLinearColor(0, 0, 0, 0), true, 0.0f, true, 0, FIntRect()); Context.SetViewportAndCallRHI(ViewRect); if (View.Family->EngineShowFlags.Selection) { const bool bUseGetMeshElements = ShouldUseGetDynamicMeshElements(); if (bUseGetMeshElements) { FHitProxyDrawingPolicyFactory::ContextType FactoryContext; //@todo - use memstack TMap<FName, int32> ActorNameToStencilIndex; ActorNameToStencilIndex.Add(NAME_BSP, 1); Context.RHICmdList.SetRasterizerState(TStaticRasterizerState<>::GetRHI()); Context.RHICmdList.SetBlendState(TStaticBlendStateWriteMask<CW_NONE, CW_NONE, CW_NONE, CW_NONE>::GetRHI()); for (int32 MeshBatchIndex = 0; MeshBatchIndex < View.DynamicMeshElements.Num(); MeshBatchIndex++) { const FMeshBatchAndRelevance& MeshBatchAndRelevance = View.DynamicMeshElements[MeshBatchIndex]; const FPrimitiveSceneProxy* PrimitiveSceneProxy = MeshBatchAndRelevance.PrimitiveSceneProxy; if (PrimitiveSceneProxy->IsSelected() && MeshBatchAndRelevance.Mesh->bUseSelectionOutline) { const int32* AssignedStencilIndexPtr = ActorNameToStencilIndex.Find(PrimitiveSceneProxy->GetOwnerName()); if (!AssignedStencilIndexPtr) { AssignedStencilIndexPtr = &ActorNameToStencilIndex.Add(PrimitiveSceneProxy->GetOwnerName(), ActorNameToStencilIndex.Num() + 1); } // This is a reversed Z depth surface, using CF_GreaterEqual. // Note that the stencil value will overflow with enough selected objects Context.RHICmdList.SetDepthStencilState(TStaticDepthStencilState<true, CF_GreaterEqual, true, CF_Always, SO_Keep, SO_Keep, SO_Replace>::GetRHI(), *AssignedStencilIndexPtr); const FMeshBatch& MeshBatch = *MeshBatchAndRelevance.Mesh; FHitProxyDrawingPolicyFactory::DrawDynamicMesh(Context.RHICmdList, View, FactoryContext, MeshBatch, false, true, MeshBatchAndRelevance.PrimitiveSceneProxy, MeshBatch.BatchHitProxyId); } } } else if (View.VisibleDynamicPrimitives.Num() > 0) { TDynamicPrimitiveDrawer<FHitProxyDrawingPolicyFactory> Drawer(Context.RHICmdList, &View, FHitProxyDrawingPolicyFactory::ContextType(), true, false, false, true); TMultiMap<FName, const FPrimitiveSceneInfo*> PrimitivesByActor; for (int32 PrimitiveIndex = 0; PrimitiveIndex < View.VisibleDynamicPrimitives.Num();PrimitiveIndex++) { const FPrimitiveSceneInfo* PrimitiveSceneInfo = View.VisibleDynamicPrimitives[PrimitiveIndex]; // Only draw the primitive if relevant if(PrimitiveSceneInfo->Proxy->IsSelected()) { PrimitivesByActor.Add(PrimitiveSceneInfo->Proxy->GetOwnerName(), PrimitiveSceneInfo); } } if (PrimitivesByActor.Num()) { // 0 means no object, 1 means BSP so we start with 2 uint32 StencilValue = 2; Context.RHICmdList.SetRasterizerState(TStaticRasterizerState<>::GetRHI()); Context.RHICmdList.SetBlendState(TStaticBlendStateWriteMask<CW_NONE, CW_NONE, CW_NONE, CW_NONE>::GetRHI()); // Sort by actor TArray<FName> Actors; PrimitivesByActor.GetKeys(Actors); for( TArray<FName>::TConstIterator ActorIt(Actors); ActorIt; ++ActorIt ) { bool bBSP = *ActorIt == NAME_BSP; if (bBSP) { // This is a reversed Z depth surface, using CF_GreaterEqual. Context.RHICmdList.SetDepthStencilState(TStaticDepthStencilState<true, CF_GreaterEqual, true, CF_Always, SO_Keep, SO_Keep, SO_Replace>::GetRHI(), 1); } else { // This is a reversed Z depth surface, using CF_GreaterEqual. Context.RHICmdList.SetDepthStencilState(TStaticDepthStencilState<true, CF_GreaterEqual, true, CF_Always, SO_Keep, SO_Keep, SO_Replace>::GetRHI(), StencilValue); // we want to use 1..255 for all objects, not correct silhouettes after that is acceptable StencilValue = (StencilValue == 255) ? 2 : (StencilValue + 1); } TArray<const FPrimitiveSceneInfo*> Primitives; PrimitivesByActor.MultiFind(*ActorIt, Primitives); for( TArray<const FPrimitiveSceneInfo*>::TConstIterator PrimIt(Primitives); PrimIt; ++PrimIt ) { const FPrimitiveSceneInfo* PrimitiveSceneInfo = *PrimIt; // Render the object to the stencil/depth buffer Drawer.SetPrimitive(PrimitiveSceneInfo->Proxy); PrimitiveSceneInfo->Proxy->DrawDynamicElements(&Drawer, &View); } } } } // to get an outline around the objects if it's partly outside of the screen { FIntRect InnerRect = ViewRect; // 1 as we have an outline that is that thick InnerRect.InflateRect(-1); // We could use Clear with InnerRect but this is just an optimization - on some hardware it might do a full clear (and we cannot disable yet) // RHICmdList.Clear(false, FLinearColor(0, 0, 0, 0), true, 0.0f, true, 0, InnerRect); // so we to 4 clears - one for each border. // top Context.RHICmdList.SetScissorRect(true, ViewRect.Min.X, ViewRect.Min.Y, ViewRect.Max.X, InnerRect.Min.Y); Context.RHICmdList.Clear(false, FLinearColor(0, 0, 0, 0), true, 0.0f, true, 0, FIntRect()); // bottom Context.RHICmdList.SetScissorRect(true, ViewRect.Min.X, InnerRect.Max.Y, ViewRect.Max.X, ViewRect.Max.Y); Context.RHICmdList.Clear(false, FLinearColor(0, 0, 0, 0), true, 0.0f, true, 0, FIntRect()); // left Context.RHICmdList.SetScissorRect(true, ViewRect.Min.X, ViewRect.Min.Y, InnerRect.Min.X, ViewRect.Max.Y); Context.RHICmdList.Clear(false, FLinearColor(0, 0, 0, 0), true, 0.0f, true, 0, FIntRect()); // right Context.RHICmdList.SetScissorRect(true, InnerRect.Max.X, ViewRect.Min.Y, ViewRect.Max.X, ViewRect.Max.Y); Context.RHICmdList.Clear(false, FLinearColor(0, 0, 0, 0), true, 0.0f, true, 0, FIntRect()); Context.RHICmdList.SetScissorRect(false, 0, 0, 0, 0); } } // Resolve to the output Context.RHICmdList.CopyToResolveTarget(DestRenderTarget.TargetableTexture, DestRenderTarget.ShaderResourceTexture, false, FResolveParams()); }
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 FRCPassPostProcessSubsurfaceSetup::Process(FRenderingCompositePassContext& Context) { SCOPED_DRAW_EVENT(Context.RHICmdList, SubsurfaceSetup); const FPooledRenderTargetDesc* InputDesc = GetInputDesc(ePId_Input0); if(!InputDesc) { // input is not hooked up correctly return; } const FSceneView& View = Context.View; const FSceneViewFamily& ViewFamily = *(View.Family); FIntPoint SrcSize = InputDesc->Extent; FIntPoint DestSize = PassOutputs[0].RenderTargetDesc.Extent; FIntRect DestRect = FIntRect(0, 0, DestSize.X, DestSize.Y); // upscale rectangle to not slightly scale (might miss a pixel) FIntRect SrcRect = DestRect * 2 + View.ViewRect.Min; 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 ); // set the state Context.RHICmdList.SetBlendState(TStaticBlendState<>::GetRHI()); Context.RHICmdList.SetRasterizerState(TStaticRasterizerState<>::GetRHI()); Context.RHICmdList.SetDepthStencilState(TStaticDepthStencilState<false, CF_Always>::GetRHI()); // reconstruct specular and add it in final pass bool bSpecularCorrection = DoSpecularCorrection(); if(bSpecularCorrection) { SetSubsurfaceSetupShader<1>(Context); } else { SetSubsurfaceSetupShader<0>(Context); } // Draw a quad mapping scene color to the view's render target TShaderMapRef<FPostProcessVS> VertexShader(Context.GetShaderMap()); 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 FRCPassPostProcessScreenSpaceReflections::Process(FRenderingCompositePassContext& Context) { SCOPED_DRAW_EVENT(Context.RHICmdList, ScreenSpaceReflections); const FSceneView& View = Context.View; const auto FeatureLevel = Context.GetFeatureLevel(); const FSceneRenderTargetItem& DestRenderTarget = PassOutputs[0].RequestSurface(Context); // Set the view family's render target/viewport. SetRenderTarget(Context.RHICmdList, DestRenderTarget.TargetableTexture, FTextureRHIRef()); Context.RHICmdList.Clear(true, FLinearColor(0, 0, 0, 0), false, 1.0f, false, 0, FIntRect()); Context.SetViewportAndCallRHI(View.ViewRect); // set the state Context.RHICmdList.SetBlendState(TStaticBlendState<>::GetRHI()); Context.RHICmdList.SetRasterizerState(TStaticRasterizerState<>::GetRHI()); Context.RHICmdList.SetDepthStencilState(TStaticDepthStencilState<false, CF_Always>::GetRHI()); int SSRQuality = ComputeSSRQuality(View.FinalPostProcessSettings.ScreenSpaceReflectionQuality); SSRQuality = FMath::Clamp(SSRQuality, 1, 4); uint32 iPreFrame = bPrevFrame ? 1 : 0; if (View.Family->EngineShowFlags.VisualizeSSR) { iPreFrame = 0; SSRQuality = 0; } TShaderMapRef< FPostProcessVS > VertexShader(Context.GetShaderMap()); #define CASE(A, B) \ case (A + 2 * (B + 3 * 0 )): \ { \ TShaderMapRef< FPostProcessScreenSpaceReflectionsPS<A, B> > PixelShader(Context.GetShaderMap()); \ static FGlobalBoundShaderState BoundShaderState; \ SetGlobalBoundShaderState(Context.RHICmdList, FeatureLevel, BoundShaderState, GFilterVertexDeclaration.VertexDeclarationRHI, *VertexShader, *PixelShader); \ VertexShader->SetParameters(Context); \ PixelShader->SetParameters(Context); \ }; \ break switch (iPreFrame + 2 * (SSRQuality + 3 * 0)) { CASE(0,0); CASE(0,1); CASE(1,1); CASE(0,2); CASE(1,2); CASE(0,3); CASE(1,3); CASE(0,4); CASE(1,4); default: check(!"Missing case in FRCPassPostProcessScreenSpaceReflections"); } #undef CASE // Draw a quad mapping scene color to the view's render target DrawRectangle( Context.RHICmdList, 0, 0, View.ViewRect.Width(), View.ViewRect.Height(), View.ViewRect.Min.X, View.ViewRect.Min.Y, View.ViewRect.Width(), View.ViewRect.Height(), View.ViewRect.Size(), GSceneRenderTargets.GetBufferSizeXY(), *VertexShader, EDRF_UseTriangleOptimization); Context.RHICmdList.CopyToResolveTarget(DestRenderTarget.TargetableTexture, DestRenderTarget.ShaderResourceTexture, false, FResolveParams()); }
/** * Transfers a list of curves to a texture on the GPU. All main memory allocated * for curve samples is released. * @param CurveTextureRHI - The * @param CurveTextureTargetRHI - The render target for the curve texture. * @param InPendingCurves - Curves to be stored on the GPU. */ static void InjectCurves( FRHICommandListImmediate& RHICmdList, FTexture2DRHIParamRef CurveTextureRHI, FTexture2DRHIParamRef CurveTextureTargetRHI, TArray<FCurveSamples>& InPendingCurves ) { static bool bFirstCall = true; check( IsInRenderingThread() ); SCOPED_DRAW_EVENT(RHICmdList, InjectParticleCurves); FVertexBufferRHIParamRef ScratchVertexBufferRHI = GParticleScratchVertexBuffer.VertexBufferRHI; SetRenderTarget(RHICmdList, CurveTextureTargetRHI, FTextureRHIParamRef()); RHICmdList.SetScissorRect(false, 0, 0, 0, 0); RHICmdList.SetViewport(0, 0, 0.0f, GParticleCurveTextureSizeX, GParticleCurveTextureSizeY, 1.0f); RHICmdList.SetDepthStencilState(TStaticDepthStencilState<false, CF_Always>::GetRHI()); RHICmdList.SetRasterizerState(TStaticRasterizerState<FM_Solid, CM_None>::GetRHI()); RHICmdList.SetBlendState(TStaticBlendState<>::GetRHI()); if (bFirstCall) { RHICmdList.Clear(true, FLinearColor::Blue, false, 0.0f, false, 0, FIntRect()); bFirstCall = false; } int32 PendingCurveCount = InPendingCurves.Num(); for ( int32 CurveIndex = 0; CurveIndex < PendingCurveCount; ++CurveIndex ) { FCurveSamples& Curve = InPendingCurves[CurveIndex]; check( Curve.Samples ); // Copy curve samples in to the scratch vertex buffer. const int32 SampleCount = Curve.TexelAllocation.Size; const int32 SampleByteCount = SampleCount * sizeof(FColor); FColor* RESTRICT DestSamples = (FColor*)RHILockVertexBuffer( ScratchVertexBufferRHI, 0, SampleByteCount, RLM_WriteOnly ); FMemory::Memcpy( DestSamples, Curve.Samples, SampleByteCount ); RHICmdList.UnlockVertexBuffer(ScratchVertexBufferRHI); FMemory::Free( Curve.Samples ); Curve.Samples = NULL; // Compute the offset in to the texture. FVector2D CurveOffset( (float)Curve.TexelAllocation.X / GParticleCurveTextureSizeX, (float)Curve.TexelAllocation.Y / GParticleCurveTextureSizeY ); // Grab shaders. TShaderMapRef<FParticleCurveInjectionVS> VertexShader(GetGlobalShaderMap(GMaxRHIFeatureLevel)); TShaderMapRef<FParticleCurveInjectionPS> PixelShader(GetGlobalShaderMap(GMaxRHIFeatureLevel)); // Bound shader state. static FGlobalBoundShaderState BoundShaderState; SetGlobalBoundShaderState( RHICmdList, GMaxRHIFeatureLevel, BoundShaderState, GParticleCurveInjectionVertexDeclaration.VertexDeclarationRHI, *VertexShader, *PixelShader, 0 ); VertexShader->SetParameters(RHICmdList, CurveOffset ); // Stream 0: New particles. RHICmdList.SetStreamSource( 0, ScratchVertexBufferRHI, /*Stride=*/ sizeof(FColor), /*Offset=*/ 0 ); // Stream 1: TexCoord. RHICmdList.SetStreamSource( 1, GParticleTexCoordVertexBuffer.VertexBufferRHI, /*Stride=*/ sizeof(FVector2D), /*Offset=*/ 0 ); // Inject particles. RHICmdList.DrawIndexedPrimitive( GParticleIndexBuffer.IndexBufferRHI, PT_TriangleList, /*BaseVertexIndex=*/ 0, /*MinIndex=*/ 0, /*NumVertices=*/ 4, /*StartIndex=*/ 0, /*NumPrimitives=*/ 2, /*NumInstances=*/ SampleCount ); } RHICmdList.CopyToResolveTarget(CurveTextureTargetRHI, CurveTextureRHI, /*bKeepOriginalSurface=*/ false, FResolveParams()); }
void FSteamVRHMD::RenderTexture_RenderThread(FRHICommandListImmediate& RHICmdList, FTexture2DRHIParamRef BackBuffer, FTexture2DRHIParamRef SrcTexture) const { check(IsInRenderingThread()); UpdateLayerTextures(); if (bSplashIsShown) { SetRenderTarget(RHICmdList, SrcTexture, FTextureRHIRef()); RHICmdList.Clear(true, FLinearColor(0, 0, 0, 0), false, (float)ERHIZBuffer::FarPlane, false, 0, FIntRect()); } if (WindowMirrorMode != 0) { const uint32 ViewportWidth = BackBuffer->GetSizeX(); const uint32 ViewportHeight = BackBuffer->GetSizeY(); SetRenderTarget(RHICmdList, BackBuffer, FTextureRHIRef()); RHICmdList.SetViewport(0, 0, 0, ViewportWidth, ViewportHeight, 1.0f); RHICmdList.SetBlendState(TStaticBlendState<>::GetRHI()); RHICmdList.SetRasterizerState(TStaticRasterizerState<>::GetRHI()); RHICmdList.SetDepthStencilState(TStaticDepthStencilState<false, CF_Always>::GetRHI()); const auto FeatureLevel = GMaxRHIFeatureLevel; auto ShaderMap = GetGlobalShaderMap(FeatureLevel); TShaderMapRef<FScreenVS> VertexShader(ShaderMap); TShaderMapRef<FScreenPS> PixelShader(ShaderMap); static FGlobalBoundShaderState BoundShaderState; SetGlobalBoundShaderState(RHICmdList, FeatureLevel, BoundShaderState, RendererModule->GetFilterVertexDeclaration().VertexDeclarationRHI, *VertexShader, *PixelShader); PixelShader->SetParameters(RHICmdList, TStaticSamplerState<SF_Bilinear>::GetRHI(), SrcTexture); if (WindowMirrorMode == 1) { // need to clear when rendering only one eye since the borders won't be touched by the DrawRect below RHICmdList.Clear(true, FLinearColor::Black, false, 0, false, 0, FIntRect()); RendererModule->DrawRectangle( RHICmdList, ViewportWidth / 4, 0, ViewportWidth / 2, ViewportHeight, 0.1f, 0.2f, 0.3f, 0.6f, FIntPoint(ViewportWidth, ViewportHeight), FIntPoint(1, 1), *VertexShader, EDRF_Default); } else if (WindowMirrorMode == 2) { RendererModule->DrawRectangle( RHICmdList, 0, 0, ViewportWidth, ViewportHeight, 0.0f, 0.0f, 1.0f, 1.0f, FIntPoint(ViewportWidth, ViewportHeight), FIntPoint(1, 1), *VertexShader, EDRF_Default); } } }
void FRCPassPostProcessWeightedSampleSum::Process(FRenderingCompositePassContext& Context) { const FSceneView& View = Context.View; FRenderingCompositeOutput *Input = GetInput(ePId_Input0)->GetOutput(); // input is not hooked up correctly check(Input); const FPooledRenderTargetDesc* InputDesc = GetInputDesc(ePId_Input0); // input is not hooked up correctly check(InputDesc); const FSceneViewFamily& ViewFamily = *(View.Family); FIntPoint SrcSize = InputDesc->Extent; FIntPoint DestSize = PassOutputs[0].RenderTargetDesc.Extent; FSceneRenderTargets& SceneContext = FSceneRenderTargets::Get(Context.RHICmdList); // e.g. 4 means the input texture is 4x smaller than the buffer size FIntPoint SrcScaleFactor = SceneContext.GetBufferSizeXY() / SrcSize; FIntPoint DstScaleFactor = SceneContext.GetBufferSizeXY() / DestSize; TRefCountPtr<IPooledRenderTarget> InputPooledElement = Input->RequestInput(); check(!InputPooledElement->IsFree()); const FSceneRenderTargetItem& DestRenderTarget = PassOutputs[0].RequestSurface(Context); bool bDoFastBlur = DoFastBlur(); FVector2D InvSrcSize(1.0f / SrcSize.X, 1.0f / SrcSize.Y); // we scale by width because FOV is defined horizontally float SrcSizeForThisAxis = View.ViewRect.Width() / (float)SrcScaleFactor.X; if(bDoFastBlur && FilterShape == EFS_Vert) { SrcSizeForThisAxis *= 2.0f; } // in texel (input resolution), /2 as we use the diameter, 100 as we use percent float EffectiveBlurRadius = SizeScale * SrcSizeForThisAxis / 2 / 100.0f; FVector2D BlurOffsets[MAX_FILTER_SAMPLES]; FLinearColor BlurWeights[MAX_FILTER_SAMPLES]; FVector2D OffsetAndWeight[MAX_FILTER_SAMPLES]; const auto FeatureLevel = Context.View.GetFeatureLevel(); // compute 1D filtered samples uint32 MaxNumSamples = GetMaxNumSamples(FeatureLevel); uint32 NumSamples = Compute1DGaussianFilterKernel(FeatureLevel, EffectiveBlurRadius, OffsetAndWeight, MaxNumSamples, FilterShape, CrossCenterWeight); FIntRect DestRect = FIntRect::DivideAndRoundUp(View.ViewRect, DstScaleFactor); SCOPED_DRAW_EVENTF(Context.RHICmdList, PostProcessWeightedSampleSum, TEXT("PostProcessWeightedSampleSum#%d %dx%d in %dx%d"), NumSamples, DestRect.Width(), DestRect.Height(), DestSize.X, DestSize.Y); // compute weights as weighted contributions of the TintValue for(uint32 i = 0; i < NumSamples; ++i) { BlurWeights[i] = TintValue * OffsetAndWeight[i].Y; } SetRenderTarget(Context.RHICmdList, DestRenderTarget.TargetableTexture, FTextureRHIRef(), ESimpleRenderTargetMode::EExistingColorAndDepth); Context.SetViewportAndCallRHI(0, 0, 0.0f, DestSize.X, DestSize.Y, 1.0f); bool bRequiresClear = true; // check if we have to clear the whole surface. // Otherwise perform the clear when the dest rectangle has been computed. if (FeatureLevel == ERHIFeatureLevel::ES2 || FeatureLevel == ERHIFeatureLevel::ES3_1) { Context.RHICmdList.Clear(true, FLinearColor(0, 0, 0, 0), false, 1.0f, false, 0, FIntRect()); bRequiresClear = false; } FIntRect SrcRect = FIntRect::DivideAndRoundUp(View.ViewRect, SrcScaleFactor); if (bRequiresClear) { DrawClear(Context.RHICmdList, FeatureLevel, bDoFastBlur, SrcRect, DestRect, DestSize); } // set the state Context.RHICmdList.SetBlendState(TStaticBlendState<>::GetRHI()); Context.RHICmdList.SetRasterizerState(TStaticRasterizerState<>::GetRHI()); Context.RHICmdList.SetDepthStencilState(TStaticDepthStencilState<false, CF_Always>::GetRHI()); const FTextureRHIRef& FilterTexture = InputPooledElement->GetRenderTargetItem().ShaderResourceTexture; FRenderingCompositeOutputRef* NodeInput1 = GetInput(ePId_Input1); FRenderingCompositeOutput *Input1 = NodeInput1 ? NodeInput1->GetOutput() : 0; uint32 CombineMethodInt = 0; if(CombineMethod == EFCM_MaxMagnitude) { CombineMethodInt = 2; } // can be optimized FTextureRHIRef AdditiveTexture; if(Input1) { TRefCountPtr<IPooledRenderTarget> InputPooledElement1 = Input1->RequestInput(); AdditiveTexture = InputPooledElement1->GetRenderTargetItem().ShaderResourceTexture; check(CombineMethod == EFCM_Weighted); CombineMethodInt = 1; } if (FilterShape == EFS_Horiz) { float YOffset = bDoFastBlur ? (InvSrcSize.Y * 0.5f) : 0.0f; for (uint32 i = 0; i < NumSamples; ++i) { BlurOffsets[i] = FVector2D(InvSrcSize.X * OffsetAndWeight[i].X, YOffset); } } else { float YOffset = bDoFastBlur ? -(InvSrcSize.Y * 0.5f) : 0.0f; for (uint32 i = 0; i < NumSamples; ++i) { BlurOffsets[i] = FVector2D(0, InvSrcSize.Y * OffsetAndWeight[i].X + YOffset); } } FShader* VertexShader = nullptr; SetFilterShaders( Context.RHICmdList, FeatureLevel, TStaticSamplerState<SF_Bilinear,AM_Border,AM_Border,AM_Clamp>::GetRHI(), FilterTexture, AdditiveTexture, CombineMethodInt, BlurOffsets, BlurWeights, NumSamples, &VertexShader ); DrawQuad(Context.RHICmdList, FeatureLevel, bDoFastBlur, SrcRect, DestRect, DestSize, SrcSize, VertexShader); Context.RHICmdList.CopyToResolveTarget(DestRenderTarget.TargetableTexture, DestRenderTarget.ShaderResourceTexture, false, FResolveParams()); }
static void UpdatePlanarReflectionContents_RenderThread( FRHICommandListImmediate& RHICmdList, FSceneRenderer* MainSceneRenderer, FSceneRenderer* SceneRenderer, const FPlanarReflectionSceneProxy* SceneProxy, FRenderTarget* RenderTarget, FTexture* RenderTargetTexture, const FPlane& MirrorPlane, const FName OwnerName, const FResolveParams& ResolveParams, bool bUseSceneColorTexture) { QUICK_SCOPE_CYCLE_COUNTER(STAT_RenderPlanarReflection); FBox PlanarReflectionBounds = SceneProxy->WorldBounds; bool bIsInAnyFrustum = false; for (int32 ViewIndex = 0; ViewIndex < SceneRenderer->Views.Num(); ++ViewIndex) { FViewInfo& View = SceneRenderer->Views[ViewIndex]; if (View.ViewFrustum.IntersectBox(PlanarReflectionBounds.GetCenter(), PlanarReflectionBounds.GetExtent())) { bIsInAnyFrustum = true; break; } } if (bIsInAnyFrustum) { bool bIsVisibleInAnyView = true; for (int32 ViewIndex = 0; ViewIndex < SceneRenderer->Views.Num(); ++ViewIndex) { FViewInfo& View = SceneRenderer->Views[ViewIndex]; FSceneViewState* ViewState = View.ViewState; if (ViewState) { FIndividualOcclusionHistory& OcclusionHistory = ViewState->PlanarReflectionOcclusionHistories.FindOrAdd(SceneProxy->PlanarReflectionId); // +1 to buffered frames because the query is submitted late into the main frame, but read at the beginning of a reflection capture frame const int32 NumBufferedFrames = FOcclusionQueryHelpers::GetNumBufferedFrames() + 1; // +1 to frame counter because we are operating before the main view's InitViews, which is where OcclusionFrameCounter is incremented uint32 OcclusionFrameCounter = ViewState->OcclusionFrameCounter + 1; FRenderQueryRHIRef& PastQuery = OcclusionHistory.GetPastQuery(OcclusionFrameCounter, NumBufferedFrames); if (IsValidRef(PastQuery)) { uint64 NumSamples = 0; QUICK_SCOPE_CYCLE_COUNTER(STAT_PlanarReflectionOcclusionQueryResults); if (RHIGetRenderQueryResult(PastQuery.GetReference(), NumSamples, true)) { bIsVisibleInAnyView = NumSamples > 0; if (bIsVisibleInAnyView) { break; } } } } } if (bIsVisibleInAnyView) { FMemMark MemStackMark(FMemStack::Get()); // update any resources that needed a deferred update FDeferredUpdateResource::UpdateResources(RHICmdList); { #if WANTS_DRAW_MESH_EVENTS FString EventName; OwnerName.ToString(EventName); SCOPED_DRAW_EVENTF(RHICmdList, SceneCapture, TEXT("PlanarReflection %s"), *EventName); #else SCOPED_DRAW_EVENT(RHICmdList, UpdatePlanarReflectionContent_RenderThread); #endif const FRenderTarget* Target = SceneRenderer->ViewFamily.RenderTarget; SetRenderTarget(RHICmdList, Target->GetRenderTargetTexture(), NULL, true); // Note: relying on GBuffer SceneColor alpha being cleared to 1 in the main scene rendering check(GetSceneColorClearAlpha() == 1.0f); RHICmdList.Clear(true, FLinearColor(0, 0, 0, 1), false, (float)ERHIZBuffer::FarPlane, false, 0, FIntRect()); // Reflection view late update if (SceneRenderer->Views.Num() > 1) { const FMirrorMatrix MirrorMatrix(MirrorPlane); for (int32 ViewIndex = 0; ViewIndex < SceneRenderer->Views.Num(); ++ViewIndex) { FViewInfo& ReflectionViewToUpdate = SceneRenderer->Views[ViewIndex]; const FViewInfo& UpdatedParentView = MainSceneRenderer->Views[ViewIndex]; ReflectionViewToUpdate.UpdatePlanarReflectionViewMatrix(UpdatedParentView, MirrorMatrix); } } // Render the scene normally { SCOPED_DRAW_EVENT(RHICmdList, RenderScene); SceneRenderer->Render(RHICmdList); } for (int32 ViewIndex = 0; ViewIndex < SceneRenderer->Views.Num(); ++ViewIndex) { FViewInfo& View = SceneRenderer->Views[ViewIndex]; if (MainSceneRenderer->Scene->GetShadingPath() == EShadingPath::Deferred) { PrefilterPlanarReflection<true>(RHICmdList, View, SceneProxy, Target); } else { PrefilterPlanarReflection<false>(RHICmdList, View, SceneProxy, Target); } } RHICmdList.CopyToResolveTarget(RenderTarget->GetRenderTargetTexture(), RenderTargetTexture->TextureRHI, false, ResolveParams); } FSceneRenderer::WaitForTasksClearSnapshotsAndDeleteSceneRenderer(RHICmdList, SceneRenderer); } } }
void FRCPassPostProcessSelectionOutlineColor::Process(FRenderingCompositePassContext& Context) { SCOPED_DRAW_EVENT(Context.RHICmdList, PostProcessSelectionOutlineBuffer); const FPooledRenderTargetDesc* SceneColorInputDesc = GetInputDesc(ePId_Input0); if(!SceneColorInputDesc) { // input is not hooked up correctly return; } const FViewInfo& View = Context.View; FIntRect ViewRect = View.ViewRect; FIntPoint SrcSize = SceneColorInputDesc->Extent; // Get the output render target const FSceneRenderTargetItem& DestRenderTarget = PassOutputs[0].RequestSurface(Context); // Set the render target/viewport. SetRenderTarget(Context.RHICmdList, FTextureRHIParamRef(), DestRenderTarget.TargetableTexture); // This is a reversed Z depth surface, so 0.0f is the far plane. Context.RHICmdList.Clear(false, FLinearColor(0, 0, 0, 0), true, (float)ERHIZBuffer::FarPlane, true, 0, FIntRect()); Context.SetViewportAndCallRHI(ViewRect); if (View.Family->EngineShowFlags.Selection) { FHitProxyDrawingPolicyFactory::ContextType FactoryContext; //@todo - use memstack TMap<FName, int32> ActorNameToStencilIndex; TMap<const FPrimitiveSceneProxy*, int32> IndividuallySelectedProxies; ActorNameToStencilIndex.Add(NAME_BSP, 1); Context.RHICmdList.SetRasterizerState(TStaticRasterizerState<>::GetRHI()); Context.RHICmdList.SetBlendState(TStaticBlendStateWriteMask<CW_NONE, CW_NONE, CW_NONE, CW_NONE>::GetRHI()); for (int32 MeshBatchIndex = 0; MeshBatchIndex < View.DynamicMeshElements.Num(); MeshBatchIndex++) { const FMeshBatchAndRelevance& MeshBatchAndRelevance = View.DynamicMeshElements[MeshBatchIndex]; const FPrimitiveSceneProxy* PrimitiveSceneProxy = MeshBatchAndRelevance.PrimitiveSceneProxy; #if WITH_EDITOR // Selected actors should be subdued if any component is individually selected bool bActorSelectionColorIsSubdued = View.bHasSelectedComponents; #else bool bActorSelectionColorIsSubdued = false; #endif if (PrimitiveSceneProxy->IsSelected() && MeshBatchAndRelevance.Mesh->bUseSelectionOutline) { const int32* AssignedStencilIndexPtr = PrimitiveSceneProxy->IsIndividuallySelected() ? IndividuallySelectedProxies.Find( PrimitiveSceneProxy ) : ActorNameToStencilIndex.Find(PrimitiveSceneProxy->GetOwnerName()); if (!AssignedStencilIndexPtr) { if( PrimitiveSceneProxy->IsIndividuallySelected() ) { // Any component that is individually selected should have a stencil value of < 128 so that it can have a unique color. We offset the value by 2 because 0 means no selection and 1 is for bsp int32 StencilValue = IndividuallySelectedProxies.Num() % 126 + 2; AssignedStencilIndexPtr = &IndividuallySelectedProxies.Add(PrimitiveSceneProxy, StencilValue); } else { // If we are subduing actor color highlight then use the top level bits to indicate that to the shader. int32 StencilValue = bActorSelectionColorIsSubdued ? ActorNameToStencilIndex.Num() % 128 + 128 : ActorNameToStencilIndex.Num() % 126 + 2; AssignedStencilIndexPtr = &ActorNameToStencilIndex.Add(PrimitiveSceneProxy->GetOwnerName(), StencilValue); } } // Note that the stencil value will overflow with enough selected objects Context.RHICmdList.SetDepthStencilState(TStaticDepthStencilState<true, CF_DepthNearOrEqual, true, CF_Always, SO_Keep, SO_Keep, SO_Replace>::GetRHI(), *AssignedStencilIndexPtr); const FMeshBatch& MeshBatch = *MeshBatchAndRelevance.Mesh; FHitProxyDrawingPolicyFactory::DrawDynamicMesh(Context.RHICmdList, View, FactoryContext, MeshBatch, false, true, MeshBatchAndRelevance.PrimitiveSceneProxy, MeshBatch.BatchHitProxyId); } } // to get an outline around the objects if it's partly outside of the screen { FIntRect InnerRect = ViewRect; // 1 as we have an outline that is that thick InnerRect.InflateRect(-1); // We could use Clear with InnerRect but this is just an optimization - on some hardware it might do a full clear (and we cannot disable yet) // RHICmdList.Clear(false, FLinearColor(0, 0, 0, 0), true, 0.0f, true, 0, InnerRect); // so we to 4 clears - one for each border. // top Context.RHICmdList.SetScissorRect(true, ViewRect.Min.X, ViewRect.Min.Y, ViewRect.Max.X, InnerRect.Min.Y); Context.RHICmdList.Clear(false, FLinearColor(0, 0, 0, 0), true, (float)ERHIZBuffer::FarPlane, true, 0, FIntRect()); // bottom Context.RHICmdList.SetScissorRect(true, ViewRect.Min.X, InnerRect.Max.Y, ViewRect.Max.X, ViewRect.Max.Y); Context.RHICmdList.Clear(false, FLinearColor(0, 0, 0, 0), true, (float)ERHIZBuffer::FarPlane, true, 0, FIntRect()); // left Context.RHICmdList.SetScissorRect(true, ViewRect.Min.X, ViewRect.Min.Y, InnerRect.Min.X, ViewRect.Max.Y); Context.RHICmdList.Clear(false, FLinearColor(0, 0, 0, 0), true, (float)ERHIZBuffer::FarPlane, true, 0, FIntRect()); // right Context.RHICmdList.SetScissorRect(true, InnerRect.Max.X, ViewRect.Min.Y, ViewRect.Max.X, ViewRect.Max.Y); Context.RHICmdList.Clear(false, FLinearColor(0, 0, 0, 0), true, (float)ERHIZBuffer::FarPlane, true, 0, FIntRect()); Context.RHICmdList.SetScissorRect(false, 0, 0, 0, 0); } } // Resolve to the output Context.RHICmdList.CopyToResolveTarget(DestRenderTarget.TargetableTexture, DestRenderTarget.ShaderResourceTexture, false, FResolveParams()); }
/** * Renders the view family. */ void FForwardShadingSceneRenderer::Render(FRHICommandListImmediate& RHICmdList) { QUICK_SCOPE_CYCLE_COUNTER(STAT_FForwardShadingSceneRenderer_Render); if(!ViewFamily.EngineShowFlags.Rendering) { return; } auto FeatureLevel = ViewFamily.GetFeatureLevel(); // Initialize global system textures (pass-through if already initialized). GSystemTextures.InitializeTextures(RHICmdList, FeatureLevel); FSceneRenderTargets& SceneContext = FSceneRenderTargets::Get(RHICmdList); // Allocate the maximum scene render target space for the current view family. SceneContext.Allocate(RHICmdList, ViewFamily); //make sure all the targets we're going to use will be safely writable. GRenderTargetPool.TransitionTargetsWritable(RHICmdList); // Find the visible primitives. InitViews(RHICmdList); // Notify the FX system that the scene is about to be rendered. if (Scene->FXSystem) { Scene->FXSystem->PreRender(RHICmdList, NULL); } GRenderTargetPool.VisualizeTexture.OnStartFrame(Views[0]); RenderShadowDepthMaps(RHICmdList); // Dynamic vertex and index buffers need to be committed before rendering. FGlobalDynamicVertexBuffer::Get().Commit(); FGlobalDynamicIndexBuffer::Get().Commit(); // This might eventually be a problem with multiple views. // Using only view 0 to check to do on-chip transform of alpha. FViewInfo& View = Views[0]; const bool bGammaSpace = !IsMobileHDR(); const bool bRequiresUpscale = !ViewFamily.bUseSeparateRenderTarget && ((uint32)ViewFamily.RenderTarget->GetSizeXY().X > ViewFamily.FamilySizeX || (uint32)ViewFamily.RenderTarget->GetSizeXY().Y > ViewFamily.FamilySizeY); // ES2 requires that the back buffer and depth match dimensions. // For the most part this is not the case when using scene captures. Thus scene captures always render to scene color target. const bool bRenderToScene = bRequiresUpscale || FSceneRenderer::ShouldCompositeEditorPrimitives(View) || View.bIsSceneCapture; if (bGammaSpace && !bRenderToScene) { SetRenderTarget(RHICmdList, ViewFamily.RenderTarget->GetRenderTargetTexture(), SceneContext.GetSceneDepthTexture(), ESimpleRenderTargetMode::EClearColorAndDepth); } else { // Begin rendering to scene color SceneContext.BeginRenderingSceneColor(RHICmdList, ESimpleRenderTargetMode::EClearColorAndDepth); } if (GIsEditor) { RHICmdList.Clear(true, Views[0].BackgroundColor, false, (float)ERHIZBuffer::FarPlane, false, 0, FIntRect()); } RenderForwardShadingBasePass(RHICmdList); // Make a copy of the scene depth if the current hardware doesn't support reading and writing to the same depth buffer ConditionalResolveSceneDepth(RHICmdList); if (ViewFamily.EngineShowFlags.Decals) { RenderDecals(RHICmdList); } // Notify the FX system that opaque primitives have been rendered. if (Scene->FXSystem) { //#todo-rco: This is switching to another RT! Scene->FXSystem->PostRenderOpaque(RHICmdList); } RenderModulatedShadowProjections(RHICmdList); // Draw translucency. if (ViewFamily.EngineShowFlags.Translucency) { SCOPE_CYCLE_COUNTER(STAT_TranslucencyDrawTime); // Note: Forward pass has no SeparateTranslucency, so refraction effect order with Translucency is different. // Having the distortion applied between two different translucency passes would make it consistent with the deferred pass. // This is not done yet. if (GetRefractionQuality(ViewFamily) > 0) { // to apply refraction effect by distorting the scene color RenderDistortionES2(RHICmdList); } RenderTranslucency(RHICmdList); } static const auto CVarMobileMSAA = IConsoleManager::Get().FindTConsoleVariableDataInt(TEXT("r.MobileMSAA")); bool bOnChipSunMask = GSupportsRenderTargetFormat_PF_FloatRGBA && GSupportsShaderFramebufferFetch && ViewFamily.EngineShowFlags.PostProcessing && ((View.bLightShaftUse) || (View.FinalPostProcessSettings.DepthOfFieldScale > 0.0) || ((ViewFamily.GetShaderPlatform() == SP_METAL) && (CVarMobileMSAA ? CVarMobileMSAA->GetValueOnAnyThread() > 1 : false)) ); if (!bGammaSpace && bOnChipSunMask) { // Convert alpha from depth to circle of confusion with sunshaft intensity. // This is done before resolve on hardware with framebuffer fetch. // This will break when PrePostSourceViewportSize is not full size. FIntPoint PrePostSourceViewportSize = SceneContext.GetBufferSizeXY(); FMemMark Mark(FMemStack::Get()); FRenderingCompositePassContext CompositeContext(RHICmdList, View); FRenderingCompositePass* PostProcessSunMask = CompositeContext.Graph.RegisterPass(new(FMemStack::Get()) FRCPassPostProcessSunMaskES2(PrePostSourceViewportSize, true)); CompositeContext.Process(PostProcessSunMask, TEXT("OnChipAlphaTransform")); } if (!bGammaSpace || bRenderToScene) { // Resolve the scene color for post processing. SceneContext.ResolveSceneColor(RHICmdList, FResolveRect(0, 0, ViewFamily.FamilySizeX, ViewFamily.FamilySizeY)); // Drop depth and stencil before post processing to avoid export. RHICmdList.DiscardRenderTargets(true, true, 0); } if (!bGammaSpace) { // Finish rendering for each view, or the full stereo buffer if enabled if (ViewFamily.bResolveScene) { { SCOPED_DRAW_EVENT(RHICmdList, PostProcessing); SCOPE_CYCLE_COUNTER(STAT_FinishRenderViewTargetTime); for(int32 ViewIndex = 0;ViewIndex < Views.Num();ViewIndex++) { SCOPED_CONDITIONAL_DRAW_EVENTF(RHICmdList, EventView, Views.Num() > 1, TEXT("View%d"), ViewIndex); GPostProcessing.ProcessES2(RHICmdList, Views[ViewIndex], bOnChipSunMask); } } } } else if (bRenderToScene) { for (int32 ViewIndex = 0; ViewIndex < Views.Num(); ViewIndex++) { BasicPostProcess(RHICmdList, Views[ViewIndex], bRequiresUpscale, FSceneRenderer::ShouldCompositeEditorPrimitives(Views[ViewIndex])); } } RenderFinish(RHICmdList); }
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); } }