UE4阴影渲染-Shader-ShadowDepthVertexShader.usf

// Copyright Epic Games, Inc. All Rights Reserved.

/*=============================================================================
	ShadowDepthVertexShader.usf: Vertex shader for writing shadow depth.
=============================================================================*/

// needs to before Common.usf
#define SHADOW_DEPTH_SHADER 1
#define USE_STENCIL_LOD_DITHER	0

#include "LPVListEntry.ush"
#include "Common.ush"

// Reroute SceneTexturesStruct uniform buffer references to the shadow depth pass uniform buffer
#if FEATURE_LEVEL >= FEATURE_LEVEL_SM5
#define PassStruct ShadowDepthPass
#define SceneTexturesStruct ShadowDepthPass.SceneTextures 
#else
#define PassStruct MobileShadowDepthPass
#define MobileSceneTextures MobileShadowDepthPass.SceneTextures 
#endif

#include "/Engine/Generated/Material.ush"
#include "/Engine/Generated/VertexFactory.ush"
#include "ShadowDepthCommon.ush"

void SetShadowDepthOutputs(
	float4x4 WorldToClipMatrix, 
	float4x4 WorldToShadowMatrix, 
	float4 WorldPosition, 
	float3 WorldVertexNormal, 
	out float4 OutPosition, 
	out float ShadowDepth
#if PERSPECTIVE_CORRECT_DEPTH
	, out float OutDepthBias
#endif
)
{
	OutPosition = mul(WorldPosition, WorldToClipMatrix);

	// Clamp the vertex to the near plane if it is in front of the near plane
	// This has problems if some vertices of a triangle get clamped and others do not, also causes artifacts with non-ortho projections
	if (PassStruct.bClampToNearPlane > 0 && OutPosition.z < 0)
	{
		OutPosition.z = 0.000001f;
		OutPosition.w = 1.0f;
	}

	#if ONEPASS_POINTLIGHT_SHADOW
	const float3 ViewDirection = -normalize(mul(WorldPosition, WorldToShadowMatrix).xyz);
	const float3 ViewNormal = mul(float4(WorldVertexNormal,0), WorldToShadowMatrix).xyz;
	const float NoL = abs(dot(ViewDirection, ViewNormal));
	#else
	const float NoL = abs(dot(
		float3(WorldToShadowMatrix[0].z, WorldToShadowMatrix[1].z, WorldToShadowMatrix[2].z),
		WorldVertexNormal));
	#endif

	const float MaxSlopeDepthBias = PassStruct.ShadowParams.z;
	const float Slope = clamp(abs(NoL) > 0 ? sqrt(saturate(1 - NoL*NoL)) / NoL : MaxSlopeDepthBias, 0, MaxSlopeDepthBias);
	
	const float SlopeDepthBias = PassStruct.ShadowParams.y;
	const float SlopeBias = SlopeDepthBias * Slope;

	const float ConstantDepthBias = PassStruct.ShadowParams.x;
	const float DepthBias = SlopeBias + ConstantDepthBias;

	#if PERSPECTIVE_CORRECT_DEPTH
		ShadowDepth = OutPosition.z;
		OutDepthBias = DepthBias;
	#elif ONEPASS_POINTLIGHT_SHADOW
		ShadowDepth = 0;
		//OutPosition.z += DepthBias;
	#else
		// Output linear, normalized depth
		const float InvMaxSubjectDepth = PassStruct.ShadowParams.w;
		ShadowDepth = OutPosition.z * InvMaxSubjectDepth + DepthBias;
		OutPosition.z = ShadowDepth * OutPosition.w;
	#endif
}

#if FEATURE_LEVEL >= FEATURE_LEVEL_SM4 && ONEPASS_POINTLIGHT_SHADOW

// Layer Id per draw call for Vertex-Shader-Layer implementation
#if VERTEXSHADER && USING_VERTEX_SHADER_LAYER
uint LayerId;
#endif

struct FShadowDepthGSToPS
{
#if INTERPOLATE_VF_ATTRIBUTES
	FShadowDepthVSToPS PSInputs;
#endif
	float4 OutPosition : SV_POSITION;

