138 lines
6.2 KiB
HLSL
138 lines
6.2 KiB
HLSL
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
/*=============================================================================
|
|
SSProfilePreIntegratedMobile.usf
|
|
=============================================================================*/
|
|
|
|
#include "Common.ush"
|
|
#include "BurleyNormalizedSSSCommon.ush"
|
|
|
|
uint SourceSubsurfaceProfileInt;
|
|
float4 TargetSSProfilesPreIntegratedTextureSizeAndInvSize;
|
|
float4 SourceSSProfilesTextureSizeAndInvSize;
|
|
Texture2D SourceSSProfilesTexture;
|
|
SamplerState SourceSSProfilesSampler;
|
|
|
|
float4 GetSourceSubsurfaceProfileTexture(uint InSampleIndex, uint InSubsurfaceProfileInt)
|
|
{
|
|
return GetSubsurfaceProfileTexture(SourceSSProfilesTexture, SourceSSProfilesSampler, SourceSSProfilesTextureSizeAndInvSize, InSampleIndex, InSubsurfaceProfileInt);
|
|
}
|
|
|
|
bool IsSubsurfaceProfileUseBurley()
|
|
{
|
|
// 0..255, which SubSurface profile to pick
|
|
float Type = GetSourceSubsurfaceProfileTexture(SSSS_BOUNDARY_COLOR_BLEED_OFFSET, SourceSubsurfaceProfileInt).a;
|
|
|
|
return abs(Type - SSS_TYPE_BURLEY) < 0.01f;
|
|
}
|
|
|
|
float3 BurleyUnit(float Angle, float3 Sharpness)
|
|
{
|
|
return exp(Sharpness * Angle);
|
|
}
|
|
|
|
// The integral of cos(x) * e^(a * x)
|
|
float3 IntegralCosineWithExponent(float Angle, float SinAngle, float CosAngle, float3 Sharpness)
|
|
{
|
|
return (SinAngle + Sharpness * CosAngle) * BurleyUnit(Angle, Sharpness) / (1 + Sharpness * Sharpness);
|
|
}
|
|
|
|
// The integral of sin(x) * e^(a * x)
|
|
float3 IntegralSineWithExponent(float Angle, float SinAngle, float CosAngle, float3 Sharpness)
|
|
{
|
|
return (-CosAngle + Sharpness * SinAngle) * BurleyUnit(Angle, Sharpness) / (1 + Sharpness * Sharpness);
|
|
}
|
|
|
|
// Theta is the angle between N and L, BurleyA is -((s * r) / m) * 2 / PI, BurleyB is BurleyA / 3
|
|
float3 ApproximationRingIntegralOfBurleyDiffusion(float Angle, float SinAngle, float CosAngle, float Theta, float CosTheta, float SinTheta, float3 BurleyA, float3 BurleyB)
|
|
{
|
|
return CosTheta * (IntegralCosineWithExponent(Angle, SinAngle, CosAngle, BurleyA) + IntegralCosineWithExponent(Angle, SinAngle, CosAngle, BurleyB))
|
|
-SinTheta * (IntegralSineWithExponent(Angle, SinAngle, CosAngle, BurleyA) + IntegralSineWithExponent(Angle, SinAngle, CosAngle, BurleyB));
|
|
}
|
|
|
|
float3 IntegralBurleyUnit(float Angle, float3 Sharpness)
|
|
{
|
|
return (1 / Sharpness) * BurleyUnit(Angle, Sharpness);
|
|
}
|
|
|
|
float3 IntegralBurleyDiffusion(float Angle, float3 BurleyA, float3 BurleyB)
|
|
{
|
|
return IntegralBurleyUnit(Angle, BurleyA) + IntegralBurleyUnit(Angle, BurleyB);
|
|
}
|
|
|
|
float4 GetIrradianceFromBurleyDiffusionOnRing(float4 SurfaceAlbedo, float4 DiffuseMeanFreePath, float Curvature, float Theta, float CosTheta, float SinTheta)
|
|
{
|
|
const float HalfPI = PI * 0.5f;
|
|
|
|
float3 S3D = GetScalingFactor3D(SurfaceAlbedo.xyz);
|
|
|
|
// d = DiffuseMeanFreePath / S;
|
|
// r = 1.0f / Curvature;
|
|
// d / r = DiffuseMeanFreePath.xyz * Curvature / S3D;
|
|
// Multiply 7.0f / 3.0f / PI to be close to the range of 2 * sin(x/2);
|
|
float3 BurleyA = (-1.0f * S3D / (DiffuseMeanFreePath.xyz * Curvature)) * 2.0f / PI;
|
|
|
|
float3 BurleyB = BurleyA / 3.0f;
|
|
|
|
// Integral on the ring (from -PI to PI) to normalize the final integral.
|
|
float3 IntegralOnRing = 2 * (IntegralBurleyDiffusion(PI, BurleyA, BurleyB) - IntegralBurleyDiffusion(0.0f, BurleyA, BurleyB));
|
|
|
|
float3 IntegralOnNegativeAngle, IntegralOnPositiveAngle, BurleyDiffuse;
|
|
if (Theta <= HalfPI)
|
|
{
|
|
// Integral from -(PI/2 + Theta) to 0.
|
|
float AngleStart = -(HalfPI + Theta);
|
|
IntegralOnNegativeAngle = ApproximationRingIntegralOfBurleyDiffusion(0.0f, 0.0f, 1.0f, Theta, CosTheta, SinTheta, -BurleyA, -BurleyB) - ApproximationRingIntegralOfBurleyDiffusion(AngleStart, sin(AngleStart), cos(AngleStart), Theta, CosTheta, SinTheta, -BurleyA, -BurleyB);
|
|
|
|
// Integral from 0 to PI/2 - Theta
|
|
float AngleEnd = HalfPI - Theta;
|
|
IntegralOnPositiveAngle = ApproximationRingIntegralOfBurleyDiffusion(AngleEnd, sin(AngleEnd), cos(AngleEnd), Theta, CosTheta, SinTheta, BurleyA, BurleyB) - ApproximationRingIntegralOfBurleyDiffusion(0.0f, 0.0f, 1.0f, Theta, CosTheta, SinTheta, BurleyA, BurleyB);
|
|
|
|
}
|
|
else
|
|
{
|
|
// Integral from -PI to PI/2 - Theta.
|
|
float AngleEnd = HalfPI - Theta;
|
|
IntegralOnNegativeAngle = ApproximationRingIntegralOfBurleyDiffusion(AngleEnd, sin(AngleEnd), cos(AngleEnd), Theta, CosTheta, SinTheta, -BurleyA, -BurleyB) - ApproximationRingIntegralOfBurleyDiffusion(-PI, 0.0f, -1.0f, Theta, CosTheta, SinTheta, -BurleyA, -BurleyB);
|
|
|
|
// Integral from 3*PI/2 - Theta to PI
|
|
float AngleStart = HalfPI * 3 - Theta;
|
|
IntegralOnPositiveAngle = ApproximationRingIntegralOfBurleyDiffusion(PI, 0.0f, -1.0f, Theta, CosTheta, SinTheta, BurleyA, BurleyB) - ApproximationRingIntegralOfBurleyDiffusion(AngleStart, sin(AngleStart), cos(AngleStart), Theta, CosTheta, SinTheta, BurleyA, BurleyB);
|
|
|
|
}
|
|
|
|
BurleyDiffuse = (IntegralOnNegativeAngle + IntegralOnPositiveAngle) / IntegralOnRing;
|
|
|
|
// float3 IntegralOnPI = ApproximationRingIntegralOfBurleyDiffusion(PI, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f, BurleyA, BurleyB);
|
|
|
|
// float3 ScatteringFactor3D = 2.0f * (ApproximationRingIntegralOfBurleyDiffusion(PI, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f, BurleyA, BurleyB) - IntegralOnPI) / IntegralOnRing;
|
|
|
|
// float ScatteringFactor = max3(ScatteringFactor3D.x, ScatteringFactor3D.y, ScatteringFactor3D.z);
|
|
|
|
return float4(BurleyDiffuse, 1.0f);
|
|
}
|
|
|
|
void SSProfilePreIntegratedPS(
|
|
in float4 SvPosition : SV_POSITION,
|
|
out HALF4_TYPE OutColor : SV_Target0)
|
|
{
|
|
OutColor = HALF4_TYPE(1.0f, 1.0f, 1.0f, 0.0f);
|
|
|
|
float2 UVPos = SvPosition.xy * TargetSSProfilesPreIntegratedTextureSizeAndInvSize.zw;
|
|
|
|
float UnClampedNoL = UVPos.x * 2.0f - 1.0f;
|
|
float Curvature = UVPos.y;
|
|
|
|
uint SurfaceAlbedoSampleIndex = BSSS_SURFACEALBEDO_OFFSET;
|
|
uint DiffuseMeanFreePathSampleIndex = BSSS_DMFP_OFFSET;
|
|
|
|
float4 SurfaceAlbedo = GetSourceSubsurfaceProfileTexture(SurfaceAlbedoSampleIndex, SourceSubsurfaceProfileInt);
|
|
float WorldUnitScale = DecodeWorldUnitScale(GetSourceSubsurfaceProfileTexture(SSSS_TINT_SCALE_OFFSET, SourceSubsurfaceProfileInt).a) * BURLEY_CM_2_MM;
|
|
float4 DiffuseMeanFreePath = max(DecodeDiffuseMeanFreePath(GetSourceSubsurfaceProfileTexture(DiffuseMeanFreePathSampleIndex, SourceSubsurfaceProfileInt)) * WorldUnitScale, 0.01f);;
|
|
|
|
float CosTheta = UnClampedNoL;
|
|
float Theta = acos(CosTheta);
|
|
float SinTheta = sin(Theta);
|
|
|
|
OutColor = GetIrradianceFromBurleyDiffusionOnRing(SurfaceAlbedo, DiffuseMeanFreePath, Curvature, Theta, CosTheta, SinTheta);
|
|
} |