e4s-sdk/gamedata/shaders/d3d11/sslr_render.ps.hlsl
2026-06-17 23:06:51 +03:00

138 lines
3.6 KiB
HLSL

#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;
}