	/** Controls which of the cube map faces to rasterize the primitive to, only the value from the first vertex is used. */
	uint RTIndex : SV_RenderTargetArrayIndex;
};

bool IsTriangleInFrustum(float4 ClipSpacePositions[3])
{
	float4 FrustumTests0 = saturate(ClipSpacePositions[0].xyxy * float4(-1, -1, 1, 1) - ClipSpacePositions[0].w);
	float4 FrustumTests1 = saturate(ClipSpacePositions[1].xyxy * float4(-1, -1, 1, 1) - ClipSpacePositions[1].w);
	float4 FrustumTests2 = saturate(ClipSpacePositions[2].xyxy * float4(-1, -1, 1, 1) - ClipSpacePositions[2].w);
	float4 FrustumTests = FrustumTests0 * FrustumTests1 * FrustumTests2;

	float2 FrustumTestsZ0 = saturate(ClipSpacePositions[0].zz * float2(-1, 1) - ClipSpacePositions[0].w);
	float2 FrustumTestsZ1 = saturate(ClipSpacePositions[1].zz * float2(-1, 1) - ClipSpacePositions[1].w);
	float2 FrustumTestsZ2 = saturate(ClipSpacePositions[2].zz * float2(-1, 1) - ClipSpacePositions[2].w);
	float2 FrustumTestsZ = FrustumTestsZ0 * FrustumTestsZ1 * FrustumTestsZ2;
	return !( any(FrustumTests != 0) || any(FrustumTestsZ != 0) );
}

/** Allocate space for cloning to all 6 faces which is the worst case. */
[maxvertexcount(18)]
void MainOnePassPointLightGS(triangle FShadowDepthVSToGS Input[3], inout TriangleStream<FShadowDepthGSToPS> OutStream)
{
	UNROLL
	// Clone the triangle to each face
	for (int CubeFaceIndex = 0; CubeFaceIndex < 6; CubeFaceIndex++)
	{
		float4 ClipSpacePositions[3];
		UNROLL
		for (int VertexIndex = 0; VertexIndex < 3; VertexIndex++)
		{
			// Calculate the clip space position for each cube face
			// Note: We don't apply any constant/slop bias here. A constant bias is applied in the shadow projection 
			// code (see CubemapHardwarePCF() in ShadowProjectionCommon.ush)
			// If one want to use this code path, don't forget to remove the bias in CubemapHardwarePCF().
			#if 0
			const float4 WorldPosition = Input[VertexIndex].GSPosition;
			const float3 WorldVertexNormal = Input[VertexIndex].WorldNormal;
			
			float4 ClipSpacePosition;
			float ShadowDepth;
			SetShadowDepthOutputs(
				PassStruct.ShadowViewProjectionMatrices[CubeFaceIndex],
				PassStruct.ShadowViewMatrices[CubeFaceIndex], 
				WorldPosition, 
				WorldVertexNormal, 
				ClipSpacePosition, 
				ShadowDepth);
			ClipSpacePositions[VertexIndex] = ClipSpacePosition;
			#else
			ClipSpacePositions[VertexIndex] = mul(Input[VertexIndex].GSPosition, PassStruct.ShadowViewProjectionMatrices[CubeFaceIndex]);
			#endif
		}
		// Frustum culling, saves GPU time with high poly meshes
		BRANCH
		if (IsTriangleInFrustum(ClipSpacePositions))
		{
			FShadowDepthGSToPS Output;
			Output.RTIndex = CubeFaceIndex;

			UNROLL
			for (int VertexIndex = 0; VertexIndex < 3; VertexIndex++)
			{
				Output.OutPosition = ClipSpacePositions[VertexIndex];

			#if INTERPOLATE_VF_ATTRIBUTES
				Output.PSInputs.FactoryInterpolants = Input[VertexIndex].FactoryInterpolants;
			#endif

			#if INTERPOLATE_POSITION
				Output.PSInputs.PixelPosition = Input[VertexIndex].GSPosition.xyz;
			#endif
				OutStream.Append(Output);
			}
			OutStream.RestartStrip();
		}
	}
}

#endif

#if USING_TESSELLATION

