UE4 SkyLight 记录

谁践踏了优雅 2022-09-15 11:44 337阅读 0赞

背景:

想了解一下,UE4如何使用HDR图,作为环境光,官方有个插件HDRIBackdrop,主要就是使用SkyLight进行,因此重点看了一下SkyLight,记录一下。

现在主要是记录过程,后面整理一个框架。

流程:

从Recapture入手,刚好转换的流程执行一遍。

  1. D:\UnrealEngine426\Engine\Source\Runtime\Engine\Private\Components\SkyLightComponent.cpp

    1. FAutoConsoleCommandWithWorld CaptureConsoleCommand(
      1. TEXT("r.SkylightRecapture"),
      2. TEXT("Updates all stationary and movable skylights, useful for debugging the capture pipeline"),
      3. FConsoleCommandWithWorldDelegate::CreateStatic(OnUpdateSkylights)
      4. );
    2. void OnUpdateSkylights(UWorld* InWorld)
      {
      1. for (TObjectIterator<USkyLightComponent> It; It; ++It)
      2. {
      3. USkyLightComponent* SkylightComponent = *It;
      4. if (InWorld->ContainsActor(SkylightComponent->GetOwner()) && !SkylightComponent->IsPendingKill())
      5. {
      6. SkylightComponent->SetCaptureIsDirty();
      7. }
      8. }
      9. USkyLightComponent::UpdateSkyCaptureContents(InWorld);
      }
    3. void USkyLightComponent::UpdateSkyCaptureContents(UWorld* WorldToUpdate)
      {

      1. if (WorldToUpdate->Scene)
      2. {
      3. QUICK_SCOPE_CYCLE_COUNTER(STAT_SkylightCaptures);
      4. if (GUpdateSkylightsEveryFrame)
      5. {
      6. for (TObjectIterator<USkyLightComponent> It; It; ++It)
      7. {
      8. USkyLightComponent* SkylightComponent = *It;
      9. if (WorldToUpdate->ContainsActor(SkylightComponent->GetOwner()) && !SkylightComponent->IsPendingKill())
      10. {
      11. SkylightComponent->SetCaptureIsDirty();
      12. }
      13. }
      14. }
      15. if (SkyCapturesToUpdate.Num() > 0)
      16. {
      17. FScopeLock Lock(&SkyCapturesToUpdateLock);
      18. UpdateSkyCaptureContentsArray(WorldToUpdate, SkyCapturesToUpdate, true);
      19. }
      20. if (SkyCapturesToUpdateBlendDestinations.Num() > 0)
      21. {
      22. UpdateSkyCaptureContentsArray(WorldToUpdate, SkyCapturesToUpdateBlendDestinations, false);
      23. }
      24. }

      }

    4. void USkyLightComponent::UpdateSkyCaptureContentsArray(UWorld WorldToUpdate, TArray<USkyLightComponent>& ComponentArray, bool bOperateOnBlendSource)
      {

      1. const bool bIsCompilingShaders = GShaderCompilingManager != NULL && GShaderCompilingManager->IsCompiling();
      2. // Iterate backwards so we can remove elements without changing the index
      3. for (int32 CaptureIndex = ComponentArray.Num() - 1; CaptureIndex >= 0; CaptureIndex--)
      4. {
      5. USkyLightComponent* CaptureComponent = ComponentArray[CaptureIndex];
      6. AActor* Owner = CaptureComponent->GetOwner();
      7. if (((!Owner || !Owner->GetLevel() || Owner->GetLevel()->bIsVisible) && CaptureComponent->GetWorld() == WorldToUpdate)
      8. // Only process sky capture requests once async shader compiling completes, otherwise we will capture the scene with temporary shaders
      9. && (!bIsCompilingShaders || CaptureComponent->SourceType == SLS_SpecifiedCubemap))
      10. {
      11. // Only capture valid sky light components
      12. if (CaptureComponent->SourceType != SLS_SpecifiedCubemap || CaptureComponent->Cubemap)
      13. {

      if WITH_EDITOR

      1. FStaticLightingSystemInterface::OnLightComponentUnregistered.Broadcast(CaptureComponent);

      endif

      1. if (bOperateOnBlendSource)
      2. {
      3. ensure(!CaptureComponent->ProcessedSkyTexture || CaptureComponent->ProcessedSkyTexture->GetSizeX() == CaptureComponent->ProcessedSkyTexture->GetSizeY());
      4. // Allocate the needed texture on first capture
      5. if (!CaptureComponent->ProcessedSkyTexture || CaptureComponent->ProcessedSkyTexture->GetSizeX() != CaptureComponent->CubemapResolution)
      6. {
      7. CaptureComponent->ProcessedSkyTexture = new FSkyTextureCubeResource();
      8. CaptureComponent->ProcessedSkyTexture->SetupParameters(CaptureComponent->CubemapResolution, FMath::CeilLogTwo(CaptureComponent->CubemapResolution) + 1, SKYLIGHT_CUBEMAP_FORMAT);
      9. BeginInitResource(CaptureComponent->ProcessedSkyTexture);
      10. CaptureComponent->MarkRenderStateDirty();
      11. }
      12. WorldToUpdate->Scene->UpdateSkyCaptureContents(CaptureComponent, CaptureComponent->bCaptureEmissiveOnly, CaptureComponent->Cubemap, CaptureComponent->ProcessedSkyTexture, CaptureComponent->AverageBrightness, CaptureComponent->IrradianceEnvironmentMap, NULL);
      13. CaptureComponent->UpdateImportanceSamplingData();
      14. }
      15. else
      16. {
      17. ensure(!CaptureComponent->BlendDestinationProcessedSkyTexture || CaptureComponent->BlendDestinationProcessedSkyTexture->GetSizeX() == CaptureComponent->BlendDestinationProcessedSkyTexture->GetSizeY());
      18. // Allocate the needed texture on first capture
      19. if (!CaptureComponent->BlendDestinationProcessedSkyTexture || CaptureComponent->BlendDestinationProcessedSkyTexture->GetSizeX() != CaptureComponent->CubemapResolution)
      20. {
      21. CaptureComponent->BlendDestinationProcessedSkyTexture = new FSkyTextureCubeResource();
      22. CaptureComponent->BlendDestinationProcessedSkyTexture->SetupParameters(CaptureComponent->CubemapResolution, FMath::CeilLogTwo(CaptureComponent->CubemapResolution) + 1, SKYLIGHT_CUBEMAP_FORMAT);
      23. BeginInitResource(CaptureComponent->BlendDestinationProcessedSkyTexture);
      24. CaptureComponent->MarkRenderStateDirty();
      25. }
      26. WorldToUpdate->Scene->UpdateSkyCaptureContents(CaptureComponent, CaptureComponent->bCaptureEmissiveOnly, CaptureComponent->BlendDestinationCubemap, CaptureComponent->BlendDestinationProcessedSkyTexture, CaptureComponent->BlendDestinationAverageBrightness, CaptureComponent->BlendDestinationIrradianceEnvironmentMap, NULL);
      27. CaptureComponent->UpdateImportanceSamplingData();
      28. }
      29. CaptureComponent->IrradianceMapFence.BeginFence();
      30. CaptureComponent->bHasEverCaptured = true;
      31. CaptureComponent->MarkRenderStateDirty();

      if WITH_EDITOR

      1. FStaticLightingSystemInterface::OnLightComponentRegistered.Broadcast(CaptureComponent);

      endif

      1. }
      2. // Only remove queued update requests if we processed it for the right world
      3. ComponentArray.RemoveAt(CaptureIndex);
      4. }
      5. }

      }

  2. D:\UnrealEngine426\Engine\Source\Runtime\Renderer\Private\ReflectionEnvironmentCapture.cpp

    1. // Warning: returns before writes to OutIrradianceEnvironmentMap have completed, as they are queued on the rendering thread
      void FScene::UpdateSkyCaptureContents(

      1. const USkyLightComponent* CaptureComponent,
      2. bool bCaptureEmissiveOnly,
      3. UTextureCube* SourceCubemap,
      4. FTexture* OutProcessedTexture,
      5. float& OutAverageBrightness,
      6. FSHVectorRGB3& OutIrradianceEnvironmentMap,
      7. TArray<FFloat16Color>* OutRadianceMap)

      {

      1. if (GSupportsRenderTargetFormat_PF_FloatRGBA || GetFeatureLevel() >= ERHIFeatureLevel::SM5)
      2. {
      3. QUICK_SCOPE_CYCLE_COUNTER(STAT_UpdateSkyCaptureContents);
      4. {
      5. World = GetWorld();
      6. if (World)
      7. {
      8. //guarantee that all render proxies are up to date before kicking off this render
      9. World->SendAllEndOfFrameUpdates();
      10. }
      11. }
      12. {
      13. int32 CubemapSize = CaptureComponent->CubemapResolution;
      14. ENQUEUE_RENDER_COMMAND(ClearCommand)(
      15. [CubemapSize](FRHICommandListImmediate& RHICmdList)
      16. {
      17. ClearScratchCubemaps(RHICmdList, CubemapSize);
      18. });
      19. }
      20. if (CaptureComponent->SourceType == SLS_CapturedScene)
      21. {
      22. bool bStaticSceneOnly = CaptureComponent->Mobility == EComponentMobility::Static;
      23. bool bCapturingForMobile = false;
      24. CaptureSceneIntoScratchCubemap(this, CaptureComponent->GetComponentLocation(), CaptureComponent->CubemapResolution, true, bStaticSceneOnly, CaptureComponent->SkyDistanceThreshold, CaptureComponent->bLowerHemisphereIsBlack, bCaptureEmissiveOnly, CaptureComponent->LowerHemisphereColor, bCapturingForMobile);
      25. }
      26. else if (CaptureComponent->SourceType == SLS_SpecifiedCubemap)
      27. {
      28. int32 CubemapSize = CaptureComponent->CubemapResolution;
      29. bool bLowerHemisphereIsBlack = CaptureComponent->bLowerHemisphereIsBlack;
      30. float SourceCubemapRotation = CaptureComponent->SourceCubemapAngle * (PI / 180.f);
      31. ERHIFeatureLevel::Type InnerFeatureLevel = FeatureLevel;
      32. FLinearColor LowerHemisphereColor = CaptureComponent->LowerHemisphereColor;
      33. ENQUEUE_RENDER_COMMAND(CopyCubemapCommand)(
      34. [SourceCubemap, CubemapSize, bLowerHemisphereIsBlack, SourceCubemapRotation, InnerFeatureLevel, LowerHemisphereColor](FRHICommandListImmediate& RHICmdList)
      35. {
      36. CopyCubemapToScratchCubemap(RHICmdList, InnerFeatureLevel, SourceCubemap, CubemapSize, true, bLowerHemisphereIsBlack, SourceCubemapRotation, LowerHemisphereColor);
      37. });
      38. }
      39. else if (CaptureComponent->IsRealTimeCaptureEnabled())
      40. {
      41. ensureMsgf(false, TEXT("A sky light with RealTimeCapture enabled cannot be scheduled for a cubemap update. This will be done dynamically each frame by the renderer."));
      42. return;
      43. }
      44. else
      45. {
      46. check(0);
      47. }
      48. if (OutRadianceMap)
      49. {
      50. int32 CubemapSize = CaptureComponent->CubemapResolution;
      51. ENQUEUE_RENDER_COMMAND(ReadbackCommand)(
      52. [CubemapSize, OutRadianceMap](FRHICommandListImmediate& RHICmdList)
      53. {
      54. ReadbackRadianceMap(RHICmdList, CubemapSize, *OutRadianceMap);
      55. });
      56. }
      57. {
      58. int32 CubemapSize = CaptureComponent->CubemapResolution;
      59. float* AverageBrightness = &OutAverageBrightness;
      60. FSHVectorRGB3* IrradianceEnvironmentMap = &OutIrradianceEnvironmentMap;
      61. ERHIFeatureLevel::Type InFeatureLevel = GetFeatureLevel();
      62. ENQUEUE_RENDER_COMMAND(FilterCommand)(
      63. [CubemapSize, AverageBrightness, IrradianceEnvironmentMap, InFeatureLevel](FRHICommandListImmediate& RHICmdList)
      64. {
      65. if (InFeatureLevel <= ERHIFeatureLevel::ES3_1)
      66. {
      67. MobileReflectionEnvironmentCapture::ComputeAverageBrightness(RHICmdList, InFeatureLevel, CubemapSize, *AverageBrightness);
      68. MobileReflectionEnvironmentCapture::FilterReflectionEnvironment(RHICmdList, InFeatureLevel, CubemapSize, IrradianceEnvironmentMap);
      69. }
      70. else
      71. {
      72. ComputeAverageBrightness(RHICmdList, InFeatureLevel, CubemapSize, *AverageBrightness);
      73. FilterReflectionEnvironment(RHICmdList, InFeatureLevel, CubemapSize, IrradianceEnvironmentMap);
      74. }
      75. });
      76. }
      77. // Optionally copy the filtered mip chain to the output texture
      78. if (OutProcessedTexture)
      79. {
      80. FScene* Scene = this;
      81. ERHIFeatureLevel::Type InFeatureLevel = GetFeatureLevel();
      82. ENQUEUE_RENDER_COMMAND(CopyCommand)(
      83. [Scene, OutProcessedTexture, InFeatureLevel](FRHICommandListImmediate& RHICmdList)
      84. {
      85. if (InFeatureLevel <= ERHIFeatureLevel::ES3_1)
      86. {
      87. MobileReflectionEnvironmentCapture::CopyToSkyTexture(RHICmdList, Scene, OutProcessedTexture);
      88. }
      89. else
      90. {
      91. CopyToSkyTexture(RHICmdList, Scene, OutProcessedTexture);
      92. }
      93. });
      94. }
      95. if (!!GFreeReflectionScratchAfterUse)
      96. {
      97. ENQUEUE_RENDER_COMMAND(FreeReflectionScratch)(
      98. [](FRHICommandListImmediate& RHICmdList)
      99. {
      100. FSceneRenderTargets& SceneContext = FSceneRenderTargets::Get(RHICmdList);
      101. SceneContext.FreeReflectionScratchRenderTargets();
      102. GRenderTargetPool.FreeUnusedResources();
      103. });
      104. }
      105. }

      }

    2. void CopyCubemapToScratchCubemap(FRHICommandListImmediate& RHICmdList, ERHIFeatureLevel::Type FeatureLevel, UTextureCube* SourceCubemap, int32 CubemapSize, bool bIsSkyLight, bool bLowerHemisphereIsBlack, float SourceCubemapRotation, const FLinearColor& LowerHemisphereColorValue)
      {

      1. SCOPED_DRAW_EVENT(RHICmdList, CopyCubemapToScratchCubemap);
      2. check(SourceCubemap);
      3. const FTexture* SourceCubemapResource = SourceCubemap->Resource;
      4. if (SourceCubemapResource == nullptr)
      5. {
      6. UE_LOG(LogEngine, Warning, TEXT("Unable to copy from cubemap %s, it's RHI resource is null"), *SourceCubemap->GetPathName());
      7. return;
      8. }
      9. FSceneRenderTargets& SceneContext = FSceneRenderTargets::Get(RHICmdList);
      10. FMemMark Mark(FMemStack::Get());
      11. FRDGBuilder GraphBuilder(RHICmdList);
      12. FRDGTextureRef OutputTexture = GraphBuilder.RegisterExternalTexture(SceneContext.ReflectionColorScratchCubemap[0], TEXT("ReflectionColorScratchCubemap"));
      13. for (uint32 CubeFace = 0; CubeFace < CubeFace_MAX; CubeFace++)
      14. {
      15. auto* PassParameters = GraphBuilder.AllocParameters<FCopyCubemapToCubeFacePS::FParameters>();
      16. PassParameters->RenderTargets[0] = FRenderTargetBinding(OutputTexture, ERenderTargetLoadAction::ENoAction, 0, CubeFace);
      17. PassParameters->LowerHemisphereColor = LowerHemisphereColorValue;
      18. PassParameters->SkyLightCaptureParameters = FVector(bIsSkyLight ? 1.0f : 0.0f, 0.0f, bLowerHemisphereIsBlack ? 1.0f : 0.0f);
      19. PassParameters->SourceCubemapSampler = TStaticSamplerState<SF_Bilinear, AM_Clamp, AM_Clamp, AM_Clamp>::GetRHI();
      20. PassParameters->SourceCubemapTexture = SourceCubemapResource->TextureRHI;
      21. PassParameters->SinCosSourceCubemapRotation = FVector2D(FMath::Sin(SourceCubemapRotation), FMath::Cos(SourceCubemapRotation));
      22. PassParameters->CubeFace = CubeFace;
      23. const int32 EffectiveSize = CubemapSize;
      24. GraphBuilder.AddPass(
      25. RDG_EVENT_NAME("CopyCubemapToCubeFace"),
      26. PassParameters,
      27. ERDGPassFlags::Raster,
      28. [EffectiveSize, &SceneContext, SourceCubemapResource, PassParameters, FeatureLevel](FRHICommandList& InRHICmdList)
      29. {
      30. const FIntPoint SourceDimensions(SourceCubemapResource->GetSizeX(), SourceCubemapResource->GetSizeY());
      31. const FIntRect ViewRect(0, 0, EffectiveSize, EffectiveSize);
      32. InRHICmdList.SetViewport(0.0f, 0.0f, 0.0f, (float)EffectiveSize, (float)EffectiveSize, 1.0f);
      33. FGraphicsPipelineStateInitializer GraphicsPSOInit;
      34. InRHICmdList.ApplyCachedRenderTargets(GraphicsPSOInit);
      35. GraphicsPSOInit.RasterizerState = TStaticRasterizerState<FM_Solid, CM_None>::GetRHI();
      36. GraphicsPSOInit.DepthStencilState = TStaticDepthStencilState<false, CF_Always>::GetRHI();
      37. GraphicsPSOInit.BlendState = TStaticBlendState<>::GetRHI();
      38. TShaderMapRef<FScreenVS> VertexShader(GetGlobalShaderMap(FeatureLevel));
      39. TShaderMapRef<FCopyCubemapToCubeFacePS> PixelShader(GetGlobalShaderMap(FeatureLevel));
      40. GraphicsPSOInit.BoundShaderState.VertexDeclarationRHI = GFilterVertexDeclaration.VertexDeclarationRHI;
      41. GraphicsPSOInit.BoundShaderState.VertexShaderRHI = VertexShader.GetVertexShader();
      42. GraphicsPSOInit.BoundShaderState.PixelShaderRHI = PixelShader.GetPixelShader();
      43. GraphicsPSOInit.PrimitiveType = PT_TriangleList;
      44. SetGraphicsPipelineState(InRHICmdList, GraphicsPSOInit);
      45. SetShaderParameters(InRHICmdList, PixelShader, PixelShader.GetPixelShader(), *PassParameters);
      46. DrawRectangle(
      47. InRHICmdList,
      48. ViewRect.Min.X, ViewRect.Min.Y,
      49. ViewRect.Width(), ViewRect.Height(),
      50. 0, 0,
      51. SourceDimensions.X, SourceDimensions.Y,
      52. FIntPoint(ViewRect.Width(), ViewRect.Height()),
      53. SourceDimensions,
      54. VertexShader);
      55. });
      56. }
      57. GraphBuilder.Execute();

      }

    3. class FCopyToCubeFaceShader : public FGlobalShader
      {
      public:

      1. static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters)
      2. {
      3. return true;
      4. }
      5. FCopyToCubeFaceShader() = default;
      6. FCopyToCubeFaceShader(const CompiledShaderInitializerType& Initializer)
      7. : FGlobalShader(Initializer)
      8. {}

      };

      /* Pixel shader used when copying a cubemap into a face of a reflection capture cubemap. /
      class FCopyCubemapToCubeFacePS : public FCopyToCubeFaceShader
      {
      public:

      1. DECLARE_GLOBAL_SHADER(FCopyCubemapToCubeFacePS);
      2. SHADER_USE_PARAMETER_STRUCT(FCopyCubemapToCubeFacePS, FCopyToCubeFaceShader);
      3. BEGIN_SHADER_PARAMETER_STRUCT(FParameters, )
      4. SHADER_PARAMETER_TEXTURE(TextureCube, SourceCubemapTexture)
      5. SHADER_PARAMETER_SAMPLER(SamplerState, SourceCubemapSampler)
      6. SHADER_PARAMETER(FVector, SkyLightCaptureParameters)
      7. SHADER_PARAMETER(int32, CubeFace)
      8. SHADER_PARAMETER(FVector4, LowerHemisphereColor)
      9. SHADER_PARAMETER(FVector2D, SinCosSourceCubemapRotation)
      10. RENDER_TARGET_BINDING_SLOTS()
      11. END_SHADER_PARAMETER_STRUCT()

      };

      IMPLEMENT_GLOBAL_SHADER(FCopyCubemapToCubeFacePS, “/Engine/Private/ReflectionEnvironmentShaders.usf”, “CopyCubemapToCubeFaceColorPS”, SF_Pixel);

      1. D:\UnrealEngine426\Engine\Shaders\Private\ReflectionEnvironmentShaders.usf

      2. int CubeFace;

        float3 GetCubemapVector(float2 ScaledUVs, int InCubeFace)
        {

        1. float3 CubeCoordinates;
        2. //@todo - this could be a 3x3 matrix multiply
        3. if (InCubeFace == 0)
        4. {
        5. CubeCoordinates = float3(1, -ScaledUVs.y, -ScaledUVs.x);
        6. }
        7. else if (InCubeFace == 1)
        8. {
        9. CubeCoordinates = float3(-1, -ScaledUVs.y, ScaledUVs.x);
        10. }
        11. else if (InCubeFace == 2)
        12. {
        13. CubeCoordinates = float3(ScaledUVs.x, 1, ScaledUVs.y);
        14. }
        15. else if (InCubeFace == 3)
        16. {
        17. CubeCoordinates = float3(ScaledUVs.x, -1, -ScaledUVs.y);
        18. }
        19. else if (InCubeFace == 4)
        20. {
        21. CubeCoordinates = float3(ScaledUVs.x, -ScaledUVs.y, 1);
        22. }
        23. else
        24. {
        25. CubeCoordinates = float3(-ScaledUVs.x, -ScaledUVs.y, -1);
        26. }
        27. return CubeCoordinates;

        }

  1. TextureCube SourceCubemapTexture;
  2. SamplerState SourceCubemapSampler;
  3. float2 SinCosSourceCubemapRotation;
  4. void CopyCubemapToCubeFaceColorPS(
  5. FScreenVertexOutput Input,
  6. out float4 OutColor : SV_Target0
  7. )
  8. {
  9. float2 ScaledUVs = Input.UV * 2 - 1;
  10. float3 CubeCoordinates = GetCubemapVector(ScaledUVs, CubeFace);
  11. // Rotate around Z axis
  12. CubeCoordinates.xy = float2(dot(CubeCoordinates.xy, float2(SinCosSourceCubemapRotation.y, -SinCosSourceCubemapRotation.x)), dot(CubeCoordinates.xy, SinCosSourceCubemapRotation));
  13. OutColor = TextureCubeSampleLevel(SourceCubemapTexture, SourceCubemapSampler, CubeCoordinates, 0);
  14. if (SkyLightCaptureParameters.x > 0)
  15. {
  16. // Assuming we're on a planet and no sky lighting is coming from below the horizon
  17. // This is important to avoid leaking from below since we are integrating incoming lighting and shadowing separately
  18. if (CubeCoordinates.z < 0 && SkyLightCaptureParameters.z >= 1)
  19. {
  20. OutColor.rgb = lerp(OutColor.rgb, LowerHemisphereColor.rgb, LowerHemisphereColor.a);
  21. }
  22. }
  23. OutColor.a = 1;
  24. }
  25. 4. D:\\UnrealEngine426\\Engine\\Source\\Runtime\\Engine\\Public\\ScreenRendering.h
  26. 1. /**
  27. * A vertex shader for rendering a textured screen element.
  28. */
  29. class FScreenVS : public FGlobalShader
  30. {
  31. DECLARE_EXPORTED_SHADER_TYPE(FScreenVS,Global,ENGINE_API);
  32. public:
  33. static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters) { return true; }
  34. FScreenVS(const ShaderMetaType::CompiledShaderInitializerType& Initializer):
  35. FGlobalShader(Initializer)
  36. {
  37. }
  38. FScreenVS() {}
  39. void SetParameters(FRHICommandList& RHICmdList, FRHIUniformBuffer* ViewUniformBuffer)
  40. {
  41. FGlobalShader::SetParameters<FViewUniformShaderParameters>(RHICmdList, RHICmdList.GetBoundVertexShader(), ViewUniformBuffer);
  42. }
  43. };
  44. 2. D:\\UnrealEngine426\\Engine\\Source\\Runtime\\Engine\\Private\\ScreenRendering.cpp
  45. 1. // Copyright Epic Games, Inc. All Rights Reserved.
  46. /*=============================================================================
  47. ScreenRendering.cpp: Screen rendering implementation.
  48. =============================================================================*/
  49. #include "ScreenRendering.h"
  50. /** Vertex declaration for screen-space rendering. */
  51. TGlobalResource<FScreenVertexDeclaration> GScreenVertexDeclaration;
  52. // Shader implementations.
  53. IMPLEMENT_SHADER_TYPE(, FScreenPS, TEXT("/Engine/Private/ScreenPixelShader.usf"), TEXT("Main"), SF_Pixel);
  54. IMPLEMENT_SHADER_TYPE(,FScreenPSInvertAlpha,TEXT("/Engine/Private/ScreenPixelShader.usf"),TEXT("MainInvertAlpha"),SF_Pixel);
  55. IMPLEMENT_SHADER_TYPE(,FScreenPSsRGBSource, TEXT("/Engine/Private/ScreenPixelShader.usf"), TEXT("MainsRGBSource"), SF_Pixel);
  56. IMPLEMENT_SHADER_TYPE(,FScreenPSMipLevel, TEXT("/Engine/Private/ScreenPixelShader.usf"), TEXT("MainMipLevel"), SF_Pixel);
  57. IMPLEMENT_SHADER_TYPE(,FScreenPSsRGBSourceMipLevel, TEXT("/Engine/Private/ScreenPixelShader.usf"), TEXT("MainsRGBSourceMipLevel"), SF_Pixel);
  58. IMPLEMENT_SHADER_TYPE(,FScreenVS,TEXT("/Engine/Private/ScreenVertexShader.usf"),TEXT("Main"),SF_Vertex);
  59. IMPLEMENT_SHADER_TYPE(,FScreenPS_OSE,TEXT("/Engine/Private/ScreenPixelShaderOES.usf"),TEXT("Main"),SF_Pixel);
  60. 2. /Private/ScreenVertexShader.usf
  61. 1. void Main(
  62. float2 InPosition : ATTRIBUTE0,
  63. float2 InUV : ATTRIBUTE1,
  64. out FScreenVertexOutput Output
  65. )
  66. {
  67. DrawRectangle( float4( InPosition, 0, 1 ), InUV, Output.Position, Output.UV);
  68. }
  69. 2. /Private/Common.ush
  70. 1. /** Used for calculating vertex positions and UVs when drawing with DrawRectangle */
  71. void DrawRectangle(
  72. in float4 InPosition,
  73. in float2 InTexCoord,
  74. out float4 OutPosition,
  75. out float2 OutTexCoord)
  76. {
  77. OutPosition = InPosition;
  78. OutPosition.xy = -1.0f + 2.0f * (DrawRectangleParameters.PosScaleBias.zw + (InPosition.xy * DrawRectangleParameters.PosScaleBias.xy)) * DrawRectangleParameters.InvTargetSizeAndTextureSize.xy;
  79. OutPosition.xy *= float2( 1, -1 );
  80. OutTexCoord.xy = (DrawRectangleParameters.UVScaleBias.zw + (InTexCoord.xy * DrawRectangleParameters.UVScaleBias.xy)) * DrawRectangleParameters.InvTargetSizeAndTextureSize.zw;
  81. }
  82. 5. D:\\UnrealEngine426\\Engine\\Source\\Runtime\\Renderer\\Private\\PostProcess\\SceneFilterRendering.h
  83. 1. /**
  84. * Draws a quad with the given vertex positions and UVs in denormalized pixel/texel coordinates.
  85. * The platform-dependent mapping from pixels to texels is done automatically.
  86. * Note that the positions are affected by the current viewport.
  87. * NOTE: DrawRectangle should be used in the vertex shader to calculate the correct position and uv for vertices.
  88. * NOTE2: Assumes previously set PSO has PrimitiveType = PT_TriangleList
  89. *
  90. * X, Y Position in screen pixels of the top left corner of the quad
  91. * SizeX, SizeY Size in screen pixels of the quad
  92. * U, V Position in texels of the top left corner of the quad's UV's
  93. * SizeU, SizeV Size in texels of the quad's UV's
  94. * TargetSizeX, TargetSizeY Size in screen pixels of the target surface
  95. * TextureSize Size in texels of the source texture
  96. * VertexShader The vertex shader used for rendering
  97. * Flags see EDrawRectangleFlags
  98. * InstanceCount Number of instances of rectangle
  99. */
  100. extern RENDERER_API void DrawRectangle(
  101. FRHICommandList& RHICmdList,
  102. float X,
  103. float Y,
  104. float SizeX,
  105. float SizeY,
  106. float U,
  107. float V,
  108. float SizeU,
  109. float SizeV,
  110. FIntPoint TargetSize,
  111. FIntPoint TextureSize,
  112. const TShaderRef<FShader>& VertexShader,
  113. EDrawRectangleFlags Flags = EDRF_Default,
  114. uint32 InstanceCount = 1
  115. );
  116. /** Uniform buffer for computing the vertex positional and UV adjustments in the vertex shader. */
  117. BEGIN_GLOBAL_SHADER_PARAMETER_STRUCT( FDrawRectangleParameters, RENDERER_API)
  118. SHADER_PARAMETER( FVector4, PosScaleBias )
  119. SHADER_PARAMETER( FVector4, UVScaleBias )
  120. SHADER_PARAMETER( FVector4, InvTargetSizeAndTextureSize )
  121. END_GLOBAL_SHADER_PARAMETER_STRUCT()
  122. 2. D:\\UnrealEngine426\\Engine\\Source\\Runtime\\Renderer\\Private\\PostProcess\\SceneFilterRendering.cpp
  123. 1. void DrawRectangle(
  124. FRHICommandList& RHICmdList,
  125. float X,
  126. float Y,
  127. float SizeX,
  128. float SizeY,
  129. float U,
  130. float V,
  131. float SizeU,
  132. float SizeV,
  133. FIntPoint TargetSize,
  134. FIntPoint TextureSize,
  135. const TShaderRef<FShader>& VertexShader,
  136. EDrawRectangleFlags Flags,
  137. uint32 InstanceCount
  138. )
  139. {
  140. InternalDrawRectangle(RHICmdList, X, Y, SizeX, SizeY, U, V, SizeU, SizeV, TargetSize, TextureSize, VertexShader, Flags, InstanceCount);
  141. }
  142. template <typename TRHICommandList>
  143. static inline void InternalDrawRectangle(
  144. TRHICommandList& RHICmdList,
  145. float X,
  146. float Y,
  147. float SizeX,
  148. float SizeY,
  149. float U,
  150. float V,
  151. float SizeU,
  152. float SizeV,
  153. FIntPoint TargetSize,
  154. FIntPoint TextureSize,
  155. const TShaderRef<FShader>& VertexShader,
  156. EDrawRectangleFlags Flags,
  157. uint32 InstanceCount
  158. )
  159. {
  160. float ClipSpaceQuadZ = 0.0f;
  161. DoDrawRectangleFlagOverride(Flags);
  162. // triangle if extending to left and top of the given rectangle, if it's not left top of the viewport it can cause artifacts
  163. if(X > 0.0f || Y > 0.0f)
  164. {
  165. // don't use triangle optimization
  166. Flags = EDRF_Default;
  167. }
  168. // Set up vertex uniform parameters for scaling and biasing the rectangle.
  169. // Note: Use DrawRectangle in the vertex shader to calculate the correct vertex position and uv.
  170. FDrawRectangleParameters Parameters;
  171. Parameters.PosScaleBias = FVector4(SizeX, SizeY, X, Y);
  172. Parameters.UVScaleBias = FVector4(SizeU, SizeV, U, V);
  173. Parameters.InvTargetSizeAndTextureSize = FVector4(
  174. 1.0f / TargetSize.X, 1.0f / TargetSize.Y,
  175. 1.0f / TextureSize.X, 1.0f / TextureSize.Y);
  176. SetUniformBufferParameterImmediate(RHICmdList, VertexShader.GetVertexShader(), VertexShader->GetUniformBufferParameter<FDrawRectangleParameters>(), Parameters);
  177. if(Flags == EDRF_UseTesselatedIndexBuffer)
  178. {
  179. // no vertex buffer needed as we compute it in VS
  180. RHICmdList.SetStreamSource(0, NULL, 0);
  181. RHICmdList.DrawIndexedPrimitive(
  182. GTesselatedScreenRectangleIndexBuffer.IndexBufferRHI,
  183. /*BaseVertexIndex=*/ 0,
  184. /*MinIndex=*/ 0,
  185. /*NumVertices=*/ GTesselatedScreenRectangleIndexBuffer.NumVertices(),
  186. /*StartIndex=*/ 0,
  187. /*NumPrimitives=*/ GTesselatedScreenRectangleIndexBuffer.NumPrimitives(),
  188. /*NumInstances=*/ InstanceCount
  189. );
  190. }
  191. else
  192. {
  193. if (Flags == EDRF_UseTriangleOptimization)
  194. {
  195. FPixelShaderUtils::DrawFullscreenTriangle(RHICmdList, InstanceCount);
  196. }
  197. else
  198. {
  199. FPixelShaderUtils::DrawFullscreenQuad(RHICmdList, InstanceCount);
  200. }
  201. }
  202. }
  203. 2. D:\\UnrealEngine426\\Engine\\Source\\Runtime\\RenderCore\\Private\\PixelShaderUtils.cpp
  204. 1. // static
  205. void FPixelShaderUtils::DrawFullscreenQuad(FRHICommandList& RHICmdList, uint32 InstanceCount)
  206. {
  207. RHICmdList.SetStreamSource(0, GScreenRectangleVertexBuffer.VertexBufferRHI, 0);
  208. RHICmdList.DrawIndexedPrimitive(
  209. GScreenRectangleIndexBuffer.IndexBufferRHI,
  210. /*BaseVertexIndex=*/ 0,
  211. /*MinIndex=*/ 0,
  212. /*NumVertices=*/ 4,
  213. /*StartIndex=*/ 0,
  214. /*NumPrimitives=*/ 2,
  215. /*NumInstances=*/ InstanceCount);
  216. }
  217. 6. ComputeAverageBrightness()
  218. 1. void ComputeAverageBrightness(FRHICommandListImmediate& RHICmdList, ERHIFeatureLevel::Type FeatureLevel, int32 CubmapSize, float& OutAverageBrightness)
  219. {
  220. SCOPED_DRAW_EVENT(RHICmdList, ComputeAverageBrightness);
  221. const int32 EffectiveTopMipSize = CubmapSize;
  222. const int32 NumMips = FMath::CeilLogTwo(EffectiveTopMipSize) + 1;
  223. // necessary to resolve the clears which touched all the mips. scene rendering only resolves mip 0.
  224. FullyResolveReflectionScratchCubes(RHICmdList);
  225. FSceneRenderTargetItem& DownSampledCube = FSceneRenderTargets::Get(RHICmdList).ReflectionColorScratchCubemap[0]->GetRenderTargetItem();
  226. CreateCubeMips( RHICmdList, FeatureLevel, NumMips, DownSampledCube );
  227. OutAverageBrightness = ComputeSingleAverageBrightnessFromCubemap(RHICmdList, FeatureLevel, CubmapSize, DownSampledCube);
  228. }
  229. 2. void CreateCubeMips( FRHICommandListImmediate& RHICmdList, ERHIFeatureLevel::Type FeatureLevel, int32 NumMips, FSceneRenderTargetItem& Cubemap )
  230. {
  231. SCOPED_DRAW_EVENT(RHICmdList, CreateCubeMips);
  232. FRHITexture* CubeRef = Cubemap.TargetableTexture.GetReference();
  233. auto* ShaderMap = GetGlobalShaderMap(FeatureLevel);
  234. TArray<TPair<FRHITextureSRVCreateInfo, TRefCountPtr<FRHIShaderResourceView>>> SRVs;
  235. SRVs.Empty(NumMips);
  236. for (int32 MipIndex = 0; MipIndex < NumMips; MipIndex++)
  237. {
  238. FRHITextureSRVCreateInfo SRVDesc;
  239. SRVDesc.MipLevel = MipIndex;
  240. SRVs.Emplace(SRVDesc, RHICreateShaderResourceView(Cubemap.ShaderResourceTexture, SRVDesc));
  241. }
  242. FGraphicsPipelineStateInitializer GraphicsPSOInit;
  243. GraphicsPSOInit.RasterizerState = TStaticRasterizerState<FM_Solid, CM_None>::GetRHI();
  244. GraphicsPSOInit.DepthStencilState = TStaticDepthStencilState<false, CF_Always>::GetRHI();
  245. GraphicsPSOInit.BlendState = TStaticBlendState<>::GetRHI();
  246. // Downsample all the mips, each one reads from the mip above it
  247. for (int32 MipIndex = 1; MipIndex < NumMips; MipIndex++)
  248. {
  249. // For the first iteration, we don't know what the previous state
  250. // of the source mip was, but we *do* for all the other iterations...
  251. ERHIAccess Previous = MipIndex == 1
  252. ? ERHIAccess::Unknown
  253. : ERHIAccess::RTV;
  254. FRHITransitionInfo Transitions[] =
  255. {
  256. // Make the source mip readable (SRVGraphics)
  257. FRHITransitionInfo(CubeRef, Previous, ERHIAccess::SRVGraphics, EResourceTransitionFlags::None, uint32(MipIndex - 1)),
  258. // Make the destination mip writable (RTV)
  259. FRHITransitionInfo(CubeRef, ERHIAccess::Unknown, ERHIAccess::RTV, EResourceTransitionFlags::None, uint32(MipIndex))
  260. };
  261. RHICmdList.Transition(Transitions);
  262. const int32 MipSize = 1 << (NumMips - MipIndex - 1);
  263. SCOPED_DRAW_EVENT(RHICmdList, CreateCubeMipsPerFace);
  264. for (int32 CubeFace = 0; CubeFace < CubeFace_MAX; CubeFace++)
  265. {
  266. FRHIRenderPassInfo RPInfo(Cubemap.TargetableTexture, ERenderTargetActions::DontLoad_Store, nullptr, MipIndex, CubeFace);
  267. RHICmdList.BeginRenderPass(RPInfo, TEXT("CreateCubeMips"));
  268. RHICmdList.ApplyCachedRenderTargets(GraphicsPSOInit);
  269. const FIntRect ViewRect(0, 0, MipSize, MipSize);
  270. RHICmdList.SetViewport(0.0f, 0.0f, 0.0f, (float)MipSize, (float)MipSize, 1.0f);
  271. TShaderMapRef<FScreenVS> VertexShader(ShaderMap);
  272. TShaderMapRef<FCubeFilterPS> PixelShader(ShaderMap);
  273. GraphicsPSOInit.BoundShaderState.VertexDeclarationRHI = GFilterVertexDeclaration.VertexDeclarationRHI;
  274. GraphicsPSOInit.BoundShaderState.VertexShaderRHI = VertexShader.GetVertexShader();
  275. GraphicsPSOInit.BoundShaderState.PixelShaderRHI = PixelShader.GetPixelShader();
  276. GraphicsPSOInit.PrimitiveType = PT_TriangleList;
  277. SetGraphicsPipelineState(RHICmdList, GraphicsPSOInit);
  278. {
  279. FRHIPixelShader* ShaderRHI = PixelShader.GetPixelShader();
  280. SetShaderValue(RHICmdList, ShaderRHI, PixelShader->CubeFace, CubeFace);
  281. SetShaderValue(RHICmdList, ShaderRHI, PixelShader->MipIndex, MipIndex);
  282. SetShaderValue(RHICmdList, ShaderRHI, PixelShader->NumMips, NumMips);
  283. check(SRVs.IsValidIndex(MipIndex - 1) && SRVs[MipIndex - 1].Key.MipLevel == MipIndex - 1);
  284. SetSRVParameter(RHICmdList, ShaderRHI, PixelShader->SourceCubemapTexture, SRVs[MipIndex - 1].Value);
  285. SetSamplerParameter(RHICmdList, ShaderRHI, PixelShader->SourceCubemapSampler, TStaticSamplerState<SF_Bilinear, AM_Clamp, AM_Clamp, AM_Clamp>::GetRHI());
  286. }
  287. DrawRectangle(
  288. RHICmdList,
  289. ViewRect.Min.X, ViewRect.Min.Y,
  290. ViewRect.Width(), ViewRect.Height(),
  291. ViewRect.Min.X, ViewRect.Min.Y,
  292. ViewRect.Width(), ViewRect.Height(),
  293. FIntPoint(ViewRect.Width(), ViewRect.Height()),
  294. FIntPoint(MipSize, MipSize),
  295. VertexShader);
  296. RHICmdList.EndRenderPass();
  297. }
  298. }
  299. RHICmdList.Transition(FRHITransitionInfo(CubeRef, ERHIAccess::Unknown, ERHIAccess::SRVMask));
  300. SRVs.Empty();
  301. }
  302. 1. void DownsamplePS(
  303. FScreenVertexOutput Input,
  304. out float4 OutColor : SV_Target0
  305. )
  306. {
  307. float2 ScaledUVs = Input.UV * 2 - 1;
  308. const int SelectedCubeFace = CubeFace;
  309. #endif // USE_COMPUTE
  310. float3 CubeCoordinates = GetCubemapVector(ScaledUVs, SelectedCubeFace);
  311. uint MipSize = 1 << ( NumMips - MipIndex - 1 );
  312. float3 TangentZ = normalize( CubeCoordinates );
  313. float3 TangentX = normalize( cross( GetCubemapVector( ScaledUVs + float2(0,1), SelectedCubeFace), TangentZ ) );
  314. float3 TangentY = cross( TangentZ, TangentX );
  315. const float SampleOffset = 2.0 * 2 / MipSize;
  316. float2 Offsets[] =
  317. {
  318. float2(-1, -1) * 0.7,
  319. float2( 1, -1) * 0.7,
  320. float2(-1, 1) * 0.7,
  321. float2( 1, 1) * 0.7,
  322. float2( 0, -1),
  323. float2(-1, 0),
  324. float2( 1, 0),
  325. float2( 0, 1),
  326. };
  327. OutColor = SourceCubemapTexture.SampleLevel(SourceCubemapSampler, CubeCoordinates, 0 );
  328. UNROLL
  329. for( uint i = 0; i < 8; i++ )
  330. {
  331. float Weight = 0.375;
  332. float3 SampleDir = CubeCoordinates;
  333. SampleDir += TangentX * ( Offsets[i].x * SampleOffset );
  334. SampleDir += TangentY * ( Offsets[i].y * SampleOffset );
  335. OutColor += SourceCubemapTexture.SampleLevel(SourceCubemapSampler, SampleDir, 0 ) * Weight;
  336. }
  337. OutColor *= rcp( 1.0 + 1.0 + 2.0 );
  338. #ifdef USE_COMPUTE
  339. OutTextureMipColor[uint3(FaceCoord, SelectedCubeFace)] = OutColor;
  340. #endif
  341. }
  342. 3. /** Computes the average brightness of the given reflection capture and stores it in the scene. */
  343. float ComputeSingleAverageBrightnessFromCubemap(FRHICommandListImmediate& RHICmdList, ERHIFeatureLevel::Type FeatureLevel, int32 TargetSize, FSceneRenderTargetItem& Cubemap)
  344. {
  345. SCOPED_DRAW_EVENT(RHICmdList, ComputeSingleAverageBrightnessFromCubemap);
  346. TRefCountPtr<IPooledRenderTarget> ReflectionBrightnessTarget;
  347. FPooledRenderTargetDesc Desc(FPooledRenderTargetDesc::Create2DDesc(FIntPoint(1, 1), PF_FloatRGBA, FClearValueBinding::None, TexCreate_None, TexCreate_RenderTargetable, false));
  348. GRenderTargetPool.FindFreeElement(RHICmdList, Desc, ReflectionBrightnessTarget, TEXT("ReflectionBrightness"));
  349. FTextureRHIRef& BrightnessTarget = ReflectionBrightnessTarget->GetRenderTargetItem().TargetableTexture;
  350. FRHIRenderPassInfo RPInfo(BrightnessTarget, ERenderTargetActions::Load_Store);
  351. TransitionRenderPassTargets(RHICmdList, RPInfo);
  352. RHICmdList.BeginRenderPass(RPInfo, TEXT("ReflectionBrightness"));
  353. {
  354. FGraphicsPipelineStateInitializer GraphicsPSOInit;
  355. RHICmdList.ApplyCachedRenderTargets(GraphicsPSOInit);
  356. GraphicsPSOInit.RasterizerState = TStaticRasterizerState<FM_Solid, CM_None>::GetRHI();
  357. GraphicsPSOInit.DepthStencilState = TStaticDepthStencilState<false, CF_Always>::GetRHI();
  358. GraphicsPSOInit.BlendState = TStaticBlendState<>::GetRHI();
  359. auto ShaderMap = GetGlobalShaderMap(FeatureLevel);
  360. TShaderMapRef<FPostProcessVS> VertexShader(ShaderMap);
  361. TShaderMapRef<FComputeBrightnessPS> PixelShader(ShaderMap);
  362. GraphicsPSOInit.BoundShaderState.VertexDeclarationRHI = GFilterVertexDeclaration.VertexDeclarationRHI;
  363. GraphicsPSOInit.BoundShaderState.VertexShaderRHI = VertexShader.GetVertexShader();
  364. GraphicsPSOInit.BoundShaderState.PixelShaderRHI = PixelShader.GetPixelShader();
  365. GraphicsPSOInit.PrimitiveType = PT_TriangleList;
  366. SetGraphicsPipelineState(RHICmdList, GraphicsPSOInit);
  367. PixelShader->SetParameters(RHICmdList, TargetSize, Cubemap);
  368. DrawRectangle(
  369. RHICmdList,
  370. 0, 0,
  371. 1, 1,
  372. 0, 0,
  373. 1, 1,
  374. FIntPoint(1, 1),
  375. FIntPoint(1, 1),
  376. VertexShader);
  377. }
  378. RHICmdList.EndRenderPass();
  379. RHICmdList.CopyToResolveTarget(BrightnessTarget, BrightnessTarget, FResolveParams());
  380. FSceneRenderTargetItem& EffectiveRT = ReflectionBrightnessTarget->GetRenderTargetItem();
  381. check(EffectiveRT.ShaderResourceTexture->GetFormat() == PF_FloatRGBA);
  382. TArray<FFloat16Color> SurfaceData;
  383. RHICmdList.ReadSurfaceFloatData(EffectiveRT.ShaderResourceTexture, FIntRect(0, 0, 1, 1), SurfaceData, CubeFace_PosX, 0, 0);
  384. // Shader outputs luminance to R
  385. float AverageBrightness = SurfaceData[0].R.GetFloat();
  386. return AverageBrightness;
  387. }
  388. 1. int NumCaptureArrayMips;
  389. /** Cube map array of reflection captures. */
  390. TextureCube ReflectionEnvironmentColorTexture;
  391. SamplerState ReflectionEnvironmentColorSampler;
  392. #if COMPUTEBRIGHTNESS_PIXELSHADER
  393. void ComputeBrightnessMain(
  394. in float4 UVAndScreenPos : TEXCOORD0,
  395. out float4 OutColor : SV_Target0
  396. )
  397. {
  398. // Sample the 6 1x1 cube faces and average
  399. float3 AverageColor = TextureCubeSampleLevel(ReflectionEnvironmentColorTexture, ReflectionEnvironmentColorSampler, float3(1, 0, 0), NumCaptureArrayMips - 1).rgb;
  400. AverageColor += TextureCubeSampleLevel(ReflectionEnvironmentColorTexture, ReflectionEnvironmentColorSampler, float3(-1, 0, 0), NumCaptureArrayMips - 1).rgb;
  401. AverageColor += TextureCubeSampleLevel(ReflectionEnvironmentColorTexture, ReflectionEnvironmentColorSampler, float3(0, 1, 0), NumCaptureArrayMips - 1).rgb;
  402. AverageColor += TextureCubeSampleLevel(ReflectionEnvironmentColorTexture, ReflectionEnvironmentColorSampler, float3(0, -1, 0), NumCaptureArrayMips - 1).rgb;
  403. AverageColor += TextureCubeSampleLevel(ReflectionEnvironmentColorTexture, ReflectionEnvironmentColorSampler, float3(0, 0, 1), NumCaptureArrayMips - 1).rgb;
  404. AverageColor += TextureCubeSampleLevel(ReflectionEnvironmentColorTexture, ReflectionEnvironmentColorSampler, float3(0, 0, -1), NumCaptureArrayMips - 1).rgb;
  405. OutColor = dot(AverageColor / 6, .3333f);
  406. }
  407. #endif
  408. 7. FilterReflectionEnvironment()
  409. 1. /** Generates mips for glossiness and filters the cubemap for a given reflection. */
  410. void FilterReflectionEnvironment(FRHICommandListImmediate& RHICmdList, ERHIFeatureLevel::Type FeatureLevel, int32 CubmapSize, FSHVectorRGB3* OutIrradianceEnvironmentMap)
  411. {
  412. SCOPED_DRAW_EVENT(RHICmdList, FilterReflectionEnvironment);
  413. const int32 EffectiveTopMipSize = CubmapSize;
  414. const int32 NumMips = FMath::CeilLogTwo(EffectiveTopMipSize) + 1;
  415. FSceneRenderTargetItem& EffectiveColorRT = FSceneRenderTargets::Get(RHICmdList).ReflectionColorScratchCubemap[0]->GetRenderTargetItem();
  416. FGraphicsPipelineStateInitializer GraphicsPSOInit;
  417. GraphicsPSOInit.RasterizerState = TStaticRasterizerState<FM_Solid, CM_None>::GetRHI();
  418. GraphicsPSOInit.DepthStencilState = TStaticDepthStencilState<false, CF_Always>::GetRHI();
  419. GraphicsPSOInit.BlendState = TStaticBlendState<CW_RGBA, BO_Add, BF_Zero, BF_DestAlpha, BO_Add, BF_Zero, BF_One>::GetRHI();
  420. RHICmdList.Transition(FRHITransitionInfo(EffectiveColorRT.TargetableTexture, ERHIAccess::Unknown, ERHIAccess::RTV));
  421. // Premultiply alpha in-place using alpha blending
  422. for (uint32 CubeFace = 0; CubeFace < CubeFace_MAX; CubeFace++)
  423. {
  424. FRHIRenderPassInfo RPInfo(EffectiveColorRT.TargetableTexture, ERenderTargetActions::Load_Store, nullptr, 0, CubeFace);
  425. RHICmdList.BeginRenderPass(RPInfo, TEXT("FilterReflectionEnvironmentRP"));
  426. RHICmdList.ApplyCachedRenderTargets(GraphicsPSOInit);
  427. const FIntPoint SourceDimensions(CubmapSize, CubmapSize);
  428. const FIntRect ViewRect(0, 0, EffectiveTopMipSize, EffectiveTopMipSize);
  429. RHICmdList.SetViewport(0, 0, 0.0f, EffectiveTopMipSize, EffectiveTopMipSize, 1.0f);
  430. TShaderMapRef<FScreenVS> VertexShader(GetGlobalShaderMap(FeatureLevel));
  431. TShaderMapRef<FOneColorPS> PixelShader(GetGlobalShaderMap(FeatureLevel));
  432. GraphicsPSOInit.BoundShaderState.VertexDeclarationRHI = GFilterVertexDeclaration.VertexDeclarationRHI;
  433. GraphicsPSOInit.BoundShaderState.VertexShaderRHI = VertexShader.GetVertexShader();
  434. GraphicsPSOInit.BoundShaderState.PixelShaderRHI = PixelShader.GetPixelShader();
  435. GraphicsPSOInit.PrimitiveType = PT_TriangleList;
  436. SetGraphicsPipelineState(RHICmdList, GraphicsPSOInit);
  437. FLinearColor UnusedColors[1] = { FLinearColor::Black };
  438. PixelShader->SetColors(RHICmdList, UnusedColors, UE_ARRAY_COUNT(UnusedColors));
  439. DrawRectangle(
  440. RHICmdList,
  441. ViewRect.Min.X, ViewRect.Min.Y,
  442. ViewRect.Width(), ViewRect.Height(),
  443. 0, 0,
  444. SourceDimensions.X, SourceDimensions.Y,
  445. FIntPoint(ViewRect.Width(), ViewRect.Height()),
  446. SourceDimensions,
  447. VertexShader);
  448. RHICmdList.EndRenderPass();
  449. }
  450. RHICmdList.Transition(FRHITransitionInfo(EffectiveColorRT.TargetableTexture, ERHIAccess::Unknown, ERHIAccess::SRVMask));
  451. auto ShaderMap = GetGlobalShaderMap(FeatureLevel);
  452. FSceneRenderTargets& SceneContext = FSceneRenderTargets::Get(RHICmdList);
  453. FSceneRenderTargetItem& DownSampledCube = FSceneRenderTargets::Get(RHICmdList).ReflectionColorScratchCubemap[0]->GetRenderTargetItem();
  454. FSceneRenderTargetItem& FilteredCube = FSceneRenderTargets::Get(RHICmdList).ReflectionColorScratchCubemap[1]->GetRenderTargetItem();
  455. CreateCubeMips( RHICmdList, FeatureLevel, NumMips, DownSampledCube );
  456. if (OutIrradianceEnvironmentMap)
  457. {
  458. SCOPED_DRAW_EVENT(RHICmdList, ComputeDiffuseIrradiance);
  459. const int32 NumDiffuseMips = FMath::CeilLogTwo( GDiffuseIrradianceCubemapSize ) + 1;
  460. const int32 DiffuseConvolutionSourceMip = FMath::Max(0, NumMips - NumDiffuseMips);
  461. ComputeDiffuseIrradiance(RHICmdList, FeatureLevel, DownSampledCube.ShaderResourceTexture, DiffuseConvolutionSourceMip, OutIrradianceEnvironmentMap);
  462. }
  463. FilterCubeMap(RHICmdList, FeatureLevel, NumMips, DownSampledCube, FilteredCube);
  464. RHICmdList.CopyToResolveTarget(FilteredCube.TargetableTexture, FilteredCube.ShaderResourceTexture, FResolveParams());
  465. }
  466. 1. ComputeDiffuseIrradiance() D:\\UnrealEngine426\\Engine\\Source\\Runtime\\Renderer\\Private\\ReflectionEnvironmentDiffuseIrradiance.cpp
  467. 1. void ComputeDiffuseIrradiance(FRHICommandListImmediate& RHICmdList, ERHIFeatureLevel::Type FeatureLevel, FTextureRHIRef LightingSource, int32 LightingSourceMipIndex, FSHVectorRGB3* OutIrradianceEnvironmentMap)
  468. {
  469. auto ShaderMap = GetGlobalShaderMap(FeatureLevel);
  470. FSceneRenderTargets& SceneContext = FSceneRenderTargets::Get(RHICmdList);
  471. FGraphicsPipelineStateInitializer GraphicsPSOInit;
  472. GraphicsPSOInit.RasterizerState = TStaticRasterizerState<FM_Solid, CM_None>::GetRHI();
  473. GraphicsPSOInit.DepthStencilState = TStaticDepthStencilState<false, CF_Always>::GetRHI();
  474. GraphicsPSOInit.BlendState = TStaticBlendState<>::GetRHI();
  475. for (int32 CoefficientIndex = 0; CoefficientIndex < FSHVector3::MaxSHBasis; CoefficientIndex++)
  476. {
  477. // Copy the starting mip from the lighting texture, apply texel area weighting and appropriate SH coefficient
  478. {
  479. const int32 MipIndex = 0;
  480. const int32 MipSize = GDiffuseIrradianceCubemapSize;
  481. FSceneRenderTargetItem& EffectiveRT = GetEffectiveDiffuseIrradianceRenderTarget(SceneContext, MipIndex);
  482. RHICmdList.Transition(FRHITransitionInfo(EffectiveRT.TargetableTexture, ERHIAccess::Unknown, ERHIAccess::RTV));
  483. for (int32 CubeFace = 0; CubeFace < CubeFace_MAX; CubeFace++)
  484. {
  485. FRHIRenderPassInfo RPInfo(EffectiveRT.TargetableTexture, ERenderTargetActions::DontLoad_Store, nullptr, 0, CubeFace);
  486. RHICmdList.BeginRenderPass(RPInfo, TEXT("CopyDiffuseIrradianceRP"));
  487. RHICmdList.ApplyCachedRenderTargets(GraphicsPSOInit);
  488. const FIntRect ViewRect(0, 0, MipSize, MipSize);
  489. RHICmdList.SetViewport(0.0f, 0.0f, 0.0f, (float)MipSize, (float)MipSize, 1.0f);
  490. TShaderMapRef<FCopyDiffuseIrradiancePS> PixelShader(ShaderMap);
  491. TShaderMapRef<FScreenVS> VertexShader(GetGlobalShaderMap(FeatureLevel));
  492. GraphicsPSOInit.BoundShaderState.VertexDeclarationRHI = GFilterVertexDeclaration.VertexDeclarationRHI;
  493. GraphicsPSOInit.BoundShaderState.VertexShaderRHI = VertexShader.GetVertexShader();
  494. GraphicsPSOInit.BoundShaderState.PixelShaderRHI = PixelShader.GetPixelShader();
  495. GraphicsPSOInit.PrimitiveType = PT_TriangleList;
  496. SetGraphicsPipelineState(RHICmdList, GraphicsPSOInit);
  497. PixelShader->SetParameters(RHICmdList, CubeFace, LightingSourceMipIndex, CoefficientIndex, MipSize, LightingSource);
  498. DrawRectangle(
  499. RHICmdList,
  500. ViewRect.Min.X, ViewRect.Min.Y,
  501. ViewRect.Width(), ViewRect.Height(),
  502. ViewRect.Min.X, ViewRect.Min.Y,
  503. ViewRect.Width(), ViewRect.Height(),
  504. FIntPoint(ViewRect.Width(), ViewRect.Height()),
  505. FIntPoint(MipSize, MipSize),
  506. VertexShader);
  507. RHICmdList.EndRenderPass();
  508. }
  509. RHICmdList.Transition(FRHITransitionInfo(EffectiveRT.TargetableTexture, ERHIAccess::RTV, ERHIAccess::SRVGraphics));
  510. }
  511. const int32 NumMips = FMath::CeilLogTwo(GDiffuseIrradianceCubemapSize) + 1;
  512. {
  513. // Accumulate all the texel values through downsampling to 1x1 mip
  514. for (int32 MipIndex = 1; MipIndex < NumMips; MipIndex++)
  515. {
  516. const int32 SourceMipIndex = FMath::Max(MipIndex - 1, 0);
  517. const int32 MipSize = 1 << (NumMips - MipIndex - 1);
  518. FSceneRenderTargetItem& EffectiveRT = GetEffectiveDiffuseIrradianceRenderTarget(SceneContext, MipIndex);
  519. FSceneRenderTargetItem& EffectiveSource = GetEffectiveDiffuseIrradianceSourceTexture(SceneContext, MipIndex);
  520. check(EffectiveRT.TargetableTexture != EffectiveSource.ShaderResourceTexture);
  521. RHICmdList.Transition(FRHITransitionInfo(EffectiveRT.TargetableTexture, ERHIAccess::Unknown, ERHIAccess::RTV));
  522. for (int32 CubeFace = 0; CubeFace < CubeFace_MAX; CubeFace++)
  523. {
  524. FRHIRenderPassInfo RPInfo(EffectiveRT.TargetableTexture, ERenderTargetActions::Load_Store, nullptr, MipIndex, CubeFace);
  525. RHICmdList.BeginRenderPass(RPInfo, TEXT("AccumulateDiffuseIrradianceRP"));
  526. RHICmdList.ApplyCachedRenderTargets(GraphicsPSOInit);
  527. const FIntRect ViewRect(0, 0, MipSize, MipSize);
  528. RHICmdList.SetViewport(0.0f, 0.0f, 0.0f, (float)MipSize, (float)MipSize, 1.0f);
  529. TShaderMapRef<FAccumulateDiffuseIrradiancePS> PixelShader(ShaderMap);
  530. TShaderMapRef<FScreenVS> VertexShader(GetGlobalShaderMap(FeatureLevel));
  531. GraphicsPSOInit.BoundShaderState.VertexDeclarationRHI = GFilterVertexDeclaration.VertexDeclarationRHI;
  532. GraphicsPSOInit.BoundShaderState.VertexShaderRHI = VertexShader.GetVertexShader();
  533. GraphicsPSOInit.BoundShaderState.PixelShaderRHI = PixelShader.GetPixelShader();
  534. GraphicsPSOInit.PrimitiveType = PT_TriangleList;
  535. SetGraphicsPipelineState(RHICmdList, GraphicsPSOInit);
  536. PixelShader->SetParameters(RHICmdList, CubeFace, NumMips, SourceMipIndex, CoefficientIndex, EffectiveSource.ShaderResourceTexture);
  537. DrawRectangle(
  538. RHICmdList,
  539. ViewRect.Min.X, ViewRect.Min.Y,
  540. ViewRect.Width(), ViewRect.Height(),
  541. ViewRect.Min.X, ViewRect.Min.Y,
  542. ViewRect.Width(), ViewRect.Height(),
  543. FIntPoint(ViewRect.Width(), ViewRect.Height()),
  544. FIntPoint(MipSize, MipSize),
  545. VertexShader);
  546. RHICmdList.EndRenderPass();
  547. }
  548. RHICmdList.Transition(FRHITransitionInfo(EffectiveRT.TargetableTexture, ERHIAccess::RTV, ERHIAccess::SRVGraphics));
  549. }
  550. }
  551. {
  552. // Gather the cubemap face results and normalize, copy this coefficient to FSceneRenderTargets::Get(RHICmdList).SkySHIrradianceMap
  553. FSceneRenderTargetItem& EffectiveRT = FSceneRenderTargets::Get(RHICmdList).SkySHIrradianceMap->GetRenderTargetItem();
  554. //load/store actions so we don't lose results as we render one pixel at a time on tile renderers.
  555. RHICmdList.Transition(FRHITransitionInfo(EffectiveRT.TargetableTexture, ERHIAccess::Unknown, ERHIAccess::RTV));
  556. FRHIRenderPassInfo RPInfo(EffectiveRT.TargetableTexture, ERenderTargetActions::Load_Store, nullptr);
  557. RHICmdList.BeginRenderPass(RPInfo, TEXT("GatherCoeffRP"));
  558. RHICmdList.ApplyCachedRenderTargets(GraphicsPSOInit);
  559. const FIntRect ViewRect(CoefficientIndex, 0, CoefficientIndex + 1, 1);
  560. RHICmdList.SetViewport(0.0f, 0.0f, 0.0f, (float)FSHVector3::MaxSHBasis, 1.0f, 1.0f);
  561. TShaderMapRef<FScreenVS> VertexShader(ShaderMap);
  562. TShaderMapRef<FAccumulateCubeFacesPS> PixelShader(ShaderMap);
  563. GraphicsPSOInit.BoundShaderState.VertexDeclarationRHI = GFilterVertexDeclaration.VertexDeclarationRHI;
  564. GraphicsPSOInit.BoundShaderState.VertexShaderRHI = VertexShader.GetVertexShader();
  565. GraphicsPSOInit.BoundShaderState.PixelShaderRHI = PixelShader.GetPixelShader();
  566. GraphicsPSOInit.PrimitiveType = PT_TriangleList;
  567. SetGraphicsPipelineState(RHICmdList, GraphicsPSOInit);
  568. const int32 SourceMipIndex = NumMips - 1;
  569. const int32 MipSize = 1;
  570. FSceneRenderTargetItem& EffectiveSource = GetEffectiveDiffuseIrradianceRenderTarget(SceneContext, SourceMipIndex);
  571. PixelShader->SetParameters(RHICmdList, SourceMipIndex, EffectiveSource.ShaderResourceTexture);
  572. DrawRectangle(
  573. RHICmdList,
  574. ViewRect.Min.X, ViewRect.Min.Y,
  575. ViewRect.Width(), ViewRect.Height(),
  576. 0, 0,
  577. MipSize, MipSize,
  578. FIntPoint(FSHVector3::MaxSHBasis, 1),
  579. FIntPoint(MipSize, MipSize),
  580. VertexShader);
  581. RHICmdList.EndRenderPass();
  582. RHICmdList.Transition(FRHITransitionInfo(EffectiveRT.TargetableTexture, ERHIAccess::RTV, ERHIAccess::SRVGraphics));
  583. }
  584. }
  585. {
  586. // Read back the completed SH environment map
  587. FSceneRenderTargetItem& EffectiveRT = FSceneRenderTargets::Get(RHICmdList).SkySHIrradianceMap->GetRenderTargetItem();
  588. check(EffectiveRT.ShaderResourceTexture->GetFormat() == PF_FloatRGBA);
  589. TArray<FFloat16Color> SurfaceData;
  590. RHICmdList.ReadSurfaceFloatData(EffectiveRT.ShaderResourceTexture, FIntRect(0, 0, FSHVector3::MaxSHBasis, 1), SurfaceData, CubeFace_PosX, 0, 0);
  591. check(SurfaceData.Num() == FSHVector3::MaxSHBasis);
  592. for (int32 CoefficientIndex = 0; CoefficientIndex < FSHVector3::MaxSHBasis; CoefficientIndex++)
  593. {
  594. const FLinearColor CoefficientValue(SurfaceData[CoefficientIndex]);
  595. OutIrradianceEnvironmentMap->R.V[CoefficientIndex] = CoefficientValue.R;
  596. OutIrradianceEnvironmentMap->G.V[CoefficientIndex] = CoefficientValue.G;
  597. OutIrradianceEnvironmentMap->B.V[CoefficientIndex] = CoefficientValue.B;
  598. }
  599. }
  600. }
  601. D:\\UnrealEngine426\\Engine\\Shaders\\Private\\ReflectionEnvironmentShaders.usf
  602. 1. float4 CoefficientMask0;
  603. float4 CoefficientMask1;
  604. float CoefficientMask2;
  605. int NumSamples;
  606. void DiffuseIrradianceCopyPS(
  607. FScreenVertexOutput Input,
  608. out float4 OutColor : SV_Target0
  609. )
  610. {
  611. float2 ScaledUVs = Input.UV * 2 - 1;
  612. float3 CubeCoordinates = normalize(GetCubemapVector(ScaledUVs, CubeFace));
  613. float SquaredUVs = 1 + dot(ScaledUVs, ScaledUVs);
  614. // Dividing by NumSamples here to keep the sum in the range of fp16, once we get down to the 1x1 mip
  615. float TexelWeight = 4 / (sqrt(SquaredUVs) * SquaredUVs);
  616. FThreeBandSHVector SHCoefficients = SHBasisFunction3(CubeCoordinates);
  617. float CurrentSHCoefficient = dot(SHCoefficients.V0, CoefficientMask0) + dot(SHCoefficients.V1, CoefficientMask1) + SHCoefficients.V2 * CoefficientMask2;
  618. float3 TexelLighting = SampleCubemap(CubeCoordinates).rgb;
  619. OutColor = float4(TexelLighting * CurrentSHCoefficient * TexelWeight, TexelWeight);
  620. }
  621. float4 Sample01;
  622. float4 Sample23;
  623. void DiffuseIrradianceAccumulatePS(
  624. FScreenVertexOutput Input,
  625. out float4 OutColor : SV_Target0
  626. )
  627. {
  628. float4 AccumulatedValue = 0;
  629. {
  630. float2 ScaledUVs = saturate(Input.UV + Sample01.xy) * 2 - 1;
  631. float3 CubeCoordinates = GetCubemapVector(ScaledUVs, CubeFace);
  632. AccumulatedValue += SampleCubemap(CubeCoordinates);
  633. }
  634. {
  635. float2 ScaledUVs = saturate(Input.UV + Sample01.zw) * 2 - 1;
  636. float3 CubeCoordinates = GetCubemapVector(ScaledUVs, CubeFace);
  637. AccumulatedValue += SampleCubemap(CubeCoordinates);
  638. }
  639. {
  640. float2 ScaledUVs = saturate(Input.UV + Sample23.xy) * 2 - 1;
  641. float3 CubeCoordinates = GetCubemapVector(ScaledUVs, CubeFace);
  642. AccumulatedValue += SampleCubemap(CubeCoordinates);
  643. }
  644. {
  645. float2 ScaledUVs = saturate(Input.UV + Sample23.zw) * 2 - 1;
  646. float3 CubeCoordinates = GetCubemapVector(ScaledUVs, CubeFace);
  647. AccumulatedValue += SampleCubemap(CubeCoordinates);
  648. }
  649. OutColor = float4(AccumulatedValue.rgb / 4.0f, AccumulatedValue.a / 4.0f);
  650. }
  651. void AccumulateCubeFacesPS(
  652. FScreenVertexOutput Input,
  653. out float4 OutColor : SV_Target0
  654. )
  655. {
  656. float4 AccumulatedValue;
  657. AccumulatedValue = TextureCubeSampleLevel(SourceCubemapTexture, SourceCubemapSampler, float3(1, 0, 0), SourceMipIndex);
  658. AccumulatedValue += TextureCubeSampleLevel(SourceCubemapTexture, SourceCubemapSampler, float3(-1, 0, 0), SourceMipIndex);
  659. AccumulatedValue += TextureCubeSampleLevel(SourceCubemapTexture, SourceCubemapSampler, float3(0, 1, 0), SourceMipIndex);
  660. AccumulatedValue += TextureCubeSampleLevel(SourceCubemapTexture, SourceCubemapSampler, float3(0, -1, 0), SourceMipIndex);
  661. AccumulatedValue += TextureCubeSampleLevel(SourceCubemapTexture, SourceCubemapSampler, float3(0, 0, 1), SourceMipIndex);
  662. AccumulatedValue += TextureCubeSampleLevel(SourceCubemapTexture, SourceCubemapSampler, float3(0, 0, -1), SourceMipIndex);
  663. OutColor = float4(4 * PI * AccumulatedValue.rgb / ( max(AccumulatedValue.a, .00001f)), 0);
  664. }
  665. D:\\UnrealEngine426\\Engine\\Shaders\\Private\\SHCommon.ush
  666. 2. FThreeBandSHVector SHBasisFunction3(half3 InputVector)
  667. {
  668. FThreeBandSHVector Result;
  669. // These are derived from simplifying SHBasisFunction in C++
  670. Result.V0.x = 0.282095f;
  671. Result.V0.y = -0.488603f * InputVector.y;
  672. Result.V0.z = 0.488603f * InputVector.z;
  673. Result.V0.w = -0.488603f * InputVector.x;
  674. half3 VectorSquared = InputVector * InputVector;
  675. Result.V1.x = 1.092548f * InputVector.x * InputVector.y;
  676. Result.V1.y = -1.092548f * InputVector.y * InputVector.z;
  677. Result.V1.z = 0.315392f * (3.0f * VectorSquared.z - 1.0f);
  678. Result.V1.w = -1.092548f * InputVector.x * InputVector.z;
  679. Result.V2 = 0.546274f * (VectorSquared.x - VectorSquared.y);
  680. return Result;
  681. }
  682. 2. FilterCubeMap()
  683. 1. void FilterCubeMap(FRHICommandListImmediate& RHICmdList, ERHIFeatureLevel::Type FeatureLevel, int32 NumMips,
  684. FSceneRenderTargetItem& DownSampledCube, FSceneRenderTargetItem& FilteredCube)
  685. {
  686. SCOPED_DRAW_EVENT(RHICmdList, FilterCubeMap);
  687. auto ShaderMap = GetGlobalShaderMap(FeatureLevel);
  688. FGraphicsPipelineStateInitializer GraphicsPSOInit;
  689. GraphicsPSOInit.RasterizerState = TStaticRasterizerState<FM_Solid, CM_None>::GetRHI();
  690. GraphicsPSOInit.DepthStencilState = TStaticDepthStencilState<false, CF_Always>::GetRHI();
  691. GraphicsPSOInit.BlendState = TStaticBlendState<>::GetRHI();
  692. RHICmdList.Transition(FRHITransitionInfo(FilteredCube.TargetableTexture, ERHIAccess::Unknown, ERHIAccess::RTV));
  693. // Filter all the mips
  694. for (int32 MipIndex = 0; MipIndex < NumMips; MipIndex++)
  695. {
  696. const int32 MipSize = 1 << (NumMips - MipIndex - 1);
  697. for (int32 CubeFace = 0; CubeFace < CubeFace_MAX; CubeFace++)
  698. {
  699. FRHIRenderPassInfo RPInfo(FilteredCube.TargetableTexture, ERenderTargetActions::DontLoad_Store, nullptr, MipIndex, CubeFace);
  700. RHICmdList.Transition(FRHITransitionInfo(FilteredCube.TargetableTexture, ERHIAccess::Unknown, ERHIAccess::RTV));
  701. RHICmdList.BeginRenderPass(RPInfo, TEXT("FilterMips"));
  702. RHICmdList.ApplyCachedRenderTargets(GraphicsPSOInit);
  703. const FIntRect ViewRect(0, 0, MipSize, MipSize);
  704. RHICmdList.SetViewport(0, 0, 0.0f, MipSize, MipSize, 1.0f);
  705. //TShaderMapRef<TCubeFilterPS<1>> CaptureCubemapArrayPixelShader(GetGlobalShaderMap(FeatureLevel));
  706. TShaderMapRef<FScreenVS> VertexShader(GetGlobalShaderMap(FeatureLevel));
  707. TShaderMapRef<TCubeFilterPS<0>> PixelShader(GetGlobalShaderMap(FeatureLevel));
  708. GraphicsPSOInit.BoundShaderState.VertexShaderRHI = VertexShader.GetVertexShader();
  709. GraphicsPSOInit.BoundShaderState.PixelShaderRHI = PixelShader.GetPixelShader();
  710. GraphicsPSOInit.BoundShaderState.VertexDeclarationRHI = GFilterVertexDeclaration.VertexDeclarationRHI;
  711. GraphicsPSOInit.PrimitiveType = PT_TriangleList;
  712. SetGraphicsPipelineState(RHICmdList, GraphicsPSOInit);
  713. {
  714. FRHIPixelShader* ShaderRHI = PixelShader.GetPixelShader();
  715. SetShaderValue(RHICmdList, ShaderRHI, PixelShader->CubeFace, CubeFace);
  716. SetShaderValue(RHICmdList, ShaderRHI, PixelShader->MipIndex, MipIndex);
  717. SetShaderValue(RHICmdList, ShaderRHI, PixelShader->NumMips, NumMips);
  718. SetTextureParameter(
  719. RHICmdList,
  720. ShaderRHI,
  721. PixelShader->SourceCubemapTexture,
  722. PixelShader->SourceCubemapSampler,
  723. TStaticSamplerState<SF_Trilinear, AM_Clamp, AM_Clamp, AM_Clamp>::GetRHI(),
  724. DownSampledCube.ShaderResourceTexture);
  725. }
  726. DrawRectangle(
  727. RHICmdList,
  728. ViewRect.Min.X, ViewRect.Min.Y,
  729. ViewRect.Width(), ViewRect.Height(),
  730. ViewRect.Min.X, ViewRect.Min.Y,
  731. ViewRect.Width(), ViewRect.Height(),
  732. FIntPoint(ViewRect.Width(), ViewRect.Height()),
  733. FIntPoint(MipSize, MipSize),
  734. VertexShader);
  735. RHICmdList.EndRenderPass();
  736. }
  737. }
  738. }
  739. D:\\UnrealEngine426\\Engine\\Shaders\\Private\\ReflectionEnvironmentShaders.usf
  740. 1. #ifdef USE_COMPUTE
  741. int CubeFaceOffset;
  742. [numthreads(THREADGROUP_SIZE, THREADGROUP_SIZE, 1)]
  743. void FilterCS(uint3 ThreadId : SV_DispatchThreadID)
  744. {
  745. const uint2 FaceCoord = uint2(ThreadId.x % uint(FaceThreadGroupSize), ThreadId.y);
  746. if (any(FaceCoord >= uint2(ValidDispatchCoord)))
  747. {
  748. return;
  749. }
  750. const int SelectedCubeFace = CubeFaceOffset + int(ThreadId.x) / FaceThreadGroupSize;
  751. float2 ScaledUVs = ((float2(FaceCoord) + 0.5f) / float2(ValidDispatchCoord)) * 2.0f - 1.0f;
  752. float4 OutColor;
  753. #else // USE_COMPUTE
  754. void FilterPS(
  755. FScreenVertexOutput Input,
  756. out float4 OutColor : SV_Target0
  757. )
  758. {
  759. float2 ScaledUVs = Input.UV * 2 - 1;
  760. const int SelectedCubeFace = CubeFace;
  761. #endif // USE_COMPUTE
  762. float3 CubeCoordinates = GetCubemapVector(ScaledUVs, SelectedCubeFace);
  763. float3 N = normalize(CubeCoordinates);
  764. float3x3 TangentToWorld = GetTangentBasis( N );
  765. float Roughness = ComputeReflectionCaptureRoughnessFromMip( MipIndex, NumMips - 1 );
  766. if( Roughness < 0.01 )
  767. {
  768. OutColor = SourceCubemapTexture.SampleLevel(SourceCubemapSampler, CubeCoordinates, 0 );
  769. #ifdef USE_COMPUTE
  770. OutTextureMipColor[uint3(FaceCoord, SelectedCubeFace)] = OutColor;
  771. #endif
  772. return;
  773. }
  774. uint CubeSize = 1 << ( NumMips - 1 );
  775. const float SolidAngleTexel = 4*PI / ( 6 * CubeSize * CubeSize ) * 2;
  776. //const uint NumSamples = 1024;
  777. const uint NumSamples = Roughness < 0.1 ? 32 : 64;
  778. float4 FilteredColor = 0;
  779. BRANCH
  780. if( Roughness > 0.99 )
  781. {
  782. // Roughness=1, GGX is constant. Use cosine distribution instead
  783. LOOP
  784. for( uint i = 0; i < NumSamples; i++ )
  785. {
  786. float2 E = Hammersley( i, NumSamples, 0 );
  787. float3 L = CosineSampleHemisphere( E ).xyz;
  788. float NoL = L.z;
  789. float PDF = NoL / PI;
  790. float SolidAngleSample = 1.0 / ( NumSamples * PDF );
  791. float Mip = 0.5 * log2( SolidAngleSample / SolidAngleTexel );
  792. L = mul( L, TangentToWorld );
  793. FilteredColor += SourceCubemapTexture.SampleLevel(SourceCubemapSampler, L, Mip );
  794. }
  795. OutColor = FilteredColor / NumSamples;
  796. }
  797. else
  798. {
  799. float Weight = 0;
  800. LOOP
  801. for( uint i = 0; i < NumSamples; i++ )
  802. {
  803. float2 E = Hammersley( i, NumSamples, 0 );
  804. // 6x6 Offset rows. Forms uniform star pattern
  805. //uint2 Index = uint2( i % 6, i / 6 );
  806. //float2 E = ( Index + 0.5 ) / 5.8;
  807. //E.x = frac( E.x + (Index.y & 1) * (0.5 / 6.0) );
  808. E.y *= 0.995;
  809. float3 H = ImportanceSampleGGX( E, Pow4(Roughness) ).xyz;
  810. float3 L = 2 * H.z * H - float3(0,0,1);
  811. float NoL = L.z;
  812. float NoH = H.z;
  813. if( NoL > 0 )
  814. {
  815. //float TexelWeight = CubeTexelWeight( L );
  816. //float SolidAngleTexel = SolidAngleAvgTexel * TexelWeight;
  817. //float PDF = D_GGX( Pow4(Roughness), NoH ) * NoH / (4 * VoH);
  818. float PDF = D_GGX( Pow4(Roughness), NoH ) * 0.25;
  819. float SolidAngleSample = 1.0 / ( NumSamples * PDF );
  820. float Mip = 0.5 * log2( SolidAngleSample / SolidAngleTexel );
  821. float ConeAngle = acos( 1 - SolidAngleSample / (2*PI) );
  822. L = mul( L, TangentToWorld );
  823. FilteredColor += SourceCubemapTexture.SampleLevel(SourceCubemapSampler, L, Mip ) * NoL;
  824. Weight += NoL;
  825. }
  826. }
  827. OutColor = FilteredColor / Weight;
  828. }
  829. #ifdef USE_COMPUTE
  830. OutTextureMipColor[uint3(FaceCoord, SelectedCubeFace)] = OutColor;
  831. #endif
  832. }
  833. D:\\UnrealEngine426\\Engine\\Shaders\\Private\\MonteCarlo.ush
  834. 1. float2 Hammersley( uint Index, uint NumSamples, uint2 Random )
  835. {
  836. float E1 = frac( (float)Index / NumSamples + float( Random.x & 0xffff ) / (1<<16) );
  837. float E2 = float( ReverseBits32(Index) ^ Random.y ) * 2.3283064365386963e-10;
  838. return float2( E1, E2 );
  839. }
  840. float4 CosineSampleHemisphere( float2 E )
  841. {
  842. float Phi = 2 * PI * E.x;
  843. float CosTheta = sqrt( E.y );
  844. float SinTheta = sqrt( 1 - CosTheta * CosTheta );
  845. float3 H;
  846. H.x = SinTheta * cos( Phi );
  847. H.y = SinTheta * sin( Phi );
  848. H.z = CosTheta;
  849. float PDF = CosTheta * (1.0 / PI);
  850. return float4( H, PDF );
  851. }
  852. float4 ImportanceSampleGGX( float2 E, float a2 )
  853. {
  854. float Phi = 2 * PI * E.x;
  855. float CosTheta = sqrt( (1 - E.y) / ( 1 + (a2 - 1) * E.y ) );
  856. float SinTheta = sqrt( 1 - CosTheta * CosTheta );
  857. float3 H;
  858. H.x = SinTheta * cos( Phi );
  859. H.y = SinTheta * sin( Phi );
  860. H.z = CosTheta;
  861. float d = ( CosTheta * a2 - CosTheta ) * CosTheta + 1;
  862. float D = a2 / ( PI*d*d );
  863. float PDF = D * CosTheta;
  864. return float4( H, PDF );
  865. }
  866. 2. D:\\UnrealEngine426\\Engine\\Shaders\\Private\\BRDF.ush
  867. 1. // GGX / Trowbridge-Reitz
  868. // [Walter et al. 2007, "Microfacet models for refraction through rough surfaces"]
  869. float D_GGX( float a2, float NoH )
  870. {
  871. float d = ( NoH * a2 - NoH ) * NoH + 1; // 2 mad
  872. return a2 / ( PI*d*d ); // 4 mul, 1 rcp
  873. }

发表评论

表情:
评论列表 (有 0 条评论,337人围观)

还没有评论,来说两句吧...

相关阅读

    相关 UE4 SkyLight 记录

    背景: 想了解一下,UE4如何使用HDR图,作为环境光,官方有个插件HDRIBackdrop,主要就是使用SkyLight进行,因此重点看了一下SkyLight,记录一下。