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

205 lines
7.1 KiB
HLSL

// Copyright Epic Games, Inc. All Rights Reserved.
/*=============================================================================
ShadingModelsMaterial.usf: Pixel shader function for computing a GBuffer from shading model.
=============================================================================*/
#include "SubsurfaceProfileCommon.ush"
// Optimization: if opacity is 0 then revert to default shading model
#define SUBSURFACE_PROFILE_OPACITY_THRESHOLD 1
void SetGBufferForShadingModel(
in out FGBufferData GBuffer,
in out FMaterialPixelParameters MaterialParameters,
FPixelMaterialInputs PixelMaterialInputs,
const float Opacity,
const half3 BaseColor,
const half Metallic,
const half Specular,
const float Roughness,
const float Anisotropy,
const float3 SubsurfaceColor,
const float SubsurfaceProfile,
const float Dither,
const uint ShadingModel)
{
GBuffer.WorldNormal = MaterialParameters.WorldNormal;
GBuffer.WorldTangent = MaterialParameters.WorldTangent;
GBuffer.BaseColor = BaseColor;
GBuffer.Metallic = Metallic;
GBuffer.Specular = Specular;
GBuffer.Roughness = Roughness;
GBuffer.Anisotropy = Anisotropy;
GBuffer.ShadingModelID = ShadingModel;
// Calculate and set custom data for the shading models that need it
// Dummy initial if statement to play nicely with the #ifdef logic
if (false)
{
}
#if MATERIAL_SHADINGMODEL_SUBSURFACE
else if (ShadingModel == SHADINGMODELID_SUBSURFACE)
{
GBuffer.CustomData.rgb = EncodeSubsurfaceColor(SubsurfaceColor);
GBuffer.CustomData.a = Opacity;
}
#endif
#if MATERIAL_SHADINGMODEL_PREINTEGRATED_SKIN
else if (ShadingModel == SHADINGMODELID_PREINTEGRATED_SKIN)
{
GBuffer.CustomData.rgb = EncodeSubsurfaceColor(SubsurfaceColor);
GBuffer.CustomData.a = Opacity;
}
#endif
#if MATERIAL_SHADINGMODEL_SUBSURFACE_PROFILE
else if (ShadingModel == SHADINGMODELID_SUBSURFACE_PROFILE)
{
// Optimization: if opacity is 0 then revert to default shading model
#if SUBSURFACE_PROFILE_OPACITY_THRESHOLD
if (Opacity > SSSS_OPACITY_THRESHOLD_EPS)
#endif
{
GBuffer.CustomData.rgb = EncodeSubsurfaceProfile(SubsurfaceProfile);
GBuffer.CustomData.a = Opacity;
#if SHADING_PATH_MOBILE
#if MATERIAL_SUBSURFACE_PROFILE_USE_CURVATURE
GBuffer.Curvature = GetMaterialCustomData0(PixelMaterialInputs);
#else
GBuffer.Curvature = CalculateCurvature(GBuffer.WorldNormal, MaterialParameters.WorldPosition_CamRelative);
#endif
GBuffer.Curvature = clamp(GBuffer.Curvature, 0.001f, 1.0f);
#endif
}
#if SUBSURFACE_PROFILE_OPACITY_THRESHOLD
else
{
GBuffer.ShadingModelID = SHADINGMODELID_DEFAULT_LIT;
GBuffer.CustomData = 0;
}
#endif
}
#endif
#if MATERIAL_SHADINGMODEL_CLEAR_COAT
else if (ShadingModel == SHADINGMODELID_CLEAR_COAT)
{
float ClearCoat = saturate( GetMaterialCustomData0(PixelMaterialInputs) );
float ClearCoatRoughness = saturate( GetMaterialCustomData1(PixelMaterialInputs) );
GBuffer.CustomData.x = ClearCoat;
GBuffer.CustomData.y = ClearCoatRoughness;
// Clamp roughness to guarantee functional inverse when computing SphereSinAlpha for multiple layers
GBuffer.Roughness = clamp(GBuffer.Roughness, 0.0, 254.0 / 255.0);
#if CLEAR_COAT_BOTTOM_NORMAL
{
float2 oct2 = UnitVectorToOctahedron(GBuffer.WorldNormal);
#if NUM_MATERIAL_OUTPUTS_CLEARCOATBOTTOMNORMAL > 0
#if MATERIAL_TANGENTSPACENORMAL
float3 tempnormal = normalize(TransformTangentVectorToWorld( MaterialParameters.TangentToWorld, ClearCoatBottomNormal0(MaterialParameters) ));
#else
float3 tempnormal = ClearCoatBottomNormal0(MaterialParameters);
#endif
float2 oct1 = UnitVectorToOctahedron(tempnormal);
float2 oct3 = ( (oct1 - oct2) * 0.25 ) + (128.0/255.0);
GBuffer.CustomData.a = oct3.x;
GBuffer.CustomData.z = oct3.y;
#else
GBuffer.CustomData.a = 128.0/255.0;
GBuffer.CustomData.z = 128.0/255.0;
#endif
}
#endif
}
#endif
#if MATERIAL_SHADINGMODEL_TWOSIDED_FOLIAGE
else if (ShadingModel == SHADINGMODELID_TWOSIDED_FOLIAGE)
{
GBuffer.CustomData.rgb = EncodeSubsurfaceColor(SubsurfaceColor);
GBuffer.CustomData.a = Opacity;
}
#endif
#if MATERIAL_SHADINGMODEL_HAIR
else if (ShadingModel == SHADINGMODELID_HAIR)
{
GBuffer.CustomData.xy = UnitVectorToOctahedron( MaterialParameters.WorldNormal ) * 0.5 + 0.5;
GBuffer.CustomData.z = saturate( GetMaterialCustomData0(PixelMaterialInputs) ); // Backlit
}
#endif
#if MATERIAL_SHADINGMODEL_CLOTH
else if (ShadingModel == SHADINGMODELID_CLOTH)
{
GBuffer.CustomData.rgb = EncodeSubsurfaceColor(SubsurfaceColor);
GBuffer.CustomData.a = saturate( GetMaterialCustomData0(PixelMaterialInputs) ); // Cloth
GBuffer.IndirectIrradiance *= 1 - GBuffer.CustomData.a;
}
#endif
#if MATERIAL_SHADINGMODEL_EYE
else if (ShadingModel == SHADINGMODELID_EYE)
{
const float IrisMask = saturate(GetMaterialCustomData0(PixelMaterialInputs));
const float IrisDistance = saturate(GetMaterialCustomData1(PixelMaterialInputs));
GBuffer.CustomData.x = EncodeSubsurfaceProfile(SubsurfaceProfile).x;
GBuffer.CustomData.w = 1.0f - IrisMask; // Opacity
#if IRIS_NORMAL
float2 WorldNormalOct = UnitVectorToOctahedron( GBuffer.WorldNormal );
// CausticNormal stored as octahedron
#if NUM_MATERIAL_OUTPUTS_GETTANGENTOUTPUT > 0
// Blend in the negative intersection normal to create some concavity
// Not great as it ties the concavity to the convexity of the cornea surface
// No good justification for that. On the other hand, if we're just looking to
// introduce some concavity, this does the job.
float3 PlaneNormal = normalize( GetTangentOutput0(MaterialParameters) );
float3 CausticNormal = normalize( lerp( PlaneNormal, -GBuffer.WorldNormal, IrisMask*IrisDistance ) );
float2 CausticNormalOct = UnitVectorToOctahedron( CausticNormal );
float2 CausticNormalDelta = ( CausticNormalOct - WorldNormalOct ) * 0.5 + (128.0/255.0);
GBuffer.Metallic = CausticNormalDelta.x;
GBuffer.Specular = CausticNormalDelta.y;
#else
float3 PlaneNormal = GBuffer.WorldNormal;
GBuffer.Metallic = 128.0/255.0;
GBuffer.Specular = 128.0/255.0;
#endif
// IrisNormal CustomData.yz
#if NUM_MATERIAL_OUTPUTS_CLEARCOATBOTTOMNORMAL > 0
float3 IrisNormal = normalize( ClearCoatBottomNormal0(MaterialParameters) );
#if MATERIAL_TANGENTSPACENORMAL
IrisNormal = normalize( TransformTangentVectorToWorld( MaterialParameters.TangentToWorld, IrisNormal ) );
#endif
#else
float3 IrisNormal = PlaneNormal;
#endif
float2 IrisNormalOct = UnitVectorToOctahedron( IrisNormal );
float2 IrisNormalDelta = ( IrisNormalOct - WorldNormalOct ) * 0.5 + (128.0/255.0);
GBuffer.CustomData.yz = IrisNormalDelta;
#else
GBuffer.Metallic = IrisDistance;
#if NUM_MATERIAL_OUTPUTS_GETTANGENTOUTPUT > 0
float3 Tangent = GetTangentOutput0(MaterialParameters);
GBuffer.CustomData.yz = UnitVectorToOctahedron( normalize(Tangent) ) * 0.5 + 0.5;
#endif
#endif
#if SHADING_PATH_MOBILE
#if MATERIAL_SHADINGMODEL_EYE_USE_CURVATURE
GBuffer.Curvature = Metallic;
#else
GBuffer.Curvature = CalculateCurvature(GBuffer.WorldNormal, MaterialParameters.WorldPosition_CamRelative);
#endif
GBuffer.Curvature = clamp(GBuffer.Curvature, 0.001f, 1.0f);
#endif
}
#endif
}