struct FShadowDepthVSToDS
{
	FVertexFactoryInterpolantsVSToDS FactoryInterpolants;
	float4 Position : VS_to_DS_Position;
	OPTIONAL_VertexID_VS_To_DS
#if ONEPASS_POINTLIGHT_SHADOW && USING_VERTEX_SHADER_LAYER
	uint LayerIndex : VS_to_DS_RenderTargetArrayIndex;
#endif
};

struct FShadowDepthDSToPS : FShadowDepthVSToPS
{
#if ONEPASS_POINTLIGHT_SHADOW
#if USING_VERTEX_SHADER_LAYER
	float4 Position : SV_POSITION;
	float4 InterpPosition : TEXCOORD6;
	uint LayerIndex : SV_RenderTargetArrayIndex;
#else
	float4 Position : TEXCOORD6;
#endif
	float3 WorldNormal : TEXCOORD8;
#else
	float4 Position : SV_POSITION;
#endif
};

#define FPassSpecificVSToDS FShadowDepthVSToDS
#define FPassSpecificVSToPS FShadowDepthDSToPS

FShadowDepthVSToDS PassInterpolate(FShadowDepthVSToDS a, float aInterp, FShadowDepthVSToDS b, float bInterp)
{
	FShadowDepthVSToDS O;
	O.FactoryInterpolants = VertexFactoryInterpolate(a.FactoryInterpolants, aInterp, b.FactoryInterpolants, bInterp);
#if ONEPASS_POINTLIGHT_SHADOW && USING_VERTEX_SHADER_LAYER
	O.LayerIndex = a.LayerIndex;
#endif
	return O;
}

FShadowDepthDSToPS PassFinalizeTessellationOutput(FShadowDepthVSToDS Interpolants, float4 WorldPosition, FMaterialTessellationParameters MaterialParameters)
{
	FShadowDepthDSToPS O;
	
#if INTERPOLATE_VF_ATTRIBUTES
	O.FactoryInterpolants = VertexFactoryAssignInterpolants(Interpolants.FactoryInterpolants);
#endif

	const float3 WorldNormal = MaterialParameters.TangentToWorld[2];

#if ONEPASS_POINTLIGHT_SHADOW
#if USING_VERTEX_SHADER_LAYER
	O.LayerIndex = Interpolants.LayerIndex;
	O.Position = WorldPosition = mul(WorldPosition, PassStruct.ShadowViewProjectionMatrices[Interpolants.LayerIndex]);
	O.InterpPosition = WorldPosition;
#else
	O.Position = WorldPosition;
#endif // USING_VERTEX_SHADER_LAYER
	O.WorldNormal = WorldNormal;
#else

	float ShadowDepth;
	SetShadowDepthOutputs(
		PassStruct.ProjectionMatrix,
		PassStruct.ViewMatrix,
		WorldPosition, 
		WorldNormal,
		O.Position, 
#if PERSPECTIVE_CORRECT_DEPTH
		O.ShadowDepth,
		O.DepthBias
#else
		ShadowDepth
#endif
		);
#endif

// Conditions below are derived. See struct FShadowDepthVSToPS in ShadowDepthCommon.ush
#if !PERSPECTIVE_CORRECT_DEPTH && !COMPILER_SUPPORTS_EMPTY_STRUCTS && !ONEPASS_POINTLIGHT_SHADOW
	O.Dummy = 0;
#endif

#if INTERPOLATE_POSITION
	O.PixelPosition = WorldPosition.xyz;
#endif

	return O;
}
	
#include "Tessellation.ush"

#endif // #if USING_TESSELLATION

