Files
UnrealEngine/Engine/Shaders/Private/PlanarReflectionShared.ush
2025-05-18 13:04:45 +08:00

84 lines
4.8 KiB
HLSL

// Copyright Epic Games, Inc. All Rights Reserved.
/*=============================================================================
PlanarReflectionShared.usf
=============================================================================*/
half4 ComputePlanarReflections(float3 TranslatedWorldPosition, half3 WorldNormal, half Roughness)
{
half4 OutPlanarReflection = 0;
float PlaneDistance = dot(PlanarReflectionStruct.ReflectionPlane, float4(TranslatedWorldPosition, -1));
half DistanceFade = 1 - saturate(abs(PlaneDistance) * PlanarReflectionStruct.PlanarReflectionParameters.x + PlanarReflectionStruct.PlanarReflectionParameters.y);
float3 PlaneOriginToWorldPosition = TranslatedWorldPosition - PlanarReflectionStruct.PlanarReflectionOrigin.xyz;
float XAxisDistance = dot(PlaneOriginToWorldPosition, PlanarReflectionStruct.PlanarReflectionXAxis.xyz);
half XAxisFade = saturate((PlanarReflectionStruct.PlanarReflectionXAxis.w - abs(XAxisDistance)) * PlanarReflectionStruct.PlanarReflectionParameters.x);
float YAxisDistance = dot(PlaneOriginToWorldPosition, PlanarReflectionStruct.PlanarReflectionYAxis.xyz);
half YAxisFade = saturate((PlanarReflectionStruct.PlanarReflectionYAxis.w - abs(YAxisDistance)) * PlanarReflectionStruct.PlanarReflectionParameters.x);
DistanceFade *= XAxisFade * YAxisFade;
half AngleFade = saturate(dot(PlanarReflectionStruct.ReflectionPlane.xyz, WorldNormal) * PlanarReflectionStruct.PlanarReflectionParameters2.x + PlanarReflectionStruct.PlanarReflectionParameters2.y);
half RoughnessFade = 1 - saturate((Roughness - .2f) * 10.0f);
half FinalFade = DistanceFade * AngleFade * RoughnessFade;
BRANCH
if (FinalFade > 0)
{
// CameraToPixel in the main view is what we used as ReflectionVector when rendering the reflection pass to PlanarReflectionTexture
float3 CameraToPixel = GetCameraVectorFromTranslatedWorldPosition(ResolvedView, TranslatedWorldPosition);
// Reflect the effective ReflectionVector in mirrored space to get the original camera vector
float3 MirroredCameraVector = reflect(CameraToPixel, -PlanarReflectionStruct.ReflectionPlane.xyz);
// Transform the GBuffer normal into mirrored space
half3 MirroredNormal = mul(WorldNormal, PlanarReflectionStruct.InverseTransposeMirrorMatrix).xyz;
// Reflect the original camera vector across the GBuffer normal in mirrored space
half3 MirroredReflectionVectorOffNormal = reflect(MirroredCameraVector, MirroredNormal);
// At this point we have a new reflection vector off of the GBuffer normal, and we need to approximate its intersection with the scene
// An accurate intersection would ray trace the planar reflection depth buffer
// As an approximation we are just intersecting with a user defined sphere
float3 VirtualReflectionSpherePosition = TranslatedWorldPosition + MirroredReflectionVectorOffNormal * PlanarReflectionStruct.PlanarReflectionParameters.z;
// Transform the intersection position into view space
float3 ViewVirtualReflectionSpherePosition = mul(float4(VirtualReflectionSpherePosition, 1), ResolvedView.TranslatedWorldToView).xyz;
// Transform the intersection position into clip space using the same projection matrix used to render PlanarReflectionTexture
float4 ClipVirtualReflectionSpherePosition = mul(float4(ViewVirtualReflectionSpherePosition, 1), PlanarReflectionStruct.ProjectionWithExtraFOV[ResolvedView.StereoPassIndex]);
uint EyeIndex = 0;
if (PlanarReflectionStruct.bIsStereo)
{
EyeIndex = ResolvedView.StereoPassIndex;
}
half2 NDC = clamp(ClipVirtualReflectionSpherePosition.xy / ClipVirtualReflectionSpherePosition.w, -PlanarReflectionStruct.PlanarReflectionScreenBound, PlanarReflectionStruct.PlanarReflectionScreenBound);
half2 ViewportUV = NDC * PlanarReflectionStruct.PlanarReflectionScreenScaleBias[EyeIndex].xy + PlanarReflectionStruct.PlanarReflectionScreenScaleBias[EyeIndex].zw;
half4 PlanarReflectionTextureValue = Texture2DSampleLevel(
PlanarReflectionStruct.PlanarReflectionTexture,
#if SUPPORTS_INDEPENDENT_SAMPLERS
View.SharedTrilinearClampedSampler,
#else
PlanarReflectionStruct.PlanarReflectionSampler,
#endif
ViewportUV,
0);
// Fade out in regions of the planar reflection that weren't written to, so we can composite with other reflection methods
FinalFade *= PlanarReflectionTextureValue.a;
OutPlanarReflection.rgb = PlanarReflectionTextureValue.rgb * RoughnessFade; // Add roughness fade to color to provide smooth color transition.
OutPlanarReflection.a = FinalFade;
}
return OutPlanarReflection;
}
#if (FEATURE_LEVEL <= FEATURE_LEVEL_ES3_1)
half4 GetPlanarReflection(float3 TranslatedWorldPosition, half3 WorldNormal, half Roughness)
{
half4 PlanarReflection = ComputePlanarReflections(TranslatedWorldPosition, WorldNormal, Roughness);
#if OUTPUT_GAMMA_SPACE
// the capture will also be in gamma space, convert to linear:
PlanarReflection.rgb *= PlanarReflection.rgb;
#endif
return PlanarReflection;
}
#endif