205 lines
7.1 KiB
HLSL
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
|
|
} |