void Main(
	FVertexFactoryInput Input,
#if USING_TESSELLATION
	out FShadowDepthVSToDS OutParameters,
#elif ONEPASS_POINTLIGHT_SHADOW
	out FShadowDepthVSToGS OutParameters,
#if FEATURE_LEVEL >= FEATURE_LEVEL_SM4 && USING_VERTEX_SHADER_LAYER
	out uint LayerIndex : SV_RenderTargetArrayIndex,
#endif
#else
	out FShadowDepthVSToPS OutParameters,
#endif
	OPTIONAL_VertexID
	out float4 OutPosition : SV_POSITION
	)
{
	ResolvedView = ResolveView();
	
	FVertexFactoryIntermediates VFIntermediates = GetVertexFactoryIntermediates(Input);
	float4 WorldPos = VertexFactoryGetWorldPosition(Input, VFIntermediates);
	float3x3 TangentToLocal = VertexFactoryGetTangentToLocal(Input, VFIntermediates);

	FMaterialVertexParameters VertexParameters = GetMaterialVertexParameters(Input, VFIntermediates, WorldPos.xyz, TangentToLocal);
	const float3 WorldNormal = VertexFactoryGetWorldNormal(Input, VFIntermediates);

	WorldPos.xyz += GetMaterialWorldPositionOffset(VertexParameters);

#if USING_TESSELLATION
	OutPosition = OutParameters.Position = WorldPos;
	
	// Tessellated materials need vertex coords for displacement
	OutParameters.FactoryInterpolants = VertexFactoryGetInterpolantsVSToDS(Input, VFIntermediates, VertexParameters);

	#if ONEPASS_POINTLIGHT_SHADOW && USING_VERTEX_SHADER_LAYER && VERTEXSHADER
		OutParameters.LayerIndex = LayerId;
	#endif

#elif ONEPASS_POINTLIGHT_SHADOW

	OutPosition = OutParameters.GSPosition = WorldPos;
	OutParameters.WorldNormal = WorldNormal;

	#if INTERPOLATE_VF_ATTRIBUTES
		// Masked materials need texture coords to clip
		OutParameters.FactoryInterpolants = VertexFactoryGetInterpolantsVSToPS(Input, VFIntermediates, VertexParameters);
	#endif

	#if INTERPOLATE_POSITION
		OutParameters.PixelPosition = WorldPos.xyz;
	#endif

	#if USING_VERTEX_SHADER_LAYER && VERTEXSHADER
		LayerIndex = LayerId;
		OutPosition = mul(WorldPos, PassStruct.ShadowViewProjectionMatrices[LayerIndex]);
		#if INTERPOLATE_VF_ATTRIBUTES
			OutParameters.GSPosition = OutPosition;
		#endif
	#endif

#else
	float Dummy;

	SetShadowDepthOutputs(
		PassStruct.ProjectionMatrix,
		PassStruct.ViewMatrix,
		WorldPos, 
		WorldNormal,
		OutPosition, 
#if !PERSPECTIVE_CORRECT_DEPTH
		Dummy
#else
		OutParameters.ShadowDepth,
		OutParameters.DepthBias
#endif
		);
	
	#if INTERPOLATE_VF_ATTRIBUTES
		// Masked materials need texture coords to clip
		OutParameters.FactoryInterpolants = VertexFactoryGetInterpolantsVSToPS(Input, VFIntermediates, VertexParameters);
	#endif

	#if INTERPOLATE_POSITION
		OutParameters.PixelPosition = WorldPos.xyz;
	#endif

	#if !PERSPECTIVE_CORRECT_DEPTH && !COMPILER_SUPPORTS_EMPTY_STRUCTS
		OutParameters.Dummy = 0;
	#endif
#endif

	OutputVertexID( OutParameters );
}

#if IS_FOR_GEOMETRY_SHADER

// Vertex shader exports must match GS inputs.
// This is a requirement on some platforms.
void MainForGS(
	OPTIONAL_VertexID
	FVertexFactoryInput Input,
#if USING_TESSELLATION
	out FShadowDepthVSToDS OutParameters
#elif ONEPASS_POINTLIGHT_SHADOW
	out FShadowDepthVSToGS OutParameters
	#if FEATURE_LEVEL >= FEATURE_LEVEL_SM4 && USING_VERTEX_SHADER_LAYER
		, out uint LayerIndex : SV_RenderTargetArrayIndex
	#endif
#else
	#error Invalid permutation for MainForGS
#endif
#if COMPILER_METAL
#define SKIP_UNUSED_POSITION
	// Metal needs a position output
	, out float4 UnusedPosition : SV_POSITION
#endif
	)
{
#ifndef SKIP_UNUSED_POSITION
	float4 UnusedPosition;
#endif

	Main(Input,
		OutParameters,
		OPTIONAL_VertexID_PARAM
#if !USING_TESSELLATION && (FEATURE_LEVEL >= FEATURE_LEVEL_SM4 && ONEPASS_POINTLIGHT_SHADOW && USING_VERTEX_SHADER_LAYER)
		LayerIndex,
#endif
		UnusedPosition);
}

