231 lines
7.9 KiB
HLSL
231 lines
7.9 KiB
HLSL
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
#pragma once
|
|
|
|
// Sanity guard.
|
|
#ifndef SUBSTRATE_ENABLED
|
|
#define SUBSTRATE_ENABLED 1
|
|
#error SUBSTRATE_ENABLED needs to be defined
|
|
#endif
|
|
|
|
#if SUBSTRATE_ENABLED
|
|
|
|
#include "../Common.ush"
|
|
#include "Substrate.ush"
|
|
#include "/Engine/Private/DeferredShadingCommon.ush"
|
|
|
|
struct FSubstrateGBufferBSDF
|
|
{
|
|
FSubstrateBSDF BSDF;
|
|
float3x3 BSDFTangentBasis;
|
|
float BSDFAO;
|
|
};
|
|
|
|
FSubstrateGBufferBSDF SubstrateReadGBufferBSDF(in FScreenSpaceData ScreenSpaceData)
|
|
{
|
|
const FGBufferData GBuffer = ScreenSpaceData.GBuffer;
|
|
|
|
FSubstrateBSDF BSDF = (FSubstrateBSDF)0;
|
|
float3x3 BSDFTangentBasis = (float3x3)0;
|
|
float BSDFAO = 0.0f;
|
|
|
|
#if SUBSTRATE_COMPLEXPATH
|
|
if (GBuffer.Anisotropy != 0)
|
|
{
|
|
BSDFTangentBasis[0] = GBuffer.WorldTangent;
|
|
BSDFTangentBasis[1] = cross(GBuffer.WorldNormal, GBuffer.WorldTangent);
|
|
BSDFTangentBasis[2] = GBuffer.WorldNormal;
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
BSDFTangentBasis = GetTangentBasis(GBuffer.WorldNormal);
|
|
}
|
|
|
|
BSDFAO = ScreenSpaceData.AmbientOcclusion;
|
|
|
|
{
|
|
FSubstratePixelFootprint Footprint = SubstrateGetPixelFootprint(1.0f, 1.0f, GBuffer.Curvature);
|
|
|
|
const float3 Emissive = 0.0f;
|
|
const float SpecularProfileId = 0.0f;
|
|
|
|
const float GlintValue = 1.0f;
|
|
const float2 GlintUV = 0.0f;
|
|
const float2 GlintUVdx = 0.0f;
|
|
const float2 GlintUVdy = 0.0f;
|
|
|
|
float3 SSSMFP = 0.0f;
|
|
float SSSMFPScale = 1.0f;
|
|
float SSSPhaseAnisotropy = 0.0f;
|
|
|
|
float SecondRoughness = 0.0f;
|
|
float SecondRoughnessWeight = 0.0f;
|
|
float SecondRoughnessAsSimpleClearCoat = 0.0f;
|
|
|
|
float FuzzAmount = 0.0f;
|
|
float3 FuzzColor = 0.0f;
|
|
float FuzzRoughness = 0.0f;
|
|
|
|
uint SSSProfileID = SSS_PROFILE_ID_INVALID;
|
|
uint SSSType = SSS_TYPE_NONE;
|
|
float ThicknessCm = 1.0f;
|
|
bool bIsThinSurface = false;
|
|
|
|
// Directly use DiffuseColor and SpecularColor (instead of ComputeDiffuseAlbedo() / ComputeF0() with BaseColor, Metallic, Specular),
|
|
// as they contain Diffuse/Specular override which are used for view modes.
|
|
float3 DiffuseAlbedo = GBuffer.DiffuseColor;
|
|
float3 F0 = GBuffer.SpecularColor;
|
|
float3 F90 = 1.0f;
|
|
|
|
float ClearCoatUseSecondNormal = 0.0f;
|
|
float3 ClearCoatBottomNormal = GBuffer.WorldNormal;
|
|
|
|
bool bIsAtTheBottomOfTopology = true;
|
|
uint SharedLocalBasisIndex = 0;
|
|
uint SharedLocalBasisTypes = 0;
|
|
|
|
#if SUBSTRATE_COMPLEXPATH
|
|
if (GBuffer.ShadingModelID == SHADINGMODELID_HAIR)
|
|
{
|
|
const float Scatter = GBuffer.Metallic;
|
|
const float BackLit = GBuffer.CustomData.b;
|
|
BSDF = GetSubstrateHairBSDF(GBuffer.BaseColor, Scatter, GBuffer.Specular, GBuffer.Roughness, BackLit, Emissive, SharedLocalBasisIndex).InlinedBSDF;
|
|
|
|
}
|
|
else if (GBuffer.ShadingModelID == SHADINGMODELID_EYE)
|
|
{
|
|
SSSProfileID = ExtractSubsurfaceProfileInt(GBuffer);
|
|
const float IrisMask = 1.0f - GBuffer.CustomData.w;
|
|
float IrisDistance = 0.0;
|
|
float3 IrisNormal = GBuffer.WorldNormal;
|
|
float3 IrisPlaneNormal = GBuffer.WorldNormal;
|
|
|
|
#if IRIS_NORMAL
|
|
const float2 IrisNormalDelta = float2(GBuffer.CustomData.y, GBuffer.CustomData.z) * 2 - (256.0 / 255.0);
|
|
const float2 WorldNormalOct = UnitVectorToOctahedron(GBuffer.WorldNormal);
|
|
IrisNormal = OctahedronToUnitVector(WorldNormalOct + IrisNormalDelta);
|
|
IrisDistance = 1.0; // Set at 1 in order to let's the mask drive the interpolation. See SubstrateEvaluation.ush.
|
|
#else
|
|
IrisNormal = OctahedronToUnitVector(GBuffer.CustomData.yz * 2 - 1);
|
|
IrisPlaneNormal = IrisNormal;
|
|
IrisDistance = GBuffer.StoredMetallic;
|
|
#endif
|
|
BSDF = GetSubstrateEyeBSDF(DiffuseAlbedo, F0, GBuffer.Roughness, IrisMask, IrisDistance, IrisNormal, IrisPlaneNormal, SSSProfileID, Emissive, SharedLocalBasisIndex).InlinedBSDF;
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
#if SUBSTRATE_SINGLEPATH || SUBSTRATE_COMPLEXPATH
|
|
if (GBuffer.ShadingModelID == SHADINGMODELID_CLOTH)
|
|
{
|
|
FuzzColor = ExtractSubsurfaceColor(GBuffer);
|
|
FuzzAmount = GBuffer.CustomData.a;
|
|
FuzzRoughness = 0.5f; // Fuzz roughness is not stored into the gbuffer. Using GBuffer.Roughness it not ideal as low value, makes most of the fuzz contribution to vanish. Instead hardcode value.
|
|
}
|
|
else if (GBuffer.ShadingModelID == SHADINGMODELID_SUBSURFACE_PROFILE || GBuffer.ShadingModelID == SHADINGMODELID_PREINTEGRATED_SKIN)
|
|
{
|
|
SSSType = SSS_TYPE_DIFFUSION; // SSS_TYPE_DIFFUSION_PROFILE will be selected in InternalGetSubstrateSlabBSDF based on SSSProfileID and SSSMFPScale.
|
|
SSSMFP = 0;
|
|
SSSProfileID = ExtractSubsurfaceProfileInt(GBuffer);
|
|
SSSMFPScale = GBuffer.CustomData.a;
|
|
SSSPhaseAnisotropy = 0.93f;
|
|
}
|
|
else if (GBuffer.ShadingModelID == SHADINGMODELID_SUBSURFACE)
|
|
{
|
|
SSSType = SSS_TYPE_WRAP;
|
|
{
|
|
// See SubstrateGetBSDFSubSurfaceColor
|
|
float3 Extinction = TransmittanceToExtinction(ExtractSubsurfaceColor(GBuffer), SUBSTRATE_SIMPLEVOLUME_THICKNESS_CM * CENTIMETER_TO_METER);
|
|
SSSMFP = (1.0f / max(SUBSTRATE_EPSILON, Extinction));
|
|
}
|
|
SSSPhaseAnisotropy = 1.f - GBuffer.CustomData.a;
|
|
SSSMFPScale = 1.0f;
|
|
}
|
|
else if (GBuffer.ShadingModelID == SHADINGMODELID_TWOSIDED_FOLIAGE)
|
|
{
|
|
SSSType = SSS_TYPE_TWO_SIDED_WRAP;
|
|
{
|
|
// See SubstrateGetBSDFSubSurfaceColor
|
|
float3 Extinction = TransmittanceToExtinction(ExtractSubsurfaceColor(GBuffer), SUBSTRATE_SIMPLEVOLUME_THICKNESS_CM * CENTIMETER_TO_METER);
|
|
SSSMFP = (1.0f / max(SUBSTRATE_EPSILON, Extinction));
|
|
}
|
|
SSSPhaseAnisotropy = 1.f - GBuffer.CustomData.a;
|
|
SSSMFPScale = 1.0f;
|
|
}
|
|
else if (GBuffer.ShadingModelID == SHADINGMODELID_CLEAR_COAT)
|
|
{
|
|
#if SUBSTRATE_FASTPATH==0 && CLEAR_COAT_BOTTOM_NORMAL
|
|
ClearCoatUseSecondNormal = 1.0f;
|
|
const float2 oct1 = ((float2(GBuffer.CustomData.a, GBuffer.CustomData.z) * 4) - (512.0 / 255.0)) + UnitVectorToOctahedron(GBuffer.WorldNormal);
|
|
ClearCoatBottomNormal = OctahedronToUnitVector(oct1);
|
|
#endif
|
|
|
|
SecondRoughnessWeight = GBuffer.CustomData.x;
|
|
SecondRoughness = GBuffer.CustomData.y;
|
|
SecondRoughnessAsSimpleClearCoat = (SecondRoughnessWeight > 0.0f || any(GBuffer.WorldNormal != ClearCoatBottomNormal)) ? 1.0f : 0.0f;
|
|
}
|
|
#endif
|
|
|
|
BSDF = InternalGetSubstrateSlabBSDF(
|
|
Footprint,
|
|
GBuffer.WorldNormal,
|
|
DiffuseAlbedo, F0, F90,
|
|
GBuffer.Roughness, GBuffer.Anisotropy,
|
|
SSSProfileID, true /*bSupportDefaultSSSProfile*/, SSSMFP, SSSMFPScale, SSSPhaseAnisotropy, SSSType,
|
|
Emissive,
|
|
SecondRoughness, SecondRoughnessWeight, SecondRoughnessAsSimpleClearCoat,
|
|
ClearCoatUseSecondNormal, ClearCoatBottomNormal,
|
|
FuzzAmount, FuzzColor, FuzzRoughness,
|
|
GlintValue, GlintUV, GlintUVdx, GlintUVdy,
|
|
SpecularProfileId,
|
|
ThicknessCm,
|
|
bIsThinSurface,
|
|
bIsAtTheBottomOfTopology,
|
|
SharedLocalBasisIndex, SharedLocalBasisTypes,
|
|
true /*bSupportSSSDiffusion*/).InlinedBSDF;
|
|
|
|
SLAB_SSSMFP(BSDF) = SanitizeSSSMFP(SLAB_SSSMFP(BSDF));
|
|
}
|
|
|
|
#if SUBSTRATE_INLINE_SHADING && !RAYTRACINGSHADER
|
|
BSDF.Coverage = 1;
|
|
BSDF.Emissive = 0;
|
|
BSDF.ThicknessCm = (SSSType == SSS_TYPE_WRAP || SSSType == SSS_TYPE_TWO_SIDED_WRAP) ? SUBSTRATE_SIMPLEVOLUME_THICKNESS_CM : SUBSTRATE_LAYER_DEFAULT_THICKNESS_CM; // Identity rescaling in InternalGetSubstrateSlabBSDF
|
|
BSDF.TmpMFP = SSSMFP;
|
|
BSDF.TopLayerDataWeight = 1;
|
|
#endif
|
|
|
|
BSDF.OperatorIndex = 0;
|
|
BSDF.LuminanceWeightV = 1.0f;
|
|
BSDF.CoverageAboveAlongN = 0.0f;
|
|
BSDF.TransmittanceAboveAlongN = 1.0f;
|
|
BSDF.bIsBottom = true;
|
|
BSDF.bIsTop = true;
|
|
BSDF_SETISTOPLAYER(BSDF, 1);
|
|
}
|
|
|
|
FSubstrateGBufferBSDF Out;
|
|
Out.BSDF = BSDF;
|
|
Out.BSDFTangentBasis = BSDFTangentBasis;
|
|
Out.BSDFAO = BSDFAO;
|
|
return Out;
|
|
}
|
|
|
|
FSubstrateBSDF UnpackSubstrateBSDFIn(inout FSubstrateAddressing SubstrateAddressing)
|
|
{
|
|
FSubstrateGBufferBSDF GBufferBSDF = (FSubstrateGBufferBSDF)0;
|
|
#if SHADING_PATH_DEFERRED
|
|
#if FEATURE_LEVEL >= FEATURE_LEVEL_SM5
|
|
FScreenSpaceData ScreenSpaceData = GetScreenSpaceDataUint(SubstrateAddressing.PixelCoords);
|
|
#else
|
|
const float2 UV = (float2(SubstrateAddressing.PixelCoords) + 0.5f) * View.BufferSizeAndInvSize.zw;
|
|
FScreenSpaceData ScreenSpaceData = GetScreenSpaceData(UV);
|
|
#endif
|
|
GBufferBSDF = SubstrateReadGBufferBSDF(ScreenSpaceData);
|
|
#endif
|
|
return GBufferBSDF.BSDF;
|
|
}
|
|
|
|
#endif // SUBSTRATE_ENABLED
|