#include "common.hlsli" #include "reflections.hlsli" #include "metalic_roughness_ambient.hlsli" struct PSInput { float4 hpos : SV_POSITION; float2 texcoord : TEXCOORD0; }; Texture3D s_blue_noise; // TODO: Это можно упростить потом float3 TangentToWorld(in float3 N, in float3 H) { float3 UpVector = abs(N.y) < 0.999f ? float3(0.0, 1.0, 0.0) : float3(0.0, 0.0, -1.0); float3 T = normalize(cross(UpVector, N)); float3 B = cross(N, T); return normalize(T * H.x + B * H.y + N * H.z); } // Brian Karis, Epic Games "Real Shading in Unreal Engine 4" float4 ImportanceSampleGGX(float3 N, float2 Xi, float Roughness) { float m = Roughness * Roughness; float m2 = m * m; float Phi = 2 * PI * Xi.x; float CosTheta = sqrt((1.0 - Xi.y) * rcp(1.0 + (m2 - 1.0) * Xi.y)); float SinTheta = sqrt(abs(1.0 - CosTheta * CosTheta)); float3 H; H.x = SinTheta * cos(Phi); H.y = SinTheta * sin(Phi); H.z = CosTheta; float d = (CosTheta * m2 - CosTheta) * CosTheta + 1.0f; float D = m2 * rcp(d * d); float pdf = D * CosTheta; H = TangentToWorld(N, H); return float4(H, pdf); } void main(PSInput I, out float4 Point : SV_Target0, out float4 Final : SV_Target1) { IXrayGbuffer O; GbufferUnpack(I.texcoord.xy, I.hpos.xy, O); if(O.Depth >= 1.0f) { Point = 0.0f; Final = 0.0f; return; } float3 ReflectPoint = GbufferGetPointRealUnjitter(I.texcoord.xy, O.Depth); float3 ViewVec = normalize(ReflectPoint); float2 Jitter = s_blue_noise[uint3(uint2(I.hpos.xy) % 128, uint(m_taa_jitter.w) % 32)].xy; Jitter.x = Jitter.x * 0.5f + 0.5f; Jitter.y *= 0.7f; float3 BaseReflect = normalize(reflect(ViewVec, O.Normal.xyz)); float4 H = ImportanceSampleGGX(mul(m_invV, O.Normal.xyz), Jitter, O.Roughness); H.xyz = mul(m_V, H.xyz); float3 Reflection = reflect(ViewVec, H.xyz); if (dot(Reflection, O.Normal) < 0.0f) { Reflection = normalize(Reflection + O.Normal); } float3 StartPoint = ReflectPoint * 0.996f; Point.xyz = StartPoint + Reflection * fog_params.z; bool isNotHUD = O.Depth >= 0.02f; if(isNotHUD) { StartPoint += O.Normal * 0.15f; #ifdef USE_OFFSCREEN_REFLECTIONS float4 VSLR = FastViewReflections(StartPoint, Reflection); Point.xyz = lerp(Point.xyz, VSLR.xyz, VSLR.w); #endif } else { Point.xyz = Reflection.xyz * s_env.SampleLevel(smp_linear, Point.xyz, 0.0f).w; } float4 SSLR = FastViewReflectionsSSR(StartPoint, Reflection, !isNotHUD); float4 EndProj = mul(O.Depth < 0.02f ? m_P_hud : m_P, float4(SSLR.xyz, 1.0f)); EndProj.xy = EndProj.xy * rcp(EndProj.w) * float2(0.5f, -0.5f) + 0.5f; float2 Velocity = s_velocity.Sample(smp_rtlinear, EndProj.xy).xy * float2(0.5f, -0.5f); float2 PrevSpecularUV = saturate(EndProj.xy - Velocity.xy); Final = s_image.Sample(smp_rtlinear, PrevSpecularUV.xy); #ifdef USE_OFFSCREEN_REFLECTIONS O.Hemi = saturate(O.Hemi * 3.0f); #endif float4 Hemi = CompureSpecularIrradance(Reflection.xyz, O.Hemi, 0.0f).xyzz; SSLR.w *= GetBorderAtten(PrevSpecularUV); #ifdef USE_OFFSCREEN_REFLECTIONS float3 Color = s_env.SampleLevel(smp_linear, Point.xyz, 0.0f); Color.xyz *= rcp(1.00001f - Color.xyz); #else float3 Color = Hemi.xyz; #endif Final.xyz = lerp(Color.xyz, Final.xyz, SSLR.w); Point.xyz = lerp(Point.xyz, SSLR.xyz, SSLR.w); Final.xyz = PopGamma(Final.xyz); Hemi.w = max(length(Point.xyz), length(StartPoint.xyz) + length(Point.xyz - StartPoint.xyz)); Hemi.w = saturate(Hemi.w * fog_params.w + fog_params.x); Final.xyz = lerp(Final.xyz, Hemi.xyz, Hemi.w); Point.w = rcp(max(0.000001f, H.w)); Final.xyz *= rcp(1.0f + Final.xyz); Final.w = isNotHUD; }