#endif // IS_FOR_GEOMETRY_SHADER

#define USING_ONEPASS_POINT_VERTEX_LAYER	(FEATURE_LEVEL >= FEATURE_LEVEL_SM4 && ONEPASS_POINTLIGHT_SHADOW && USING_VERTEX_SHADER_LAYER)

#if POSITION_ONLY
void PositionOnlyMain(
	in FPositionAndNormalOnlyVertexFactoryInput Input,
#if USING_ONEPASS_POINT_VERTEX_LAYER
	out uint LayerIndex : SV_RenderTargetArrayIndex,
#endif
#if ONEPASS_POINTLIGHT_SHADOW
	out FShadowDepthVSToGS OutParameters,
#else
	out FShadowDepthVSToPS OutParameters,
#endif
	out float4 OutPosition : SV_POSITION
	)
{
	ResolvedView = ResolveView();

	float4 WorldPos = VertexFactoryGetWorldPosition(Input);

#if INTERPOLATE_VF_ATTRIBUTES
	OutParameters.FactoryInterpolants = (FVertexFactoryInterpolantsVSToPS)0;
#endif

	float3 WorldNormal = VertexFactoryGetWorldNormal(Input);

#if ONEPASS_POINTLIGHT_SHADOW
	OutPosition = OutParameters.GSPosition = WorldPos;
	OutParameters.WorldNormal = WorldNormal;
	#if USING_ONEPASS_POINT_VERTEX_LAYER
		LayerIndex = LayerId;
		OutPosition = mul(WorldPos, PassStruct.ShadowViewProjectionMatrices[LayerIndex]);
		#if INTERPOLATE_VF_ATTRIBUTES
			OutParameters.GSPosition = OutPosition;
		#endif
	#endif

#else // #if ONEPASS_POINTLIGHT_SHADOW
	float ShadowDepth;
	SetShadowDepthOutputs(
		PassStruct.ProjectionMatrix, 
		PassStruct.ViewMatrix, 
		WorldPos, 
		WorldNormal, 
		OutPosition,
	#if PERSPECTIVE_CORRECT_DEPTH
		OutParameters.ShadowDepth,
		OutParameters.DepthBias
	#else
		ShadowDepth
	#endif
	);

	#if !PERSPECTIVE_CORRECT_DEPTH && !COMPILER_SUPPORTS_EMPTY_STRUCTS
		OutParameters.Dummy = 0;
	#endif
#endif // #if ONEPASS_POINTLIGHT_SHADOW

#if INTERPOLATE_POSITION
	OutParameters.PixelPosition = WorldPos.xyz;
#endif
}


#if IS_FOR_GEOMETRY_SHADER

// Vertex shader exports must match GS inputs.
// This is a requirement on some platforms.
void PositionOnlyMainForGS(
	in FPositionAndNormalOnlyVertexFactoryInput Input,
#if USING_ONEPASS_POINT_VERTEX_LAYER
	out uint LayerIndex : SV_RenderTargetArrayIndex,
#endif
#if ONEPASS_POINTLIGHT_SHADOW
	out FShadowDepthVSToGS OutParameters
#else
	#error Invalid permutation for PositionOnlyMainForGS
#endif
#if COMPILER_METAL
	#ifndef SKIP_UNUSED_POSITION
		#define SKIP_UNUSED_POSITION
	#endif
	// Metal needs a position output
	, out float4 UnusedPosition : SV_POSITION
#endif
	)
{
#ifndef SKIP_UNUSED_POSITION
	float4 UnusedPosition;
#endif

	PositionOnlyMain(Input,
#if USING_ONEPASS_POINT_VERTEX_LAYER
		LayerIndex,
#endif
		OutParameters, UnusedPosition);
}

#endif // IS_FOR_GEOMETRY_SHADER

#endif

猜你喜欢

转载自blog.csdn.net/sh15285118586/article/details/124768778