Files
UnrealEngine/Engine/Shaders/Public/SubstratePublic.ush
2025-05-18 13:04:45 +08:00

139 lines
5.1 KiB
HLSL

// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
/*=============================================================================
SubstratePublic.ush: Public facing API for external users of Substrate.
=============================================================================*/
#include "/Engine/Private/Substrate/Substrate.ush"
#if SUBSTRATE_ENABLED
#define SUBSTRATE_ALLOWS_GBUFFER_SAMPLING ((NEEDS_SCENE_TEXTURES && !SCENE_TEXTURES_DISABLED) && SUBSTRATE_MATERIALCONTAINER_IS_VIEWRESOURCE)
/** Public facing functions allowing external users access to some Substrate data. */
#ifndef SubstratePublicStruct
#error One must specify the SubstratePublicStruct uniform buffer to fetch data from when using SubstratePuclic.ush
#endif
struct FSubstrateGBuffer
{
bool bIsValid;
float3 DiffuseColor;
float3 SpecularColor;
float3 SubsurfaceColor;
float3 BaseColor;
float Specular;
float Metallic;
float3 WorldNormal;
float Opacity;
float Roughness;
float MaterialAO;
float3 ShadingModelColor;
float ShadingModelID;
float3 StoredBaseColor;
float3 StoredSpecular;
float3 WorldTangent;
float Anisotropy;
bool bIsFirstPerson;
};
FSubstrateGBuffer SubstratePublic_GetSubstrateGBufferFromFirstBSDF(uint2 PixelCoord)
{
FSubstrateGBuffer SGBuffer = (FSubstrateGBuffer)0;
SGBuffer.bIsValid = false;
SGBuffer.WorldNormal = float3(0.0, 0.0, 1.0);
#if SUBSTRATE_ALLOWS_GBUFFER_SAMPLING
FSubstrateAddressing SubstrateAddressing = GetSubstratePixelDataByteOffset(PixelCoord, uint2(View.BufferSizeAndInvSize.xy), SubstratePublicStruct.MaxBytesPerPixel);
FSubstratePixelHeader SubstratePixelHeader = UnpackSubstrateHeaderIn(SubstratePublicStruct.MaterialTextureArray, SubstrateAddressing, SubstratePublicStruct.TopLayerTexture);
BRANCH
if (SubstratePixelHeader.ClosureCount > 0)
{
const FSubstrateSubsurfaceHeader SSSHeader = SubstrateLoadSubsurfaceHeader(SubstratePublicStruct.MaterialTextureArray, SubstratePublicStruct.FirstSliceStoringSubstrateSSSData, SubstrateAddressing.PixelCoords);
const bool bSkipSSSMaterialOverride = true; // We do not want the material data to be affected by any override.
FSubstrateBSDF BSDF = UnpackSubstrateBSDFIn(SubstratePublicStruct.MaterialTextureArray, SubstrateAddressing, SubstratePixelHeader, bSkipSSSMaterialOverride);
SGBuffer.bIsValid = true;
SGBuffer.DiffuseColor = SubstrateGetBSDFDiffuseColor(BSDF);
SGBuffer.SpecularColor = SubstrateGetBSDFSpecularF0(BSDF);
SGBuffer.SubsurfaceColor = SubstrateGetBSDFSubSurfaceColor(BSDF);
SGBuffer.BaseColor = SubstrateGetBSDFBaseColor(BSDF);
SGBuffer.Specular = SubstrateGetBSDFSpecular(BSDF);
SGBuffer.Metallic = SubstrateGetBSDFMetallic(BSDF);
SGBuffer.WorldNormal = SubstrateGetWorldNormal(SubstratePixelHeader, BSDF, SubstrateAddressing);
SGBuffer.Roughness = SubstrateGetBSDFRoughness(BSDF);
SGBuffer.MaterialAO = SubstrateGetAO(SubstratePixelHeader);
SGBuffer.ShadingModelID = SubstrateGetLegacyShadingModels(BSDF);
SGBuffer.ShadingModelColor = GetShadingModelColor(SGBuffer.ShadingModelID);
SGBuffer.StoredBaseColor = SubstrateGetBSDFBaseColor(BSDF);
SGBuffer.StoredSpecular = SubstrateGetBSDFSpecular(BSDF).rrr;
SGBuffer.WorldTangent = SubstrateGetWorldTangent(SubstratePixelHeader, BSDF, SubstrateAddressing);
SGBuffer.Anisotropy = SubstrateGetBSDFAnisotropy(BSDF);
SGBuffer.bIsFirstPerson = SubstratePixelHeader.IsFirstPerson();
SGBuffer.Opacity = 0.0f;
if (SubstrateSubSurfaceHeaderGetSSSType(SSSHeader) != SSS_TYPE_NONE)
{
SGBuffer.Opacity = SubstrateSubSurfaceHeaderGetOpacity(SSSHeader);
}
else if (BSDF_GETTYPE(BSDF) == SUBSTRATE_BSDF_TYPE_SLAB)
{
if (BSDF_GETHASFUZZ(BSDF))
{
SGBuffer.Opacity = SLAB_FUZZ_AMOUNT(BSDF); // Cloth
}
else if (BSDF_GETHASHAZINESS(BSDF))
{
const FHaziness Haziness = UnpackHaziness(SLAB_HAZINESS(BSDF));
const bool bHazeAsSimpleClearCoat = Haziness.bSimpleClearCoat;
if (bHazeAsSimpleClearCoat)
{
SGBuffer.Opacity = Haziness.Weight; // ClearCoat
}
}
}
else if (BSDF_GETTYPE(BSDF) == SUBSTRATE_BSDF_TYPE_EYE)
{
SGBuffer.Opacity = 1 - EYE_IRISMASK(BSDF); // IrisMask
}
else if (BSDF_GETTYPE(BSDF) == SUBSTRATE_BSDF_TYPE_HAIR)
{
SGBuffer.Opacity = HAIR_BACKLIT(BSDF); // BackLit
}
}
else if (SubstratePixelHeader.State == 0) // Only Unlit and non written pixels have a state of 0. Those pixels should show up as unlit to respect the legacy behavior.
{
SGBuffer.bIsValid = true;
SGBuffer.ShadingModelID = SHADINGMODELID_UNLIT;
SGBuffer.ShadingModelColor = GetShadingModelColor(SGBuffer.ShadingModelID);
}
#endif
return SGBuffer;
}
// Optimised data fetch from the TopLayer texture
float3 SubstratePublic_GetWorldNormal(uint2 PixelCoord)
{
#if SUBSTRATE_ALLOWS_GBUFFER_SAMPLING
return SubstrateUnpackTopLayerData(SubstratePublicStruct.TopLayerTexture.Load(uint3(PixelCoord, 0))).WorldNormal;
#else
return float3(0, 0, 1);
#endif
}
float SubstratePublic_GetRoughness(uint2 PixelCoord)
{
#if SUBSTRATE_ALLOWS_GBUFFER_SAMPLING
return SubstrateUnpackTopLayerData(SubstratePublicStruct.TopLayerTexture.Load(uint3(PixelCoord, 0))).Roughness;
#else
return 0.0;
#endif
}
#endif