138 lines
3.6 KiB
HLSL
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;
|
|
}
|
|
|