You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
189 lines
4.7 KiB
Plaintext
189 lines
4.7 KiB
Plaintext
// Copyright 1998-2014 Epic Games, Inc. All Rights Reserved.
|
|
|
|
/*=============================================================================
|
|
PostProcessSubsurface.usf: Screenspace subsurface scattering shaders.
|
|
=============================================================================*/
|
|
|
|
#include "Common.usf"
|
|
#include "PostProcessCommon.usf"
|
|
#include "DeferredShadingCommon.usf"
|
|
|
|
#if SSSS_SPECULAR_CORRECTION == 1
|
|
// requires alpha channel for scenecolor
|
|
#elif SSSS_SPECULAR_CORRECTION == 0
|
|
// speculars leak into SSS
|
|
#else
|
|
error
|
|
#endif
|
|
|
|
#if METHOD == 0
|
|
// horizontal
|
|
#elif METHOD == 1
|
|
// vertical
|
|
#elif METHOD == 2
|
|
// vertical and reconstruct specular
|
|
#else
|
|
error
|
|
#endif
|
|
|
|
// 0 / 1
|
|
#define VISUALIZE_KERNEL 0
|
|
|
|
// x:Radius
|
|
float4 SSSParams;
|
|
|
|
|
|
float3 ReconstructDiffuseLighting(float4 SceneColor4)
|
|
{
|
|
float SceneColorLum = Luminance(SceneColor4.rgb);
|
|
|
|
// max to avoid division by 0
|
|
return SceneColor4.rgb * max(0, SceneColorLum - SceneColor4.a) / max(0.0001f, SceneColorLum);
|
|
}
|
|
|
|
float3 ReconstructNonDiffuseLighting(float4 SceneColor4)
|
|
{
|
|
float SceneColorLum = Luminance(SceneColor4.rgb);
|
|
|
|
// max to avoid division by 0
|
|
return SceneColor4.rgb * SceneColor4.a / max(0.0001f, SceneColorLum);
|
|
}
|
|
|
|
void SetupPS(in float4 UVAndScreenPos : TEXCOORD0, out float4 OutColor : SV_Target0)
|
|
{
|
|
float2 UV = UVAndScreenPos.xy;
|
|
|
|
OutColor = 0;
|
|
|
|
FScreenSpaceData ScreenSpaceData = GetScreenSpaceData(UV);
|
|
|
|
FLATTEN if(ScreenSpaceData.GBuffer.ShadingModelID >= SHADINGMODELID_SUBSURFACE)
|
|
{
|
|
float4 SceneColor4 = Texture2DSample(PostprocessInput0, PostprocessInput0Sampler, UV);
|
|
|
|
#if SSSS_SPECULAR_CORRECTION == 1
|
|
// we take out the specular highlights
|
|
float3 Lighting = ReconstructDiffuseLighting(SceneColor4);
|
|
#else
|
|
float3 Lighting = SceneColor4.rgb;
|
|
#endif
|
|
|
|
OutColor.rgb = Lighting;
|
|
}
|
|
}
|
|
|
|
// Gaussian in window -2/c0 .. 2/c0, 2d integral: 1
|
|
// @param XSquared x * x
|
|
float ComputeWindowedGaussian(float x, float c0)
|
|
{
|
|
x *= c0;
|
|
|
|
float XSquared = x * x;
|
|
return max(exp2(-XSquared) - 0.065f, 0) / 3.4324f * (c0 * c0);
|
|
}
|
|
|
|
// Subsurface function
|
|
// @param x > 0
|
|
float3 ColorOverDistance(float3 SubsurfaceColor, float x)
|
|
{
|
|
// larger means tighter gaussian
|
|
x *= 2.0f; // -1..1 to -2..2
|
|
|
|
float3 Color = SubsurfaceColor;
|
|
|
|
// to avoid stuff gets brighter
|
|
// Color /= dot(Color, 1);
|
|
|
|
float3 Hack = 1;//float3(0.8f, 0.5f, 0.35f);
|
|
|
|
return Hack * float3(
|
|
ComputeWindowedGaussian(x, Color.r),
|
|
ComputeWindowedGaussian(x, Color.g),
|
|
ComputeWindowedGaussian(x, Color.b) );
|
|
}
|
|
|
|
float3 SampleDiffuseLighting(float2 LocalUV)
|
|
{
|
|
#if VISUALIZE_KERNEL
|
|
float Aspect = ViewportSize.x / ViewportSize.y;
|
|
|
|
float2 Dxy = (LocalUV - float2(0.75f, 0.25f)) * float2(Aspect, 1);
|
|
|
|
if(dot(Dxy, Dxy) < 0.000006f) return 2;
|
|
if(dot(Dxy, Dxy) < 0.05f) return 0;
|
|
#endif
|
|
|
|
return Texture2DSample(PostprocessInput0, PostprocessInput0Sampler, LocalUV).rgb;
|
|
}
|
|
|
|
// input0 is created by the SetupPS shader
|
|
void MainPS(float4 UVAndScreenPos : TEXCOORD0, out float4 OutColor : SV_Target0)
|
|
{
|
|
float2 UV = UVAndScreenPos.xy;
|
|
|
|
FScreenSpaceData ScreenSpaceData = GetScreenSpaceData(UV);
|
|
|
|
float2 Offset = PostprocessInput0Size.zw;
|
|
|
|
const int Count = 20;
|
|
float AccumSum = 0.0001f;
|
|
|
|
// scale in world space, todo: expose scale
|
|
float Radius = SSSParams.x * saturate(45 / ScreenSpaceData.GBuffer.Depth);
|
|
|
|
|
|
LOOP for(int i = -Count; i <= Count; ++i)
|
|
{
|
|
#if METHOD == 0
|
|
int x = i, y = 0;
|
|
#else
|
|
int x = 0, y = i;
|
|
#endif
|
|
|
|
{
|
|
float2 NormDelta = float2(x, y) / Count;
|
|
|
|
float r = length(NormDelta);
|
|
|
|
// float2 LocalUV = UV + float2(x, y) * Offset;
|
|
float2 LocalUV = UV + NormDelta * Radius * Offset;
|
|
|
|
FScreenSpaceData LocalScreenSpaceData = GetScreenSpaceData(LocalUV);
|
|
|
|
// hack
|
|
// float Subsurface = ScreenSpaceData.GBuffer.Roughness > 0.4f;
|
|
// float Subsurface = (1 - ScreenSpaceData.GBuffer.DecalMask) > 0.5f && ScreenSpaceData.GBuffer.Depth < 1000.0f;
|
|
FLATTEN if(LocalScreenSpaceData.GBuffer.ShadingModelID == SHADINGMODELID_SUBSURFACE)
|
|
{
|
|
float3 Color = ColorOverDistance(DecodeSubsurfaceColor(LocalScreenSpaceData.GBuffer.CustomData), r);
|
|
float ColorLum = Luminance(Color);
|
|
|
|
OutColor += float4(Color, 1) * float4(SampleDiffuseLighting(LocalUV), 1);
|
|
AccumSum += ColorLum;
|
|
}
|
|
}
|
|
}
|
|
|
|
OutColor.rgb /= AccumSum;
|
|
OutColor.a /= (2 * Count + 1);
|
|
|
|
|
|
#if METHOD >= 1
|
|
|
|
float4 SceneColor4 = Texture2DSample(PostprocessInput1, PostprocessInput1Sampler, UV);
|
|
float4 SSSColor = OutColor;
|
|
|
|
SSSColor.a = (ScreenSpaceData.GBuffer.ShadingModelID == SHADINGMODELID_SUBSURFACE);
|
|
|
|
// partly translucent surface (0.9 means 10% of the opaque is blended in)
|
|
SSSColor.a *= 0.3f;
|
|
|
|
#if METHOD > 1
|
|
// we took the specular highlights out, now we add them back in
|
|
SSSColor.rgb += ReconstructNonDiffuseLighting(SceneColor4);
|
|
#endif
|
|
|
|
OutColor = float4(lerp(SceneColor4.rgb, SSSColor.rgb, SSSColor.a), 1);
|
|
#endif
|
|
}
|