UE4 SkyLight 记录

背景:

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

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

流程:

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

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

    1. FAutoConsoleCommandWithWorld CaptureConsoleCommand(
      	TEXT("r.SkylightRecapture"),
      	TEXT("Updates all stationary and movable skylights, useful for debugging the capture pipeline"),
      	FConsoleCommandWithWorldDelegate::CreateStatic(OnUpdateSkylights)
      	);

    2. void OnUpdateSkylights(UWorld* InWorld)
      {
      	for (TObjectIterator<USkyLightComponent> It; It; ++It)
      	{
      		USkyLightComponent* SkylightComponent = *It;
      		if (InWorld->ContainsActor(SkylightComponent->GetOwner()) && !SkylightComponent->IsPendingKill())
      		{			
      			SkylightComponent->SetCaptureIsDirty();			
      		}
      	}
      	USkyLightComponent::UpdateSkyCaptureContents(InWorld);
      }

    3. void USkyLightComponent::UpdateSkyCaptureContents(UWorld* WorldToUpdate)
      {
      	if (WorldToUpdate->Scene)
      	{
      		QUICK_SCOPE_CYCLE_COUNTER(STAT_SkylightCaptures);
      
      		if (GUpdateSkylightsEveryFrame)
      		{
      			for (TObjectIterator<USkyLightComponent> It; It; ++It)
      			{
      				USkyLightComponent* SkylightComponent = *It;
      				if (WorldToUpdate->ContainsActor(SkylightComponent->GetOwner()) && !SkylightComponent->IsPendingKill())
      				{			
      					SkylightComponent->SetCaptureIsDirty();			
      				}
      			}
      		}
      
      		if (SkyCapturesToUpdate.Num() > 0)
      		{
      			FScopeLock Lock(&SkyCapturesToUpdateLock);
      			UpdateSkyCaptureContentsArray(WorldToUpdate, SkyCapturesToUpdate, true);
      		}
      		
      		if (SkyCapturesToUpdateBlendDestinations.Num() > 0)
      		{
      			UpdateSkyCaptureContentsArray(WorldToUpdate, SkyCapturesToUpdateBlendDestinations, false);
      		}
      	}
      }

    4. void USkyLightComponent::UpdateSkyCaptureContentsArray(UWorld* WorldToUpdate, TArray<USkyLightComponent*>& ComponentArray, bool bOperateOnBlendSource)
      {
      	const bool bIsCompilingShaders = GShaderCompilingManager != NULL && GShaderCompilingManager->IsCompiling();
      
      	// Iterate backwards so we can remove elements without changing the index
      	for (int32 CaptureIndex = ComponentArray.Num() - 1; CaptureIndex >= 0; CaptureIndex--)
      	{
      		USkyLightComponent* CaptureComponent = ComponentArray[CaptureIndex];
      		AActor* Owner = CaptureComponent->GetOwner();
      
      		if (((!Owner || !Owner->GetLevel() || Owner->GetLevel()->bIsVisible) && CaptureComponent->GetWorld() == WorldToUpdate)
      			// Only process sky capture requests once async shader compiling completes, otherwise we will capture the scene with temporary shaders
      			&& (!bIsCompilingShaders || CaptureComponent->SourceType == SLS_SpecifiedCubemap))
      		{
      			// Only capture valid sky light components
      			if (CaptureComponent->SourceType != SLS_SpecifiedCubemap || CaptureComponent->Cubemap)
      			{
      
      #if WITH_EDITOR
      				FStaticLightingSystemInterface::OnLightComponentUnregistered.Broadcast(CaptureComponent);
      #endif
      
      				if (bOperateOnBlendSource)
      				{
      					ensure(!CaptureComponent->ProcessedSkyTexture || CaptureComponent->ProcessedSkyTexture->GetSizeX() == CaptureComponent->ProcessedSkyTexture->GetSizeY());
      
      					// Allocate the needed texture on first capture
      					if (!CaptureComponent->ProcessedSkyTexture || CaptureComponent->ProcessedSkyTexture->GetSizeX() != CaptureComponent->CubemapResolution)
      					{
      						CaptureComponent->ProcessedSkyTexture = new FSkyTextureCubeResource();
      						CaptureComponent->ProcessedSkyTexture->SetupParameters(CaptureComponent->CubemapResolution, FMath::CeilLogTwo(CaptureComponent->CubemapResolution) + 1, SKYLIGHT_CUBEMAP_FORMAT);
      						BeginInitResource(CaptureComponent->ProcessedSkyTexture);
      						CaptureComponent->MarkRenderStateDirty();
      					}
      
      					WorldToUpdate->Scene->UpdateSkyCaptureContents(CaptureComponent, CaptureComponent->bCaptureEmissiveOnly, CaptureComponent->Cubemap, CaptureComponent->ProcessedSkyTexture, CaptureComponent->AverageBrightness, CaptureComponent->IrradianceEnvironmentMap, NULL);
      					CaptureComponent->UpdateImportanceSamplingData();
      				}
      				else
      				{
      					ensure(!CaptureComponent->BlendDestinationProcessedSkyTexture || CaptureComponent->BlendDestinationProcessedSkyTexture->GetSizeX() == CaptureComponent->BlendDestinationProcessedSkyTexture->GetSizeY());
      
      					// Allocate the needed texture on first capture
      					if (!CaptureComponent->BlendDestinationProcessedSkyTexture || CaptureComponent->BlendDestinationProcessedSkyTexture->GetSizeX() != CaptureComponent->CubemapResolution)
      					{
      						CaptureComponent->BlendDestinationProcessedSkyTexture = new FSkyTextureCubeResource();
      						CaptureComponent->BlendDestinationProcessedSkyTexture->SetupParameters(CaptureComponent->CubemapResolution, FMath::CeilLogTwo(CaptureComponent->CubemapResolution) + 1, SKYLIGHT_CUBEMAP_FORMAT);
      						BeginInitResource(CaptureComponent->BlendDestinationProcessedSkyTexture);
      						CaptureComponent->MarkRenderStateDirty(); 
      					}
      
      					WorldToUpdate->Scene->UpdateSkyCaptureContents(CaptureComponent, CaptureComponent->bCaptureEmissiveOnly, CaptureComponent->BlendDestinationCubemap, CaptureComponent->BlendDestinationProcessedSkyTexture, CaptureComponent->BlendDestinationAverageBrightness, CaptureComponent->BlendDestinationIrradianceEnvironmentMap, NULL);
      					CaptureComponent->UpdateImportanceSamplingData();
      				}
      
      				CaptureComponent->IrradianceMapFence.BeginFence();
      				CaptureComponent->bHasEverCaptured = true;
      				CaptureComponent->MarkRenderStateDirty();
      
      #if WITH_EDITOR
      				FStaticLightingSystemInterface::OnLightComponentRegistered.Broadcast(CaptureComponent);
      #endif
      			}
      
      			// Only remove queued update requests if we processed it for the right world
      			ComponentArray.RemoveAt(CaptureIndex);
      		}
      	}
      }
  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(
      	const USkyLightComponent* CaptureComponent, 
      	bool bCaptureEmissiveOnly, 
      	UTextureCube* SourceCubemap, 
      	FTexture* OutProcessedTexture, 
      	float& OutAverageBrightness, 
      	FSHVectorRGB3& OutIrradianceEnvironmentMap,
      	TArray<FFloat16Color>* OutRadianceMap)
      {	
      	if (GSupportsRenderTargetFormat_PF_FloatRGBA || GetFeatureLevel() >= ERHIFeatureLevel::SM5)
      	{
      		QUICK_SCOPE_CYCLE_COUNTER(STAT_UpdateSkyCaptureContents);
      		{
      			World = GetWorld();
      			if (World)
      			{
      				//guarantee that all render proxies are up to date before kicking off this render
      				World->SendAllEndOfFrameUpdates();
      			}
      		}
      		{
      			int32 CubemapSize = CaptureComponent->CubemapResolution;
      			ENQUEUE_RENDER_COMMAND(ClearCommand)(
      				[CubemapSize](FRHICommandListImmediate& RHICmdList)
      				{
      					ClearScratchCubemaps(RHICmdList, CubemapSize);
      				});
      		}
      
      		if (CaptureComponent->SourceType == SLS_CapturedScene)
      		{
      			bool bStaticSceneOnly = CaptureComponent->Mobility == EComponentMobility::Static;
      			bool bCapturingForMobile = false;
      			CaptureSceneIntoScratchCubemap(this, CaptureComponent->GetComponentLocation(), CaptureComponent->CubemapResolution, true, bStaticSceneOnly, CaptureComponent->SkyDistanceThreshold, CaptureComponent->bLowerHemisphereIsBlack, bCaptureEmissiveOnly, CaptureComponent->LowerHemisphereColor, bCapturingForMobile);
      		}
      		else if (CaptureComponent->SourceType == SLS_SpecifiedCubemap)
      		{
      			int32 CubemapSize = CaptureComponent->CubemapResolution;
      			bool bLowerHemisphereIsBlack = CaptureComponent->bLowerHemisphereIsBlack;
      			float SourceCubemapRotation = CaptureComponent->SourceCubemapAngle * (PI / 180.f);
      			ERHIFeatureLevel::Type InnerFeatureLevel = FeatureLevel;
      			FLinearColor LowerHemisphereColor = CaptureComponent->LowerHemisphereColor;
      			ENQUEUE_RENDER_COMMAND(CopyCubemapCommand)(
      				[SourceCubemap, CubemapSize, bLowerHemisphereIsBlack, SourceCubemapRotation, InnerFeatureLevel, LowerHemisphereColor](FRHICommandListImmediate& RHICmdList)
      				{
      					CopyCubemapToScratchCubemap(RHICmdList, InnerFeatureLevel, SourceCubemap, CubemapSize, true, bLowerHemisphereIsBlack, SourceCubemapRotation, LowerHemisphereColor);
      				});
      		}
      		else if (CaptureComponent->IsRealTimeCaptureEnabled())
      		{
      			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."));
      			return;
      		}
      		else
      		{
      			check(0);
      		}
      
      		if (OutRadianceMap)
      		{
      			int32 CubemapSize = CaptureComponent->CubemapResolution;
      			ENQUEUE_RENDER_COMMAND(ReadbackCommand)(
      				[CubemapSize, OutRadianceMap](FRHICommandListImmediate& RHICmdList)
      				{
      					ReadbackRadianceMap(RHICmdList, CubemapSize, *OutRadianceMap);
      				});
      		}
      
      		{
      			int32 CubemapSize = CaptureComponent->CubemapResolution;
      			float* AverageBrightness = &OutAverageBrightness;
      			FSHVectorRGB3* IrradianceEnvironmentMap = &OutIrradianceEnvironmentMap;
      			ERHIFeatureLevel::Type InFeatureLevel = GetFeatureLevel();
      			ENQUEUE_RENDER_COMMAND(FilterCommand)(
      				[CubemapSize, AverageBrightness, IrradianceEnvironmentMap, InFeatureLevel](FRHICommandListImmediate& RHICmdList)
      				{
      					if (InFeatureLevel <= ERHIFeatureLevel::ES3_1)
      					{
      						MobileReflectionEnvironmentCapture::ComputeAverageBrightness(RHICmdList, InFeatureLevel, CubemapSize, *AverageBrightness);
      						MobileReflectionEnvironmentCapture::FilterReflectionEnvironment(RHICmdList, InFeatureLevel, CubemapSize, IrradianceEnvironmentMap);
      					}
      					else
      					{
      						ComputeAverageBrightness(RHICmdList, InFeatureLevel, CubemapSize, *AverageBrightness);
      						FilterReflectionEnvironment(RHICmdList, InFeatureLevel, CubemapSize, IrradianceEnvironmentMap);
      					}
      				});
      		}
      
      		// Optionally copy the filtered mip chain to the output texture
      		if (OutProcessedTexture)
      		{
      			FScene* Scene = this;
      			ERHIFeatureLevel::Type InFeatureLevel = GetFeatureLevel();
      			ENQUEUE_RENDER_COMMAND(CopyCommand)(
      				[Scene, OutProcessedTexture, InFeatureLevel](FRHICommandListImmediate& RHICmdList)
      				{
      					if (InFeatureLevel <= ERHIFeatureLevel::ES3_1)
      					{
      						MobileReflectionEnvironmentCapture::CopyToSkyTexture(RHICmdList, Scene, OutProcessedTexture);
      					}
      					else
      					{
      						CopyToSkyTexture(RHICmdList, Scene, OutProcessedTexture);
      					}
      				});
      		}
      
      		if (!!GFreeReflectionScratchAfterUse)
      		{
      			ENQUEUE_RENDER_COMMAND(FreeReflectionScratch)(
      				[](FRHICommandListImmediate& RHICmdList)
      			{
      				FSceneRenderTargets& SceneContext = FSceneRenderTargets::Get(RHICmdList);
      				SceneContext.FreeReflectionScratchRenderTargets();
      				GRenderTargetPool.FreeUnusedResources();
      			});
      		}
      	}
      }

    2. void CopyCubemapToScratchCubemap(FRHICommandListImmediate& RHICmdList, ERHIFeatureLevel::Type FeatureLevel, UTextureCube* SourceCubemap, int32 CubemapSize, bool bIsSkyLight, bool bLowerHemisphereIsBlack, float SourceCubemapRotation, const FLinearColor& LowerHemisphereColorValue)
      {
      	SCOPED_DRAW_EVENT(RHICmdList, CopyCubemapToScratchCubemap);
      	check(SourceCubemap);
      
      	const FTexture* SourceCubemapResource = SourceCubemap->Resource;
      	if (SourceCubemapResource == nullptr)
      	{
      		UE_LOG(LogEngine, Warning, TEXT("Unable to copy from cubemap %s, it's RHI resource is null"), *SourceCubemap->GetPathName());
      		return;
      	}
      
      	FSceneRenderTargets& SceneContext = FSceneRenderTargets::Get(RHICmdList);
      
      	FMemMark Mark(FMemStack::Get());
      	FRDGBuilder GraphBuilder(RHICmdList);
      
      	FRDGTextureRef OutputTexture = GraphBuilder.RegisterExternalTexture(SceneContext.ReflectionColorScratchCubemap[0], TEXT("ReflectionColorScratchCubemap"));
      
      	for (uint32 CubeFace = 0; CubeFace < CubeFace_MAX; CubeFace++)
      	{
      		auto* PassParameters = GraphBuilder.AllocParameters<FCopyCubemapToCubeFacePS::FParameters>();
      		PassParameters->RenderTargets[0] = FRenderTargetBinding(OutputTexture, ERenderTargetLoadAction::ENoAction, 0, CubeFace);
      		PassParameters->LowerHemisphereColor = LowerHemisphereColorValue;
      		PassParameters->SkyLightCaptureParameters = FVector(bIsSkyLight ? 1.0f : 0.0f, 0.0f, bLowerHemisphereIsBlack ? 1.0f : 0.0f);
      		PassParameters->SourceCubemapSampler = TStaticSamplerState<SF_Bilinear, AM_Clamp, AM_Clamp, AM_Clamp>::GetRHI();
      		PassParameters->SourceCubemapTexture = SourceCubemapResource->TextureRHI;
      		PassParameters->SinCosSourceCubemapRotation = FVector2D(FMath::Sin(SourceCubemapRotation), FMath::Cos(SourceCubemapRotation));
      		PassParameters->CubeFace = CubeFace;
      
      		const int32 EffectiveSize = CubemapSize;
      
      		GraphBuilder.AddPass(
      			RDG_EVENT_NAME("CopyCubemapToCubeFace"),
      			PassParameters,
      			ERDGPassFlags::Raster,
      			[EffectiveSize, &SceneContext, SourceCubemapResource, PassParameters, FeatureLevel](FRHICommandList& InRHICmdList)
      		{
      			const FIntPoint SourceDimensions(SourceCubemapResource->GetSizeX(), SourceCubemapResource->GetSizeY());
      			const FIntRect ViewRect(0, 0, EffectiveSize, EffectiveSize);
      			InRHICmdList.SetViewport(0.0f, 0.0f, 0.0f, (float)EffectiveSize, (float)EffectiveSize, 1.0f);
      
      			FGraphicsPipelineStateInitializer GraphicsPSOInit;
      			InRHICmdList.ApplyCachedRenderTargets(GraphicsPSOInit);
      			GraphicsPSOInit.RasterizerState = TStaticRasterizerState<FM_Solid, CM_None>::GetRHI();
      			GraphicsPSOInit.DepthStencilState = TStaticDepthStencilState<false, CF_Always>::GetRHI();
      			GraphicsPSOInit.BlendState = TStaticBlendState<>::GetRHI();
      
      			TShaderMapRef<FScreenVS> VertexShader(GetGlobalShaderMap(FeatureLevel));
      			TShaderMapRef<FCopyCubemapToCubeFacePS> PixelShader(GetGlobalShaderMap(FeatureLevel));
      
      			GraphicsPSOInit.BoundShaderState.VertexDeclarationRHI = GFilterVertexDeclaration.VertexDeclarationRHI;
      			GraphicsPSOInit.BoundShaderState.VertexShaderRHI = VertexShader.GetVertexShader();
      			GraphicsPSOInit.BoundShaderState.PixelShaderRHI = PixelShader.GetPixelShader();
      			GraphicsPSOInit.PrimitiveType = PT_TriangleList;
      
      			SetGraphicsPipelineState(InRHICmdList, GraphicsPSOInit);
      			SetShaderParameters(InRHICmdList, PixelShader, PixelShader.GetPixelShader(), *PassParameters);
      
      			DrawRectangle(
      				InRHICmdList,
      				ViewRect.Min.X, ViewRect.Min.Y,
      				ViewRect.Width(), ViewRect.Height(),
      				0, 0,
      				SourceDimensions.X, SourceDimensions.Y,
      				FIntPoint(ViewRect.Width(), ViewRect.Height()),
      				SourceDimensions,
      				VertexShader);
      		});
      	}
      
      	GraphBuilder.Execute();
      }

    3. class FCopyToCubeFaceShader : public FGlobalShader
      {
      public:
      	static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters)
      	{
      		return true;
      	}
      
      	FCopyToCubeFaceShader() = default;
      	FCopyToCubeFaceShader(const CompiledShaderInitializerType& Initializer)
      		: FGlobalShader(Initializer)
      	{}
      };
      
      /** Pixel shader used when copying a cubemap into a face of a reflection capture cubemap. */
      class FCopyCubemapToCubeFacePS : public FCopyToCubeFaceShader
      {
      public:
      	DECLARE_GLOBAL_SHADER(FCopyCubemapToCubeFacePS);
      	SHADER_USE_PARAMETER_STRUCT(FCopyCubemapToCubeFacePS, FCopyToCubeFaceShader);
      
      	BEGIN_SHADER_PARAMETER_STRUCT(FParameters, )
      		SHADER_PARAMETER_TEXTURE(TextureCube, SourceCubemapTexture)
      		SHADER_PARAMETER_SAMPLER(SamplerState, SourceCubemapSampler)
      		SHADER_PARAMETER(FVector, SkyLightCaptureParameters)
      		SHADER_PARAMETER(int32, CubeFace)
      		SHADER_PARAMETER(FVector4, LowerHemisphereColor)
      		SHADER_PARAMETER(FVector2D, SinCosSourceCubemapRotation)
      		RENDER_TARGET_BINDING_SLOTS()
      	END_SHADER_PARAMETER_STRUCT()
      };
      
      IMPLEMENT_GLOBAL_SHADER(FCopyCubemapToCubeFacePS, "/Engine/Private/ReflectionEnvironmentShaders.usf", "CopyCubemapToCubeFaceColorPS", SF_Pixel);

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

        1. int CubeFace;
          
          float3 GetCubemapVector(float2 ScaledUVs, int InCubeFace)
          {
          	float3 CubeCoordinates;
          
          	//@todo - this could be a 3x3 matrix multiply
          	if (InCubeFace == 0)
          	{
          		CubeCoordinates = float3(1, -ScaledUVs.y, -ScaledUVs.x);
          	}
          	else if (InCubeFace == 1)
          	{
          		CubeCoordinates = float3(-1, -ScaledUVs.y, ScaledUVs.x);
          	}
          	else if (InCubeFace == 2)
          	{
          		CubeCoordinates = float3(ScaledUVs.x, 1, ScaledUVs.y);
          	}
          	else if (InCubeFace == 3)
          	{
          		CubeCoordinates = float3(ScaledUVs.x, -1, -ScaledUVs.y);
          	}
          	else if (InCubeFace == 4)
          	{
          		CubeCoordinates = float3(ScaledUVs.x, -ScaledUVs.y, 1);
          	}
          	else
          	{
          		CubeCoordinates = float3(-ScaledUVs.x, -ScaledUVs.y, -1);
          	}
          
          	return CubeCoordinates;
          }
          
          
          TextureCube SourceCubemapTexture;
          SamplerState SourceCubemapSampler;
          float2 SinCosSourceCubemapRotation;
          
          void CopyCubemapToCubeFaceColorPS(
          	FScreenVertexOutput Input,
          	out float4 OutColor : SV_Target0
          	)
          { 
          	float2 ScaledUVs = Input.UV * 2 - 1;
          	float3 CubeCoordinates = GetCubemapVector(ScaledUVs, CubeFace);
          	// Rotate around Z axis
          	CubeCoordinates.xy = float2(dot(CubeCoordinates.xy, float2(SinCosSourceCubemapRotation.y, -SinCosSourceCubemapRotation.x)), dot(CubeCoordinates.xy, SinCosSourceCubemapRotation));
          	OutColor = TextureCubeSampleLevel(SourceCubemapTexture, SourceCubemapSampler, CubeCoordinates, 0);
          
          	if (SkyLightCaptureParameters.x > 0)
          	{
          		// Assuming we're on a planet and no sky lighting is coming from below the horizon
          		// This is important to avoid leaking from below since we are integrating incoming lighting and shadowing separately
          		if (CubeCoordinates.z < 0 && SkyLightCaptureParameters.z >= 1)
          		{
          			OutColor.rgb = lerp(OutColor.rgb, LowerHemisphereColor.rgb, LowerHemisphereColor.a);
          		}
          	}
          
          	OutColor.a = 1;
          }

    4.  D:\UnrealEngine426\Engine\Source\Runtime\Engine\Public\ScreenRendering.h
      1. /**
         * A vertex shader for rendering a textured screen element.
         */
        class FScreenVS : public FGlobalShader
        {
        	DECLARE_EXPORTED_SHADER_TYPE(FScreenVS,Global,ENGINE_API);
        public:
        
        	static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters) { return true; }
        
        	FScreenVS(const ShaderMetaType::CompiledShaderInitializerType& Initializer):
        		FGlobalShader(Initializer)
        	{
        	}
        	FScreenVS() {}
        
        	void SetParameters(FRHICommandList& RHICmdList, FRHIUniformBuffer* ViewUniformBuffer)
        	{
        		FGlobalShader::SetParameters<FViewUniformShaderParameters>(RHICmdList, RHICmdList.GetBoundVertexShader(), ViewUniformBuffer);
        	}
        };

      2.  D:\UnrealEngine426\Engine\Source\Runtime\Engine\Private\ScreenRendering.cpp

        1. // Copyright Epic Games, Inc. All Rights Reserved.
          
          /*=============================================================================
          	ScreenRendering.cpp: Screen rendering implementation.
          =============================================================================*/
          
          #include "ScreenRendering.h"
          
          /** Vertex declaration for screen-space rendering. */
          TGlobalResource<FScreenVertexDeclaration> GScreenVertexDeclaration;
          
          // Shader implementations.
          IMPLEMENT_SHADER_TYPE(, FScreenPS, TEXT("/Engine/Private/ScreenPixelShader.usf"), TEXT("Main"), SF_Pixel);
          IMPLEMENT_SHADER_TYPE(,FScreenPSInvertAlpha,TEXT("/Engine/Private/ScreenPixelShader.usf"),TEXT("MainInvertAlpha"),SF_Pixel);
          IMPLEMENT_SHADER_TYPE(,FScreenPSsRGBSource, TEXT("/Engine/Private/ScreenPixelShader.usf"), TEXT("MainsRGBSource"), SF_Pixel);
          IMPLEMENT_SHADER_TYPE(,FScreenPSMipLevel, TEXT("/Engine/Private/ScreenPixelShader.usf"), TEXT("MainMipLevel"), SF_Pixel);
          IMPLEMENT_SHADER_TYPE(,FScreenPSsRGBSourceMipLevel, TEXT("/Engine/Private/ScreenPixelShader.usf"), TEXT("MainsRGBSourceMipLevel"), SF_Pixel);
          IMPLEMENT_SHADER_TYPE(,FScreenVS,TEXT("/Engine/Private/ScreenVertexShader.usf"),TEXT("Main"),SF_Vertex);
          IMPLEMENT_SHADER_TYPE(,FScreenPS_OSE,TEXT("/Engine/Private/ScreenPixelShaderOES.usf"),TEXT("Main"),SF_Pixel);
          

        2.  /Private/ScreenVertexShader.usf

          1. void Main(
            	float2 InPosition : ATTRIBUTE0,
            	float2 InUV       : ATTRIBUTE1,
            	out FScreenVertexOutput Output
            	)
            {
            	DrawRectangle( float4( InPosition, 0, 1 ), InUV, Output.Position, Output.UV);
            }

          2.  /Private/Common.ush

            1. /** Used for calculating vertex positions and UVs when drawing with DrawRectangle */
              void DrawRectangle(
              	in float4 InPosition,
              	in float2 InTexCoord,
              	out float4 OutPosition,
              	out float2 OutTexCoord)
              {
              	OutPosition = InPosition;
              	OutPosition.xy = -1.0f + 2.0f * (DrawRectangleParameters.PosScaleBias.zw + (InPosition.xy * DrawRectangleParameters.PosScaleBias.xy)) * DrawRectangleParameters.InvTargetSizeAndTextureSize.xy;
              	OutPosition.xy *= float2( 1, -1 );
              	OutTexCoord.xy = (DrawRectangleParameters.UVScaleBias.zw + (InTexCoord.xy * DrawRectangleParameters.UVScaleBias.xy)) * DrawRectangleParameters.InvTargetSizeAndTextureSize.zw;
              }

    5. D:\UnrealEngine426\Engine\Source\Runtime\Renderer\Private\PostProcess\SceneFilterRendering.h
      1. /**
         * Draws a quad with the given vertex positions and UVs in denormalized pixel/texel coordinates.
         * The platform-dependent mapping from pixels to texels is done automatically.
         * Note that the positions are affected by the current viewport.
         * NOTE: DrawRectangle should be used in the vertex shader to calculate the correct position and uv for vertices.
         * NOTE2: Assumes previously set PSO has PrimitiveType = PT_TriangleList
         *
         * X, Y							Position in screen pixels of the top left corner of the quad
         * SizeX, SizeY					Size in screen pixels of the quad
         * U, V							Position in texels of the top left corner of the quad's UV's
         * SizeU, SizeV					Size in texels of the quad's UV's
         * TargetSizeX, TargetSizeY		Size in screen pixels of the target surface
         * TextureSize                  Size in texels of the source texture
         * VertexShader					The vertex shader used for rendering
         * Flags						see EDrawRectangleFlags
         * InstanceCount				Number of instances of rectangle
         */
        extern RENDERER_API void DrawRectangle(
        	FRHICommandList& RHICmdList,
        	float X,
        	float Y,
        	float SizeX,
        	float SizeY,
        	float U,
        	float V,
        	float SizeU,
        	float SizeV,
        	FIntPoint TargetSize,
        	FIntPoint TextureSize,
        	const TShaderRef<FShader>& VertexShader,
        	EDrawRectangleFlags Flags = EDRF_Default,
        	uint32 InstanceCount = 1
        	);
        
        /** Uniform buffer for computing the vertex positional and UV adjustments in the vertex shader. */
        BEGIN_GLOBAL_SHADER_PARAMETER_STRUCT( FDrawRectangleParameters, RENDERER_API)
        	SHADER_PARAMETER( FVector4, PosScaleBias )
        	SHADER_PARAMETER( FVector4, UVScaleBias )
        	SHADER_PARAMETER( FVector4, InvTargetSizeAndTextureSize )
        END_GLOBAL_SHADER_PARAMETER_STRUCT()

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

        1. void DrawRectangle(
          	FRHICommandList& RHICmdList,
          	float X,
          	float Y,
          	float SizeX,
          	float SizeY,
          	float U,
          	float V,
          	float SizeU,
          	float SizeV,
          	FIntPoint TargetSize,
          	FIntPoint TextureSize,
          	const TShaderRef<FShader>& VertexShader,
          	EDrawRectangleFlags Flags,
          	uint32 InstanceCount
          )
          {
          	InternalDrawRectangle(RHICmdList, X, Y, SizeX, SizeY, U, V, SizeU, SizeV, TargetSize, TextureSize, VertexShader, Flags, InstanceCount);
          }
          
          template <typename TRHICommandList>
          static inline void InternalDrawRectangle(
          	TRHICommandList& RHICmdList,
          	float X,
          	float Y,
          	float SizeX,
          	float SizeY,
          	float U,
          	float V,
          	float SizeU,
          	float SizeV,
          	FIntPoint TargetSize,
          	FIntPoint TextureSize,
          	const TShaderRef<FShader>& VertexShader,
          	EDrawRectangleFlags Flags,
          	uint32 InstanceCount
          	)
          {
          	float ClipSpaceQuadZ = 0.0f;
          
          	DoDrawRectangleFlagOverride(Flags);
          
          	// triangle if extending to left and top of the given rectangle, if it's not left top of the viewport it can cause artifacts
          	if(X > 0.0f || Y > 0.0f)
          	{
          		// don't use triangle optimization
          		Flags = EDRF_Default;
          	}
          
          	// Set up vertex uniform parameters for scaling and biasing the rectangle.
          	// Note: Use DrawRectangle in the vertex shader to calculate the correct vertex position and uv.
          
          	FDrawRectangleParameters Parameters;
          	Parameters.PosScaleBias = FVector4(SizeX, SizeY, X, Y);
          	Parameters.UVScaleBias = FVector4(SizeU, SizeV, U, V);
          
          	Parameters.InvTargetSizeAndTextureSize = FVector4(
          		1.0f / TargetSize.X, 1.0f / TargetSize.Y,
          		1.0f / TextureSize.X, 1.0f / TextureSize.Y);
          
          	SetUniformBufferParameterImmediate(RHICmdList, VertexShader.GetVertexShader(), VertexShader->GetUniformBufferParameter<FDrawRectangleParameters>(), Parameters);
          
          	if(Flags == EDRF_UseTesselatedIndexBuffer)
          	{
          		// no vertex buffer needed as we compute it in VS
          		RHICmdList.SetStreamSource(0, NULL, 0);
          
          		RHICmdList.DrawIndexedPrimitive(
          			GTesselatedScreenRectangleIndexBuffer.IndexBufferRHI,
          			/*BaseVertexIndex=*/ 0,
          			/*MinIndex=*/ 0,
          			/*NumVertices=*/ GTesselatedScreenRectangleIndexBuffer.NumVertices(),
          			/*StartIndex=*/ 0,
          			/*NumPrimitives=*/ GTesselatedScreenRectangleIndexBuffer.NumPrimitives(),
          			/*NumInstances=*/ InstanceCount
          			);
          	}
          	else
          	{
          		if (Flags == EDRF_UseTriangleOptimization)
          		{
          			FPixelShaderUtils::DrawFullscreenTriangle(RHICmdList, InstanceCount);
          		}
          		else
          		{
          			FPixelShaderUtils::DrawFullscreenQuad(RHICmdList, InstanceCount);
          		}
          	}
          }

        2.  D:\UnrealEngine426\Engine\Source\Runtime\RenderCore\Private\PixelShaderUtils.cpp

          1. // static
            void FPixelShaderUtils::DrawFullscreenQuad(FRHICommandList& RHICmdList, uint32 InstanceCount)
            {
            	RHICmdList.SetStreamSource(0, GScreenRectangleVertexBuffer.VertexBufferRHI, 0);
            
            	RHICmdList.DrawIndexedPrimitive(
            		GScreenRectangleIndexBuffer.IndexBufferRHI,
            		/*BaseVertexIndex=*/ 0,
            		/*MinIndex=*/ 0,
            		/*NumVertices=*/ 4,
            		/*StartIndex=*/ 0,
            		/*NumPrimitives=*/ 2,
            		/*NumInstances=*/ InstanceCount);
            }

    6.  ComputeAverageBrightness()
      1. void ComputeAverageBrightness(FRHICommandListImmediate& RHICmdList, ERHIFeatureLevel::Type FeatureLevel, int32 CubmapSize, float& OutAverageBrightness)
        {
        	SCOPED_DRAW_EVENT(RHICmdList, ComputeAverageBrightness);
        
        	const int32 EffectiveTopMipSize = CubmapSize;
        	const int32 NumMips = FMath::CeilLogTwo(EffectiveTopMipSize) + 1;
        
        	// necessary to resolve the clears which touched all the mips.  scene rendering only resolves mip 0.
        	FullyResolveReflectionScratchCubes(RHICmdList);	
        
        	FSceneRenderTargetItem& DownSampledCube = FSceneRenderTargets::Get(RHICmdList).ReflectionColorScratchCubemap[0]->GetRenderTargetItem();
        	CreateCubeMips( RHICmdList, FeatureLevel, NumMips, DownSampledCube );
        
        	OutAverageBrightness = ComputeSingleAverageBrightnessFromCubemap(RHICmdList, FeatureLevel, CubmapSize, DownSampledCube);
        }

      2. 
        void CreateCubeMips( FRHICommandListImmediate& RHICmdList, ERHIFeatureLevel::Type FeatureLevel, int32 NumMips, FSceneRenderTargetItem& Cubemap )
        {	
        	SCOPED_DRAW_EVENT(RHICmdList, CreateCubeMips);
        
        	FRHITexture* CubeRef = Cubemap.TargetableTexture.GetReference();
        
        	auto* ShaderMap = GetGlobalShaderMap(FeatureLevel);
        
        	TArray<TPair<FRHITextureSRVCreateInfo, TRefCountPtr<FRHIShaderResourceView>>> SRVs;
        	SRVs.Empty(NumMips);
        
        	for (int32 MipIndex = 0; MipIndex < NumMips; MipIndex++)
        	{
        		FRHITextureSRVCreateInfo SRVDesc;
        		SRVDesc.MipLevel = MipIndex;
        		SRVs.Emplace(SRVDesc, RHICreateShaderResourceView(Cubemap.ShaderResourceTexture, SRVDesc));
        	}
        
        	FGraphicsPipelineStateInitializer GraphicsPSOInit;
        	GraphicsPSOInit.RasterizerState = TStaticRasterizerState<FM_Solid, CM_None>::GetRHI();
        	GraphicsPSOInit.DepthStencilState = TStaticDepthStencilState<false, CF_Always>::GetRHI();
        	GraphicsPSOInit.BlendState = TStaticBlendState<>::GetRHI();
        
        	// Downsample all the mips, each one reads from the mip above it
        	for (int32 MipIndex = 1; MipIndex < NumMips; MipIndex++)
        	{
        		// For the first iteration, we don't know what the previous state
        		// of the source mip was, but we *do* for all the other iterations...
        		ERHIAccess Previous = MipIndex == 1
        			? ERHIAccess::Unknown
        			: ERHIAccess::RTV;
        
        		FRHITransitionInfo Transitions[] =
        		{
        			// Make the source mip readable (SRVGraphics)
        			FRHITransitionInfo(CubeRef, Previous, ERHIAccess::SRVGraphics, EResourceTransitionFlags::None, uint32(MipIndex - 1)),
        
        			// Make the destination mip writable (RTV)
        			FRHITransitionInfo(CubeRef, ERHIAccess::Unknown, ERHIAccess::RTV, EResourceTransitionFlags::None, uint32(MipIndex))
        		};
        		RHICmdList.Transition(Transitions);
        
        		const int32 MipSize = 1 << (NumMips - MipIndex - 1);
        		SCOPED_DRAW_EVENT(RHICmdList, CreateCubeMipsPerFace);
        		for (int32 CubeFace = 0; CubeFace < CubeFace_MAX; CubeFace++)
        		{
        			FRHIRenderPassInfo RPInfo(Cubemap.TargetableTexture, ERenderTargetActions::DontLoad_Store, nullptr, MipIndex, CubeFace);
        			RHICmdList.BeginRenderPass(RPInfo, TEXT("CreateCubeMips"));
        			RHICmdList.ApplyCachedRenderTargets(GraphicsPSOInit);
        
        			const FIntRect ViewRect(0, 0, MipSize, MipSize);
        			RHICmdList.SetViewport(0.0f, 0.0f, 0.0f, (float)MipSize, (float)MipSize, 1.0f);
        
        
        			TShaderMapRef<FScreenVS> VertexShader(ShaderMap);
        			TShaderMapRef<FCubeFilterPS> PixelShader(ShaderMap);
        
        			GraphicsPSOInit.BoundShaderState.VertexDeclarationRHI = GFilterVertexDeclaration.VertexDeclarationRHI;
        			GraphicsPSOInit.BoundShaderState.VertexShaderRHI = VertexShader.GetVertexShader();
        			GraphicsPSOInit.BoundShaderState.PixelShaderRHI = PixelShader.GetPixelShader();
        			GraphicsPSOInit.PrimitiveType = PT_TriangleList;
        
        			SetGraphicsPipelineState(RHICmdList, GraphicsPSOInit);
        
        			{
        				FRHIPixelShader* ShaderRHI = PixelShader.GetPixelShader();
        
        				SetShaderValue(RHICmdList, ShaderRHI, PixelShader->CubeFace, CubeFace);
        				SetShaderValue(RHICmdList, ShaderRHI, PixelShader->MipIndex, MipIndex);
        
        				SetShaderValue(RHICmdList, ShaderRHI, PixelShader->NumMips, NumMips);
        
        				check(SRVs.IsValidIndex(MipIndex - 1) && SRVs[MipIndex - 1].Key.MipLevel == MipIndex - 1);
        				SetSRVParameter(RHICmdList, ShaderRHI, PixelShader->SourceCubemapTexture, SRVs[MipIndex - 1].Value);
        				SetSamplerParameter(RHICmdList, ShaderRHI, PixelShader->SourceCubemapSampler, TStaticSamplerState<SF_Bilinear, AM_Clamp, AM_Clamp, AM_Clamp>::GetRHI());
        			}
        
        			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.EndRenderPass();
        		}
        	}
        
        	RHICmdList.Transition(FRHITransitionInfo(CubeRef, ERHIAccess::Unknown, ERHIAccess::SRVMask));
        
        	SRVs.Empty();
        }

        1. void DownsamplePS(
          	FScreenVertexOutput Input,
          	out float4 OutColor : SV_Target0
          	)
          { 
          	float2 ScaledUVs = Input.UV * 2 - 1;
          	const int SelectedCubeFace = CubeFace;
          #endif // USE_COMPUTE
          	float3 CubeCoordinates = GetCubemapVector(ScaledUVs, SelectedCubeFace);
          
          	uint MipSize = 1 << ( NumMips - MipIndex - 1 );
          
          	float3 TangentZ = normalize( CubeCoordinates );
          	float3 TangentX = normalize( cross( GetCubemapVector( ScaledUVs + float2(0,1), SelectedCubeFace), TangentZ ) );
          	float3 TangentY = cross( TangentZ, TangentX );
          
          	const float SampleOffset = 2.0 * 2 / MipSize;
          
          	float2 Offsets[] =
          	{
          		float2(-1, -1) * 0.7,
          		float2( 1, -1) * 0.7,
          		float2(-1,  1) * 0.7,
          		float2( 1,  1) * 0.7,
          		
          		float2( 0, -1),
          		float2(-1,  0),
          		float2( 1,  0),
          		float2( 0,  1),
          	};
          
          	OutColor = SourceCubemapTexture.SampleLevel(SourceCubemapSampler, CubeCoordinates, 0 );
          
          	UNROLL
          	for( uint i = 0; i < 8; i++ )
          	{
          		float Weight = 0.375;
          
          		float3 SampleDir = CubeCoordinates;
          		SampleDir += TangentX * ( Offsets[i].x * SampleOffset );
          		SampleDir += TangentY * ( Offsets[i].y * SampleOffset );
          		OutColor += SourceCubemapTexture.SampleLevel(SourceCubemapSampler, SampleDir, 0 ) * Weight;
          	}
          
          	OutColor *= rcp( 1.0 + 1.0 + 2.0 );
          
          #ifdef USE_COMPUTE
          	OutTextureMipColor[uint3(FaceCoord, SelectedCubeFace)] = OutColor;
          #endif
          }

      3. /** Computes the average brightness of the given reflection capture and stores it in the scene. */
        float ComputeSingleAverageBrightnessFromCubemap(FRHICommandListImmediate& RHICmdList, ERHIFeatureLevel::Type FeatureLevel, int32 TargetSize, FSceneRenderTargetItem& Cubemap)
        {
        	SCOPED_DRAW_EVENT(RHICmdList, ComputeSingleAverageBrightnessFromCubemap);
        
        	TRefCountPtr<IPooledRenderTarget> ReflectionBrightnessTarget;
        	FPooledRenderTargetDesc Desc(FPooledRenderTargetDesc::Create2DDesc(FIntPoint(1, 1), PF_FloatRGBA, FClearValueBinding::None, TexCreate_None, TexCreate_RenderTargetable, false));
        	GRenderTargetPool.FindFreeElement(RHICmdList, Desc, ReflectionBrightnessTarget, TEXT("ReflectionBrightness"));
        
        	FTextureRHIRef& BrightnessTarget = ReflectionBrightnessTarget->GetRenderTargetItem().TargetableTexture;
        
        	FRHIRenderPassInfo RPInfo(BrightnessTarget, ERenderTargetActions::Load_Store);
        	TransitionRenderPassTargets(RHICmdList, RPInfo);
        	RHICmdList.BeginRenderPass(RPInfo, TEXT("ReflectionBrightness"));
        	{
        		FGraphicsPipelineStateInitializer GraphicsPSOInit;
        		RHICmdList.ApplyCachedRenderTargets(GraphicsPSOInit);
        		GraphicsPSOInit.RasterizerState = TStaticRasterizerState<FM_Solid, CM_None>::GetRHI();
        		GraphicsPSOInit.DepthStencilState = TStaticDepthStencilState<false, CF_Always>::GetRHI();
        		GraphicsPSOInit.BlendState = TStaticBlendState<>::GetRHI();
        
        		auto ShaderMap = GetGlobalShaderMap(FeatureLevel);
        		TShaderMapRef<FPostProcessVS> VertexShader(ShaderMap);
        		TShaderMapRef<FComputeBrightnessPS> PixelShader(ShaderMap);
        
        		GraphicsPSOInit.BoundShaderState.VertexDeclarationRHI = GFilterVertexDeclaration.VertexDeclarationRHI;
        		GraphicsPSOInit.BoundShaderState.VertexShaderRHI = VertexShader.GetVertexShader();
        		GraphicsPSOInit.BoundShaderState.PixelShaderRHI = PixelShader.GetPixelShader();
        		GraphicsPSOInit.PrimitiveType = PT_TriangleList;
        	
        		SetGraphicsPipelineState(RHICmdList, GraphicsPSOInit);
        
        		PixelShader->SetParameters(RHICmdList, TargetSize, Cubemap);
        
        		DrawRectangle(
        			RHICmdList,
        			0, 0,
        			1, 1,
        			0, 0,
        			1, 1,
        			FIntPoint(1, 1),
        			FIntPoint(1, 1),
        			VertexShader);
        	}
        	RHICmdList.EndRenderPass();
        	RHICmdList.CopyToResolveTarget(BrightnessTarget, BrightnessTarget, FResolveParams());
        
        	FSceneRenderTargetItem& EffectiveRT = ReflectionBrightnessTarget->GetRenderTargetItem();
        	check(EffectiveRT.ShaderResourceTexture->GetFormat() == PF_FloatRGBA);
        
        	TArray<FFloat16Color> SurfaceData;
        	RHICmdList.ReadSurfaceFloatData(EffectiveRT.ShaderResourceTexture, FIntRect(0, 0, 1, 1), SurfaceData, CubeFace_PosX, 0, 0);
        
        	// Shader outputs luminance to R
        	float AverageBrightness = SurfaceData[0].R.GetFloat();
        	return AverageBrightness;
        }
         
        1. int NumCaptureArrayMips;
          
          /** Cube map array of reflection captures. */
          TextureCube ReflectionEnvironmentColorTexture;
          SamplerState ReflectionEnvironmentColorSampler;
          
          #if COMPUTEBRIGHTNESS_PIXELSHADER
          
          void ComputeBrightnessMain(
          	in float4 UVAndScreenPos : TEXCOORD0, 
          	out float4 OutColor : SV_Target0
          	)
          { 
          	// Sample the 6 1x1 cube faces and average
          	float3 AverageColor = TextureCubeSampleLevel(ReflectionEnvironmentColorTexture, ReflectionEnvironmentColorSampler, float3(1, 0, 0), NumCaptureArrayMips - 1).rgb;
          	AverageColor += TextureCubeSampleLevel(ReflectionEnvironmentColorTexture, ReflectionEnvironmentColorSampler, float3(-1, 0, 0), NumCaptureArrayMips - 1).rgb;
          	AverageColor += TextureCubeSampleLevel(ReflectionEnvironmentColorTexture, ReflectionEnvironmentColorSampler, float3(0, 1, 0), NumCaptureArrayMips - 1).rgb;
          	AverageColor += TextureCubeSampleLevel(ReflectionEnvironmentColorTexture, ReflectionEnvironmentColorSampler, float3(0, -1, 0), NumCaptureArrayMips - 1).rgb;
          	AverageColor += TextureCubeSampleLevel(ReflectionEnvironmentColorTexture, ReflectionEnvironmentColorSampler, float3(0, 0, 1), NumCaptureArrayMips - 1).rgb;
          	AverageColor += TextureCubeSampleLevel(ReflectionEnvironmentColorTexture, ReflectionEnvironmentColorSampler, float3(0, 0, -1), NumCaptureArrayMips - 1).rgb;
          
          	OutColor = dot(AverageColor / 6, .3333f); 
          }
          
          #endif

    7.  FilterReflectionEnvironment()
      1. /** Generates mips for glossiness and filters the cubemap for a given reflection. */
        void FilterReflectionEnvironment(FRHICommandListImmediate& RHICmdList, ERHIFeatureLevel::Type FeatureLevel, int32 CubmapSize, FSHVectorRGB3* OutIrradianceEnvironmentMap)
        {
        	SCOPED_DRAW_EVENT(RHICmdList, FilterReflectionEnvironment);
        
        	const int32 EffectiveTopMipSize = CubmapSize;
        	const int32 NumMips = FMath::CeilLogTwo(EffectiveTopMipSize) + 1;
        
        	FSceneRenderTargetItem& EffectiveColorRT = FSceneRenderTargets::Get(RHICmdList).ReflectionColorScratchCubemap[0]->GetRenderTargetItem();
        
        	FGraphicsPipelineStateInitializer GraphicsPSOInit;
        	GraphicsPSOInit.RasterizerState = TStaticRasterizerState<FM_Solid, CM_None>::GetRHI();
        	GraphicsPSOInit.DepthStencilState = TStaticDepthStencilState<false, CF_Always>::GetRHI();
        	GraphicsPSOInit.BlendState = TStaticBlendState<CW_RGBA, BO_Add, BF_Zero, BF_DestAlpha, BO_Add, BF_Zero, BF_One>::GetRHI();
        		
        	RHICmdList.Transition(FRHITransitionInfo(EffectiveColorRT.TargetableTexture, ERHIAccess::Unknown, ERHIAccess::RTV));
        
        	// Premultiply alpha in-place using alpha blending
        	for (uint32 CubeFace = 0; CubeFace < CubeFace_MAX; CubeFace++)
        	{
        		FRHIRenderPassInfo RPInfo(EffectiveColorRT.TargetableTexture, ERenderTargetActions::Load_Store, nullptr, 0, CubeFace);
        		RHICmdList.BeginRenderPass(RPInfo, TEXT("FilterReflectionEnvironmentRP"));
        		RHICmdList.ApplyCachedRenderTargets(GraphicsPSOInit);
        
        		const FIntPoint SourceDimensions(CubmapSize, CubmapSize);
        		const FIntRect ViewRect(0, 0, EffectiveTopMipSize, EffectiveTopMipSize);
        		RHICmdList.SetViewport(0, 0, 0.0f, EffectiveTopMipSize, EffectiveTopMipSize, 1.0f);
        
        		TShaderMapRef<FScreenVS> VertexShader(GetGlobalShaderMap(FeatureLevel));
        		TShaderMapRef<FOneColorPS> PixelShader(GetGlobalShaderMap(FeatureLevel));
        
        		GraphicsPSOInit.BoundShaderState.VertexDeclarationRHI = GFilterVertexDeclaration.VertexDeclarationRHI;
        		GraphicsPSOInit.BoundShaderState.VertexShaderRHI = VertexShader.GetVertexShader();
        		GraphicsPSOInit.BoundShaderState.PixelShaderRHI = PixelShader.GetPixelShader();
        		GraphicsPSOInit.PrimitiveType = PT_TriangleList;
        
        		SetGraphicsPipelineState(RHICmdList, GraphicsPSOInit);
        
        		FLinearColor UnusedColors[1] = { FLinearColor::Black };
        		PixelShader->SetColors(RHICmdList, UnusedColors, UE_ARRAY_COUNT(UnusedColors));
        
        		DrawRectangle(
        			RHICmdList,
        			ViewRect.Min.X, ViewRect.Min.Y, 
        			ViewRect.Width(), ViewRect.Height(),
        			0, 0, 
        			SourceDimensions.X, SourceDimensions.Y,
        			FIntPoint(ViewRect.Width(), ViewRect.Height()),
        			SourceDimensions,
        			VertexShader);
        
        		RHICmdList.EndRenderPass();
        	}
        
        	RHICmdList.Transition(FRHITransitionInfo(EffectiveColorRT.TargetableTexture, ERHIAccess::Unknown, ERHIAccess::SRVMask));
        
        	auto ShaderMap = GetGlobalShaderMap(FeatureLevel);
        	FSceneRenderTargets& SceneContext = FSceneRenderTargets::Get(RHICmdList);
        
        	FSceneRenderTargetItem& DownSampledCube = FSceneRenderTargets::Get(RHICmdList).ReflectionColorScratchCubemap[0]->GetRenderTargetItem();
        	FSceneRenderTargetItem& FilteredCube = FSceneRenderTargets::Get(RHICmdList).ReflectionColorScratchCubemap[1]->GetRenderTargetItem();
        
        	CreateCubeMips( RHICmdList, FeatureLevel, NumMips, DownSampledCube );
        
        	if (OutIrradianceEnvironmentMap)
        	{
        		SCOPED_DRAW_EVENT(RHICmdList, ComputeDiffuseIrradiance);
        		
        		const int32 NumDiffuseMips = FMath::CeilLogTwo( GDiffuseIrradianceCubemapSize ) + 1;
        		const int32 DiffuseConvolutionSourceMip = FMath::Max(0, NumMips - NumDiffuseMips);
        
        		ComputeDiffuseIrradiance(RHICmdList, FeatureLevel, DownSampledCube.ShaderResourceTexture, DiffuseConvolutionSourceMip, OutIrradianceEnvironmentMap);
        	}
        
        	FilterCubeMap(RHICmdList, FeatureLevel, NumMips, DownSampledCube, FilteredCube);
        	RHICmdList.CopyToResolveTarget(FilteredCube.TargetableTexture, FilteredCube.ShaderResourceTexture, FResolveParams());
        }

        1.  ComputeDiffuseIrradiance()  D:\UnrealEngine426\Engine\Source\Runtime\Renderer\Private\ReflectionEnvironmentDiffuseIrradiance.cpp

          1. 
            void ComputeDiffuseIrradiance(FRHICommandListImmediate& RHICmdList, ERHIFeatureLevel::Type FeatureLevel, FTextureRHIRef LightingSource, int32 LightingSourceMipIndex, FSHVectorRGB3* OutIrradianceEnvironmentMap)
            {
            	auto ShaderMap = GetGlobalShaderMap(FeatureLevel);
            	FSceneRenderTargets& SceneContext = FSceneRenderTargets::Get(RHICmdList);
            
            	FGraphicsPipelineStateInitializer GraphicsPSOInit;
            	GraphicsPSOInit.RasterizerState = TStaticRasterizerState<FM_Solid, CM_None>::GetRHI();
            	GraphicsPSOInit.DepthStencilState = TStaticDepthStencilState<false, CF_Always>::GetRHI();
            	GraphicsPSOInit.BlendState = TStaticBlendState<>::GetRHI();
            
            	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);			
            
            			RHICmdList.Transition(FRHITransitionInfo(EffectiveRT.TargetableTexture, ERHIAccess::Unknown, ERHIAccess::RTV));
            
            			for (int32 CubeFace = 0; CubeFace < CubeFace_MAX; CubeFace++)
            			{
            				FRHIRenderPassInfo RPInfo(EffectiveRT.TargetableTexture, ERenderTargetActions::DontLoad_Store, nullptr, 0, CubeFace);
            				RHICmdList.BeginRenderPass(RPInfo, TEXT("CopyDiffuseIrradianceRP"));
            				RHICmdList.ApplyCachedRenderTargets(GraphicsPSOInit);
            
            				const FIntRect ViewRect(0, 0, MipSize, MipSize);
            				RHICmdList.SetViewport(0.0f, 0.0f, 0.0f, (float)MipSize, (float)MipSize, 1.0f);
            				TShaderMapRef<FCopyDiffuseIrradiancePS> PixelShader(ShaderMap);
            					
            				TShaderMapRef<FScreenVS> VertexShader(GetGlobalShaderMap(FeatureLevel));
            
            				GraphicsPSOInit.BoundShaderState.VertexDeclarationRHI = GFilterVertexDeclaration.VertexDeclarationRHI;
            				GraphicsPSOInit.BoundShaderState.VertexShaderRHI = VertexShader.GetVertexShader();
            				GraphicsPSOInit.BoundShaderState.PixelShaderRHI = PixelShader.GetPixelShader();
            				GraphicsPSOInit.PrimitiveType = PT_TriangleList;
            
            				SetGraphicsPipelineState(RHICmdList, GraphicsPSOInit);
            
            				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.EndRenderPass();
            			}
            
            			RHICmdList.Transition(FRHITransitionInfo(EffectiveRT.TargetableTexture, ERHIAccess::RTV, ERHIAccess::SRVGraphics));
            		}
            
            		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);
            
            				RHICmdList.Transition(FRHITransitionInfo(EffectiveRT.TargetableTexture, ERHIAccess::Unknown, ERHIAccess::RTV));
            
            				for (int32 CubeFace = 0; CubeFace < CubeFace_MAX; CubeFace++)
            				{
            					FRHIRenderPassInfo RPInfo(EffectiveRT.TargetableTexture, ERenderTargetActions::Load_Store, nullptr, MipIndex, CubeFace);
            					RHICmdList.BeginRenderPass(RPInfo, TEXT("AccumulateDiffuseIrradianceRP"));
            					RHICmdList.ApplyCachedRenderTargets(GraphicsPSOInit);
            
            					const FIntRect ViewRect(0, 0, MipSize, MipSize);
            					RHICmdList.SetViewport(0.0f, 0.0f, 0.0f, (float)MipSize, (float)MipSize, 1.0f);
            					TShaderMapRef<FAccumulateDiffuseIrradiancePS> PixelShader(ShaderMap);
            						
            					TShaderMapRef<FScreenVS> VertexShader(GetGlobalShaderMap(FeatureLevel));
            						
            					GraphicsPSOInit.BoundShaderState.VertexDeclarationRHI = GFilterVertexDeclaration.VertexDeclarationRHI;
            					GraphicsPSOInit.BoundShaderState.VertexShaderRHI = VertexShader.GetVertexShader();
            					GraphicsPSOInit.BoundShaderState.PixelShaderRHI = PixelShader.GetPixelShader();
            					GraphicsPSOInit.PrimitiveType = PT_TriangleList;
            
            					SetGraphicsPipelineState(RHICmdList, GraphicsPSOInit);
            						
            					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.EndRenderPass();
            				}				
            
            				RHICmdList.Transition(FRHITransitionInfo(EffectiveRT.TargetableTexture, ERHIAccess::RTV, ERHIAccess::SRVGraphics));
            			}
            		}
            
            		{
            			// 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.
            			RHICmdList.Transition(FRHITransitionInfo(EffectiveRT.TargetableTexture, ERHIAccess::Unknown, ERHIAccess::RTV));
            			FRHIRenderPassInfo RPInfo(EffectiveRT.TargetableTexture, ERenderTargetActions::Load_Store, nullptr);
            			RHICmdList.BeginRenderPass(RPInfo, TEXT("GatherCoeffRP"));
            			RHICmdList.ApplyCachedRenderTargets(GraphicsPSOInit);
            
            			const FIntRect ViewRect(CoefficientIndex, 0, CoefficientIndex + 1, 1);
            			RHICmdList.SetViewport(0.0f, 0.0f, 0.0f, (float)FSHVector3::MaxSHBasis, 1.0f, 1.0f);
            
            			TShaderMapRef<FScreenVS> VertexShader(ShaderMap);
            			TShaderMapRef<FAccumulateCubeFacesPS> PixelShader(ShaderMap);
            
            			GraphicsPSOInit.BoundShaderState.VertexDeclarationRHI = GFilterVertexDeclaration.VertexDeclarationRHI;
            			GraphicsPSOInit.BoundShaderState.VertexShaderRHI = VertexShader.GetVertexShader();
            			GraphicsPSOInit.BoundShaderState.PixelShaderRHI = PixelShader.GetPixelShader();
            			GraphicsPSOInit.PrimitiveType = PT_TriangleList;
            
            			SetGraphicsPipelineState(RHICmdList, GraphicsPSOInit);
            
            			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.EndRenderPass();
            			RHICmdList.Transition(FRHITransitionInfo(EffectiveRT.TargetableTexture, ERHIAccess::RTV, ERHIAccess::SRVGraphics));
            		}
            	}
            
            	{
            		// 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;
            		}
            	}
            }
            
            

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

            1. 
              float4 CoefficientMask0;
              float4 CoefficientMask1;
              float CoefficientMask2;
              int NumSamples;
              
              void DiffuseIrradianceCopyPS(
              	FScreenVertexOutput Input,
              	out float4 OutColor : SV_Target0
              	)
              { 
              	float2 ScaledUVs = Input.UV * 2 - 1;
              	float3 CubeCoordinates = normalize(GetCubemapVector(ScaledUVs, CubeFace));
              
              	float SquaredUVs = 1 + dot(ScaledUVs, ScaledUVs);
              	// Dividing by NumSamples here to keep the sum in the range of fp16, once we get down to the 1x1 mip
              	float TexelWeight = 4 / (sqrt(SquaredUVs) * SquaredUVs);
              
              	FThreeBandSHVector SHCoefficients = SHBasisFunction3(CubeCoordinates);
              	float CurrentSHCoefficient = dot(SHCoefficients.V0, CoefficientMask0) + dot(SHCoefficients.V1, CoefficientMask1) + SHCoefficients.V2 * CoefficientMask2;
              	float3 TexelLighting = SampleCubemap(CubeCoordinates).rgb;
              
              	OutColor = float4(TexelLighting * CurrentSHCoefficient * TexelWeight, TexelWeight);
              }
              
              float4 Sample01;
              float4 Sample23;
              
              void DiffuseIrradianceAccumulatePS(
              	FScreenVertexOutput Input,
              	out float4 OutColor : SV_Target0
              	)
              { 
              	float4 AccumulatedValue = 0;
              
              	{
              		float2 ScaledUVs = saturate(Input.UV + Sample01.xy) * 2 - 1;
              		float3 CubeCoordinates = GetCubemapVector(ScaledUVs, CubeFace);
              		AccumulatedValue += SampleCubemap(CubeCoordinates);
              	}
              	
              	{
              		float2 ScaledUVs = saturate(Input.UV + Sample01.zw) * 2 - 1;
              		float3 CubeCoordinates = GetCubemapVector(ScaledUVs, CubeFace);
              		AccumulatedValue += SampleCubemap(CubeCoordinates);
              	}
              
              	{
              		float2 ScaledUVs = saturate(Input.UV + Sample23.xy) * 2 - 1;
              		float3 CubeCoordinates = GetCubemapVector(ScaledUVs, CubeFace);
              		AccumulatedValue += SampleCubemap(CubeCoordinates);
              	}
              
              	{
              		float2 ScaledUVs = saturate(Input.UV + Sample23.zw) * 2 - 1;
              		float3 CubeCoordinates = GetCubemapVector(ScaledUVs, CubeFace);
              		AccumulatedValue += SampleCubemap(CubeCoordinates);
              	}
              	
              	OutColor = float4(AccumulatedValue.rgb / 4.0f, AccumulatedValue.a / 4.0f);
              }
              
              void AccumulateCubeFacesPS(
              	FScreenVertexOutput Input,
              	out float4 OutColor : SV_Target0
              	)
              {
              	float4 AccumulatedValue; 
              	AccumulatedValue  = TextureCubeSampleLevel(SourceCubemapTexture, SourceCubemapSampler, float3(1, 0, 0), SourceMipIndex);
              	AccumulatedValue += TextureCubeSampleLevel(SourceCubemapTexture, SourceCubemapSampler, float3(-1, 0, 0), SourceMipIndex);
              	AccumulatedValue += TextureCubeSampleLevel(SourceCubemapTexture, SourceCubemapSampler, float3(0, 1, 0), SourceMipIndex);
              	AccumulatedValue += TextureCubeSampleLevel(SourceCubemapTexture, SourceCubemapSampler, float3(0, -1, 0), SourceMipIndex);
              	AccumulatedValue += TextureCubeSampleLevel(SourceCubemapTexture, SourceCubemapSampler, float3(0, 0, 1), SourceMipIndex);
              	AccumulatedValue += TextureCubeSampleLevel(SourceCubemapTexture, SourceCubemapSampler, float3(0, 0, -1), SourceMipIndex);
              	OutColor = float4(4 * PI * AccumulatedValue.rgb / ( max(AccumulatedValue.a, .00001f)), 0);	
              }
              

              D:\UnrealEngine426\Engine\Shaders\Private\SHCommon.ush

            2. FThreeBandSHVector SHBasisFunction3(half3 InputVector)
              {
              	FThreeBandSHVector Result;
              	// These are derived from simplifying SHBasisFunction in C++
              	Result.V0.x = 0.282095f; 
              	Result.V0.y = -0.488603f * InputVector.y;
              	Result.V0.z = 0.488603f * InputVector.z;
              	Result.V0.w = -0.488603f * InputVector.x;
              
              	half3 VectorSquared = InputVector * InputVector;
              	Result.V1.x = 1.092548f * InputVector.x * InputVector.y;
              	Result.V1.y = -1.092548f * InputVector.y * InputVector.z;
              	Result.V1.z = 0.315392f * (3.0f * VectorSquared.z - 1.0f);
              	Result.V1.w = -1.092548f * InputVector.x * InputVector.z;
              	Result.V2 = 0.546274f * (VectorSquared.x - VectorSquared.y);
              
              	return Result;
              }

        2. FilterCubeMap()

          1. 
            void FilterCubeMap(FRHICommandListImmediate& RHICmdList, ERHIFeatureLevel::Type FeatureLevel, int32 NumMips, 
            	FSceneRenderTargetItem& DownSampledCube, FSceneRenderTargetItem& FilteredCube)
            {
            	SCOPED_DRAW_EVENT(RHICmdList, FilterCubeMap);
            	auto ShaderMap = GetGlobalShaderMap(FeatureLevel);
            
            	FGraphicsPipelineStateInitializer GraphicsPSOInit;
            	GraphicsPSOInit.RasterizerState = TStaticRasterizerState<FM_Solid, CM_None>::GetRHI();
            	GraphicsPSOInit.DepthStencilState = TStaticDepthStencilState<false, CF_Always>::GetRHI();
            	GraphicsPSOInit.BlendState = TStaticBlendState<>::GetRHI();
            
            	RHICmdList.Transition(FRHITransitionInfo(FilteredCube.TargetableTexture, ERHIAccess::Unknown, ERHIAccess::RTV));
            
            	// Filter all the mips
            	for (int32 MipIndex = 0; MipIndex < NumMips; MipIndex++)
            	{
            		const int32 MipSize = 1 << (NumMips - MipIndex - 1);
            
            		for (int32 CubeFace = 0; CubeFace < CubeFace_MAX; CubeFace++)
            		{
            			FRHIRenderPassInfo RPInfo(FilteredCube.TargetableTexture, ERenderTargetActions::DontLoad_Store, nullptr, MipIndex, CubeFace);
            			RHICmdList.Transition(FRHITransitionInfo(FilteredCube.TargetableTexture, ERHIAccess::Unknown, ERHIAccess::RTV));
            			RHICmdList.BeginRenderPass(RPInfo, TEXT("FilterMips"));
            
            			RHICmdList.ApplyCachedRenderTargets(GraphicsPSOInit);
            
            			const FIntRect ViewRect(0, 0, MipSize, MipSize);
            			RHICmdList.SetViewport(0, 0, 0.0f, MipSize, MipSize, 1.0f);
            
            			//TShaderMapRef<TCubeFilterPS<1>> CaptureCubemapArrayPixelShader(GetGlobalShaderMap(FeatureLevel));
            
            			TShaderMapRef<FScreenVS> VertexShader(GetGlobalShaderMap(FeatureLevel));
            			TShaderMapRef<TCubeFilterPS<0>> PixelShader(GetGlobalShaderMap(FeatureLevel));
            			GraphicsPSOInit.BoundShaderState.VertexShaderRHI = VertexShader.GetVertexShader();
            			GraphicsPSOInit.BoundShaderState.PixelShaderRHI = PixelShader.GetPixelShader();
            			GraphicsPSOInit.BoundShaderState.VertexDeclarationRHI = GFilterVertexDeclaration.VertexDeclarationRHI;
            			GraphicsPSOInit.PrimitiveType = PT_TriangleList;
            
            			SetGraphicsPipelineState(RHICmdList, GraphicsPSOInit);
            
            			{
            				FRHIPixelShader* ShaderRHI = PixelShader.GetPixelShader();
            
            				SetShaderValue(RHICmdList, ShaderRHI, PixelShader->CubeFace, CubeFace);
            				SetShaderValue(RHICmdList, ShaderRHI, PixelShader->MipIndex, MipIndex);
            
            				SetShaderValue(RHICmdList, ShaderRHI, PixelShader->NumMips, NumMips);
            
            				SetTextureParameter(
            					RHICmdList,
            					ShaderRHI,
            					PixelShader->SourceCubemapTexture,
            					PixelShader->SourceCubemapSampler,
            					TStaticSamplerState<SF_Trilinear, AM_Clamp, AM_Clamp, AM_Clamp>::GetRHI(),
            					DownSampledCube.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.EndRenderPass();
            		}
            	}
            }
            D:\UnrealEngine426\Engine\Shaders\Private\ReflectionEnvironmentShaders.usf
            1. #ifdef USE_COMPUTE
              int CubeFaceOffset;
              [numthreads(THREADGROUP_SIZE, THREADGROUP_SIZE, 1)]
              void FilterCS(uint3 ThreadId : SV_DispatchThreadID)
              {
              	const uint2 FaceCoord = uint2(ThreadId.x % uint(FaceThreadGroupSize), ThreadId.y);
              	if (any(FaceCoord >= uint2(ValidDispatchCoord)))
              	{
              		return;
              	}
              	const int SelectedCubeFace = CubeFaceOffset + int(ThreadId.x) / FaceThreadGroupSize;
              	float2 ScaledUVs = ((float2(FaceCoord) + 0.5f) / float2(ValidDispatchCoord)) * 2.0f - 1.0f;
              	float4 OutColor;
              #else // USE_COMPUTE
              void FilterPS(
              	FScreenVertexOutput Input,
              	out float4 OutColor : SV_Target0
              	)
              { 
              	float2 ScaledUVs = Input.UV * 2 - 1;
              	const int SelectedCubeFace = CubeFace;
              #endif // USE_COMPUTE
              	float3 CubeCoordinates = GetCubemapVector(ScaledUVs, SelectedCubeFace);
              
              	float3 N = normalize(CubeCoordinates);
              	float3x3 TangentToWorld = GetTangentBasis( N );
              
              	float Roughness = ComputeReflectionCaptureRoughnessFromMip( MipIndex, NumMips - 1 );
              
              	if( Roughness < 0.01 )
              	{
              		OutColor = SourceCubemapTexture.SampleLevel(SourceCubemapSampler, CubeCoordinates, 0 );
              	#ifdef USE_COMPUTE
              		OutTextureMipColor[uint3(FaceCoord, SelectedCubeFace)] = OutColor;
              	#endif
              		return;
              	}
              
              	uint CubeSize = 1 << ( NumMips - 1 );
              	const float SolidAngleTexel = 4*PI / ( 6 * CubeSize * CubeSize ) * 2;
              
              	//const uint NumSamples = 1024;
              	const uint NumSamples = Roughness < 0.1 ? 32 : 64;
              	
              	float4 FilteredColor = 0;
              	BRANCH
              	if( Roughness > 0.99 )
              	{
              		// Roughness=1, GGX is constant. Use cosine distribution instead
              
              		LOOP
              		for( uint i = 0; i < NumSamples; i++ )
              		{
              			float2 E = Hammersley( i, NumSamples, 0 );
              
              			float3 L = CosineSampleHemisphere( E ).xyz;
              
              			float NoL = L.z;
              
              			float PDF = NoL / PI;
              			float SolidAngleSample = 1.0 / ( NumSamples * PDF );
              			float Mip = 0.5 * log2( SolidAngleSample / SolidAngleTexel );
              
              			L = mul( L, TangentToWorld );
              			FilteredColor += SourceCubemapTexture.SampleLevel(SourceCubemapSampler, L, Mip );
              		}
              
              		OutColor = FilteredColor / NumSamples;
              	}
              	else
              	{
              		float Weight = 0;
              
              		LOOP
              		for( uint i = 0; i < NumSamples; i++ )
              		{
              			float2 E = Hammersley( i, NumSamples, 0 );
              
              			// 6x6 Offset rows. Forms uniform star pattern
              			//uint2 Index = uint2( i % 6, i / 6 );
              			//float2 E = ( Index + 0.5 ) / 5.8;
              			//E.x = frac( E.x + (Index.y & 1) * (0.5 / 6.0) );
              
              			E.y *= 0.995;
              
              			float3 H = ImportanceSampleGGX( E, Pow4(Roughness) ).xyz;
              			float3 L = 2 * H.z * H - float3(0,0,1);
              
              			float NoL = L.z;
              			float NoH = H.z;
              
              			if( NoL > 0 )
              			{
              				//float TexelWeight = CubeTexelWeight( L );
              				//float SolidAngleTexel = SolidAngleAvgTexel * TexelWeight;
              
              				//float PDF = D_GGX( Pow4(Roughness), NoH ) * NoH / (4 * VoH);
              				float PDF = D_GGX( Pow4(Roughness), NoH ) * 0.25;
              				float SolidAngleSample = 1.0 / ( NumSamples * PDF );
              				float Mip = 0.5 * log2( SolidAngleSample / SolidAngleTexel );
              
              				float ConeAngle = acos( 1 - SolidAngleSample / (2*PI) );
              
              				L = mul( L, TangentToWorld );
              				FilteredColor += SourceCubemapTexture.SampleLevel(SourceCubemapSampler, L, Mip ) * NoL;
              				Weight += NoL;
              			}
              		}
              
              		OutColor = FilteredColor / Weight;
              	}
              
              #ifdef USE_COMPUTE
              	OutTextureMipColor[uint3(FaceCoord, SelectedCubeFace)] = OutColor;
              #endif
              }
              D:\UnrealEngine426\Engine\Shaders\Private\MonteCarlo.ush
              1. float2 Hammersley( uint Index, uint NumSamples, uint2 Random )
                {
                	float E1 = frac( (float)Index / NumSamples + float( Random.x & 0xffff ) / (1<<16) );
                	float E2 = float( ReverseBits32(Index) ^ Random.y ) * 2.3283064365386963e-10;
                	return float2( E1, E2 );
                }
                
                float4 CosineSampleHemisphere( float2 E )
                {
                	float Phi = 2 * PI * E.x;
                	float CosTheta = sqrt( E.y );
                	float SinTheta = sqrt( 1 - CosTheta * CosTheta );
                
                	float3 H;
                	H.x = SinTheta * cos( Phi );
                	H.y = SinTheta * sin( Phi );
                	H.z = CosTheta;
                
                	float PDF = CosTheta * (1.0 /  PI);
                
                	return float4( H, PDF );
                }
                
                float4 ImportanceSampleGGX( float2 E, float a2 )
                {
                	float Phi = 2 * PI * E.x;
                	float CosTheta = sqrt( (1 - E.y) / ( 1 + (a2 - 1) * E.y ) );
                	float SinTheta = sqrt( 1 - CosTheta * CosTheta );
                
                	float3 H;
                	H.x = SinTheta * cos( Phi );
                	H.y = SinTheta * sin( Phi );
                	H.z = CosTheta;
                	
                	float d = ( CosTheta * a2 - CosTheta ) * CosTheta + 1;
                	float D = a2 / ( PI*d*d );
                	float PDF = D * CosTheta;
                
                	return float4( H, PDF );
                }
                
                
              2. D:\UnrealEngine426\Engine\Shaders\Private\BRDF.ush
                1. // GGX / Trowbridge-Reitz
                  // [Walter et al. 2007, "Microfacet models for refraction through rough surfaces"]
                  float D_GGX( float a2, float NoH )
                  {
                  	float d = ( NoH * a2 - NoH ) * NoH + 1;	// 2 mad
                  	return a2 / ( PI*d*d );					// 4 mul, 1 rcp
                  }
  3. void CopyToSkyTexture(FRHICommandList& RHICmdList, FScene* Scene, FTexture* ProcessedTexture)
    {
    	SCOPED_DRAW_EVENT(RHICmdList, CopyToSkyTexture);
    	if (ProcessedTexture->TextureRHI)
    	{
    		const int32 EffectiveTopMipSize = ProcessedTexture->GetSizeX();
    		const int32 NumMips = FMath::CeilLogTwo(EffectiveTopMipSize) + 1;
    		FSceneRenderTargets& SceneContext = FSceneRenderTargets::Get(RHICmdList);
    
    		FSceneRenderTargetItem& FilteredCube = FSceneRenderTargets::Get(RHICmdList).ReflectionColorScratchCubemap[1]->GetRenderTargetItem();
    
    		// GPU copy back to the skylight's texture, which is not a render target
    		FRHICopyTextureInfo CopyInfo;
    		CopyInfo.Size = FilteredCube.ShaderResourceTexture->GetSizeXYZ();
    		CopyInfo.NumSlices = 6;
    		CopyInfo.NumMips = NumMips;
    
    		FRHITransitionInfo TransitionsBefore[] =
    		{
    			FRHITransitionInfo(FilteredCube.ShaderResourceTexture, ERHIAccess::Unknown, ERHIAccess::CopySrc),
    			FRHITransitionInfo(ProcessedTexture->TextureRHI, ERHIAccess::Unknown, ERHIAccess::CopyDest)
    		};
    		RHICmdList.Transition(MakeArrayView(TransitionsBefore, UE_ARRAY_COUNT(TransitionsBefore)));
    
    		RHICmdList.CopyTexture(FilteredCube.ShaderResourceTexture, ProcessedTexture->TextureRHI, CopyInfo);
    
    		FRHITransitionInfo TransitionsAfter[] =
    		{
    			FRHITransitionInfo(FilteredCube.ShaderResourceTexture, ERHIAccess::CopySrc, ERHIAccess::SRVMask),
    			FRHITransitionInfo(ProcessedTexture->TextureRHI, ERHIAccess::CopyDest, ERHIAccess::SRVMask)
    		};
    		RHICmdList.Transition(MakeArrayView(TransitionsAfter, UE_ARRAY_COUNT(TransitionsAfter)));
    	}
    }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值