Files
UnrealEngineUWP/Engine/Shaders/PostProcessSubsurface.usf
Martin Mittring 1cbde4cefe * optimized ScreenSpaceSubsurfaceScattering (4 pass: setup, blurX, blurY, recombine)
* fixed reallocation of scene render targets because of Skylight, was wasting VRam

[CL 2317878 by Martin Mittring in Main branch]
2014-10-02 17:19:02 -04:00

284 lines
7.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"
// for VisualizeSSS
#include "MiniFontCommon.usf"
/** RGBA8 linear texture containing random normals */
Texture2D SSProfilesTexture;
SamplerState SSProfilesTextureSampler;
// x:Radius, y:DistanceToProjectionWindow, zw:xy scale correction for BufferSize!=ViewportSize
float4 SSSParams;
// ------------------------------------------
// setup for "SeparableSSS.usf"
#define SSSS_HLSL_4 1
// can be optimized
float GetSubsurfaceStrength(float2 UV)
{
FScreenSpaceData ScreenSpaceData = GetScreenSpaceData(UV);
float Mask = ScreenSpaceData.GBuffer.ShadingModelID >= SHADINGMODELID_SUBSURFACE_PROFILE;
return Mask * ScreenSpaceData.GBuffer.Opacity;
}
//#define SSSS_STREGTH_SOURCE 1 // todo: masking fom LightingModel or SSSColor
#define SSSS_STREGTH_SOURCE GetSubsurfaceStrength(texcoord)
// 0:speculars leak into SSS / 1:requires alpha channel for scenecolor
// #define SSSS_SPECULAR_CORRECTION 1
// set by C++ for SubsurfaceRecombinePS
// #define SSS_RECOMBINE_METHOD 0:without reconstruct specular/1:with reconstruct specular
// set by C++ for SubsurfacePS
// #define SSS_DIRECTION 0/1
// define by C++ for the setup pass
#ifndef SETUP_MODE
#define SETUP_MODE 0
#endif
#if SETUP_MODE == 0
#define SSSS_SPECULAR_CORRECTION 0
#define SETUP_HALF_RES 0
#elif SETUP_MODE == 1
#define SSSS_SPECULAR_CORRECTION 1
#define SETUP_HALF_RES 0
#elif SETUP_MODE == 3
#define SSSS_SPECULAR_CORRECTION 0
#define SETUP_HALF_RES 1
#elif SETUP_MODE == 4
#define SSSS_SPECULAR_CORRECTION 1
#define SETUP_HALF_RES 1
#else
// doesn't matter
#define SSSS_SPECULAR_CORRECTION 0
#endif
#if SSS_SAMPLESET == 0
#define SSSS_N_KERNELWEIGHTCOUNT 6
#define SSSS_N_KERNELWEIGHTOFFSET (13 + 9)
#elif SSS_SAMPLESET == 1
#define SSSS_N_KERNELWEIGHTCOUNT 9
#define SSSS_N_KERNELWEIGHTOFFSET 13
#else // SSS_SAMPLESET == 2
#define SSSS_N_KERNELWEIGHTCOUNT 13
#define SSSS_N_KERNELWEIGHTOFFSET 0
#endif
// 0: faster
// 1: no color bleeding in z direction
#define SSSS_FOLLOW_SURFACE 1
// from https://github.com/iryoku/separable-sss/tree/master/Demo
// Jorge Jimenez http://www.iryoku.com/
// http://www.iryoku.com/translucency/downloads/Real-Time-Realistic-Skin-Translucency.pdf
#include "SeparableSSS.usf"
// ------------------------------------------
#if SSSS_SPECULAR_CORRECTION == 1
// requires alpha channel for scenecolor
#elif SSSS_SPECULAR_CORRECTION == 0
// speculars leak into SSS
#else
error
#endif
// 0 / 1
#define VISUALIZE_KERNEL 0
bool InUnitBox(float2 UV)
{
return UV.x >= 0 && UV.y >= 0 && UV.y < 1 && UV.y < 1;
}
float3 SetupSubsurfaceForOnePixel(float2 UV)
{
float3 Ret = 0;
FScreenSpaceData ScreenSpaceData = GetScreenSpaceData(UV);
FLATTEN if (ScreenSpaceData.GBuffer.ShadingModelID >= SHADINGMODELID_SUBSURFACE_PROFILE)
{
float4 SceneColor4 = Texture2DSample(PostprocessInput0, PostprocessInput0Sampler, UV);
#if SSSS_SPECULAR_CORRECTION == 1
// we take out the specular highlights
Ret = LightAccumulator_ReconstructDiffuseLighting(SceneColor4);
#else
Ret = SceneColor4.rgb;
#endif
}
return Ret;
}
void SetupPS(in float4 UVAndScreenPos : TEXCOORD0, out float4 OutColor : SV_Target0)
{
float2 UV = UVAndScreenPos.xy;
OutColor = 0;
// if not VisualizeSSS
if (SETUP_MODE != 2)
{
#if SETUP_HALF_RES
OutColor.rgb += SetupSubsurfaceForOnePixel(UV + float2(-0.5, -0.5f) * PostprocessInput0Size.zw);
OutColor.rgb += SetupSubsurfaceForOnePixel(UV + float2( 0.5, -0.5f) * PostprocessInput0Size.zw);
OutColor.rgb += SetupSubsurfaceForOnePixel(UV + float2(-0.5, 0.5f) * PostprocessInput0Size.zw);
OutColor.rgb += SetupSubsurfaceForOnePixel(UV + float2( 0.5, 0.5f) * PostprocessInput0Size.zw);
OutColor *= 0.25f;
#else
OutColor.rgb = SetupSubsurfaceForOnePixel(UV);
#endif
}
else
{
// visualization (doesn't have to be fast)
OutColor = Texture2DSample(PostprocessInput0, PostprocessInput0Sampler, UV);
int2 PixelPos = (int2)(UVAndScreenPos.zw * ScreenPosToPixel.xy + ScreenPosToPixel.zw + 0.5f);
float2 ViewLocalUV = (PixelPos - View.ViewRectMin.xy) * View.ViewSizeAndSceneTexelSize.zw;
float2 IDAreaLocalUV = ViewLocalUV * 2 - 1.0f;
// OutColor = float4(IDAreaLocalUV.xy, 0, 0); return;
if (InUnitBox(IDAreaLocalUV))
{
FScreenSpaceData ScreenSpaceData = GetScreenSpaceData(View.ViewRectMin.xy * View.ViewSizeAndSceneTexelSize.zw + IDAreaLocalUV * (View.ViewSizeAndSceneTexelSize.xy * View.ViewSizeAndSceneTexelSize.zw));
int SubsurfaceProfileInt = ExtractSubsurfaceProfileInt(ScreenSpaceData.GBuffer);
OutColor = float4(0.5f, 0.5f, 0.5f, 0);
BRANCH if (ScreenSpaceData.GBuffer.ShadingModelID == SHADINGMODELID_SUBSURFACE_PROFILE)
{
if (SubsurfaceProfileInt == 0)
{
// default (no Profile)
OutColor = float4(0.8f, 0.7f, 0.6f, 0);
}
if (SubsurfaceProfileInt == 1)
{
OutColor = float4(1, 0, 0, 0);
}
if (SubsurfaceProfileInt == 2)
{
OutColor = float4(0, 1, 0, 0);
}
if (SubsurfaceProfileInt == 3)
{
OutColor = float4(0, 0, 1, 0);
}
if (SubsurfaceProfileInt == 4)
{
OutColor = float4(1, 0, 1, 0);
}
if (SubsurfaceProfileInt == 5)
{
OutColor = float4(0, 1, 1, 0);
}
if (SubsurfaceProfileInt == 6)
{
OutColor = float4(1, 1, 0, 0);
}
if (SubsurfaceProfileInt == 100)
{
OutColor = float4(0, 0.2f, 0, 0);
}
if (SubsurfaceProfileInt == 255)
{
OutColor = float4(1, 1, 1, 0);
}
int2 LeftTop = (PixelPos / 8) * 8;
PrintCharacter(PixelPos, OutColor.rgb, float3(1, 1, 1), LeftTop, SubsurfaceProfileInt);
}
}
}
}
// input0 is created by the SetupPS shader
void MainPS(float4 UVAndScreenPos : TEXCOORD0, out float4 OutColor : SV_Target0)
{
float2 UV = UVAndScreenPos.xy;
// call into "SeparableSSS.usf"
// in world units, *0.01 to scale from units(cm) to m
float sssWidth = SSSParams.x;
// the viewport is only a fraction of the buffersize, here we compensate for that
// *1000 as we store the sample distances / 1000 to allows for scaling
float Scaler = View.ViewSizeAndSceneTexelSize.x * View.ViewSizeAndSceneTexelSize.z * 1000.0f;
#if SSS_DIRECTION == 0
// horizontal
float2 Direction = float2(1, 0) * Scaler;
#else
// vertical
float2 Direction = float2(0, View.ViewSizeAndSceneTexelSize.w / View.ViewSizeAndSceneTexelSize.z) * Scaler;
#endif
OutColor.rgb = SSSSBlurPS(UV, sssWidth, Direction, false).rgb;
OutColor.a = 1.0f;
}
void SubsurfaceRecombinePS(float4 UVAndScreenPos : TEXCOORD0, out float4 OutColor : SV_Target0)
{
float2 UV = UVAndScreenPos.xy;
OutColor.rgb = Texture2DSample(PostprocessInput0, PostprocessInput0Sampler, UV).rgb;
OutColor.a = 1.0f;
// recombine with the scene color
// can be optimized
float2 PixelPos = UVAndScreenPos.zw * ScreenPosToPixel.xy + ScreenPosToPixel.zw;
float2 UVSceneColor = (PixelPos + 0.5f) * View.ViewSizeAndSceneTexelSize.zw;
float4 SceneColor4 = Texture2DSample(PostprocessInput1, PostprocessInput1Sampler, UVSceneColor);
float4 SSSColor = OutColor;
FScreenSpaceData ScreenSpaceData = GetScreenSpaceData(UVSceneColor);
SSSColor.a = (ScreenSpaceData.GBuffer.ShadingModelID >= SHADINGMODELID_SUBSURFACE_PROFILE);
#if SSS_RECOMBINE_METHOD
// we took the specular highlights out, now we add them back in
SSSColor.rgb += LightAccumulator_ReconstructNonDiffuseLighting(SceneColor4);
#endif
// alpha channel can be anything - we consumed the value and likely output to a format that doesn't need the value
OutColor = float4(lerp(SceneColor4.rgb, SSSColor.rgb, SSSColor.a), 0);
}