UE4 DeferredLightVertexShaders.usf

DeferredLightVertexShaders.usf

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

/*=============================================================================
	DeferredLightVertexShaders.usf: 
=============================================================================*/

#include "Common.ush"

#if defined(SHADER_RADIAL_LIGHT)
float4 StencilingGeometryPosAndScale;
float4 StencilingConeParameters;	// .x NumSides (0 if not cone), .y NumSlices, .z ConeAngle, .w ConeSphereRadius
float4x4 StencilingConeTransform;
float3 StencilingPreViewTranslation;
#endif

#if defined(SHADER_RADIAL_LIGHT) && SHADER_RADIAL_LIGHT == 0
/** Vertex shader for rendering a directional light using a full screen quad. */
void DirectionalVertexMain(
	in float2 InPosition : ATTRIBUTE0,
	in float2 InUV       : ATTRIBUTE1,
	out float2 OutTexCoord : TEXCOORD0,
	out float3 OutScreenVector : TEXCOORD1,
	out float4 OutPosition : SV_POSITION
	)
{	
	DrawRectangle(float4(InPosition.xy, 0, 1), InUV, OutPosition, OutTexCoord);
	OutScreenVector = mul(float4(OutPosition.xy, 1, 0), View.ScreenToTranslatedWorld).xyz;
}
#endif

#if SHADER_RADIAL_LIGHT == 1
/** Vertex shader for rendering a point or spot light using approximate bounding geometry. */
void RadialVertexMain(
	in uint InVertexId : SV_VertexID,
	in float3 InPosition : ATTRIBUTE0,
	out float4 OutScreenPosition : TEXCOORD0,
	out float4 OutPosition : SV_POSITION
	)
{
	float3 WorldPosition;
	uint NumSides = StencilingConeParameters.x;
	if (NumSides != 0)
	{
		float SphereRadius = StencilingConeParameters.w;
		float ConeAngle = StencilingConeParameters.z;

		// Cone vertex shader
		const float InvCosRadiansPerSide = 1.0f / cos(PI / (float)NumSides);
		// Use Cos(Theta) = Adjacent / Hypotenuse to solve for the distance of the end of the cone along the cone's Z axis
		const float ZRadius = SphereRadius * cos(ConeAngle);
		const float TanConeAngle = tan(ConeAngle);

		uint NumSlices = StencilingConeParameters.y;
		uint CapIndexStart = NumSides * NumSlices;
		// Generate vertices for the cone shape
		if (InVertexId < CapIndexStart)
		{
			uint SliceIndex = InVertexId / NumSides;
			uint SideIndex = InVertexId % NumSides;

			const float CurrentAngle = SideIndex * 2 * PI / (float)NumSides;
			const float DistanceDownConeDirection = ZRadius * SliceIndex / (float)(NumSlices - 1);
			// Use Tan(Theta) = Opposite / Adjacent to solve for the radius of this slice
			// Boost the effective radius so that the edges of the circle lie on the cone, instead of the vertices
			const float SliceRadius = DistanceDownConeDirection * TanConeAngle * InvCosRadiansPerSide;
			// Create a position in the local space of the cone, forming a circle in the XY plane, and offsetting along the Z axis
			const float3 LocalPosition = float3(ZRadius * SliceIndex / (float)(NumSlices - 1), SliceRadius * sin(CurrentAngle), SliceRadius * cos(CurrentAngle));
			// Transform to world space and apply pre-view translation, since these vertices will be used with a shader that has pre-view translation removed
			WorldPosition = mul(float4(LocalPosition, 1), StencilingConeTransform).xyz + StencilingPreViewTranslation;
		}
		else
		{
			// Generate vertices for the spherical cap
			const float CapRadius = ZRadius * tan(ConeAngle);

			uint VertexId = InVertexId - CapIndexStart;
			uint SliceIndex = VertexId / NumSides;
			uint SideIndex = VertexId % NumSides;

			const float UnadjustedSliceRadius = CapRadius * SliceIndex / (float)(NumSlices - 1);
			// Boost the effective radius so that the edges of the circle lie on the cone, instead of the vertices
			const float SliceRadius = UnadjustedSliceRadius * InvCosRadiansPerSide;
			// Solve for the Z axis distance that this slice should be at using the Pythagorean theorem
			const float ZDistance = sqrt(SphereRadius * SphereRadius - UnadjustedSliceRadius * UnadjustedSliceRadius);

			const float CurrentAngle = SideIndex * 2 * PI / (float)NumSides;
			const float3 LocalPosition = float3(ZDistance, SliceRadius * sin(CurrentAngle), SliceRadius * cos(CurrentAngle));
			WorldPosition = mul(float4(LocalPosition, 1), StencilingConeTransform).xyz + StencilingPreViewTranslation;
		}
	}
	else
	{
		// Sphere
		WorldPosition = InPosition * StencilingGeometryPosAndScale.w + StencilingGeometryPosAndScale.xyz;
	}

	OutScreenPosition = OutPosition = mul(float4(WorldPosition, 1), View.TranslatedWorldToClip);
}
#endif

#if defined(SHADER_HAIR) && SHADER_HAIR == 1

int2 MaxViewportResolution;
Texture2D<uint> HairVisibilityNodeCount;

void HairVertexMain(
	in uint InVertexId : SV_VertexID,
	out float4 OutPosition : SV_POSITION,
	nointerpolation out uint OutNodeCount : DISPATCH_NODECOUNT,
	nointerpolation out uint2 OutResolution : DISPATCH_RESOLUTION)
{
	OutNodeCount = HairVisibilityNodeCount.Load(uint3(0,0,0));
	OutResolution.x = ceil(sqrt(OutNodeCount));
	OutResolution.y = OutResolution.x;

	const float2 ClipCoord = ((OutResolution + 0.5f) / float2(MaxViewportResolution)) * 2;

	const float2 UV = float2(InVertexId & 1, InVertexId >> 1);
	const float2 Pos = float2(-UV.x, UV.y) * 4 + float2(-1, +1) + float2(ClipCoord.x, -ClipCoord.y);
	OutPosition = float4(Pos, 0.5f, 1);
}

#endif


/** A vertex shader for rendering the light in a deferred pass. */
template<bool bRadialLight>
class TDeferredLightVS : public FGlobalShader
{
	DECLARE_SHADER_TYPE(TDeferredLightVS,Global);
public:

	static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters)
	{
		if (bRadialLight)
		{
			return IsFeatureLevelSupported(Parameters.Platform, ERHIFeatureLevel::SM5) || IsMobileDeferredShadingEnabled(Parameters.Platform);
		}
		// used with FPrefilterPlanarReflectionPS on mobile
		return true;
	}

	static void ModifyCompilationEnvironment(const FGlobalShaderPermutationParameters& Parameters, FShaderCompilerEnvironment& OutEnvironment)
	{
		FGlobalShader::ModifyCompilationEnvironment(Parameters, OutEnvironment);
		OutEnvironment.SetDefine(TEXT("SHADER_RADIAL_LIGHT"), bRadialLight ? 1 : 0);
	}

	TDeferredLightVS()	{}
	TDeferredLightVS(const ShaderMetaType::CompiledShaderInitializerType& Initializer):
		FGlobalShader(Initializer)
	{
		StencilingGeometryParameters.Bind(Initializer.ParameterMap);
	}

	void SetParameters(FRHICommandList& RHICmdList, const FViewInfo& View, const FLightSceneInfo* LightSceneInfo)
	{
		FGlobalShader::SetParameters<FViewUniformShaderParameters>(RHICmdList, RHICmdList.GetBoundVertexShader(), View.ViewUniformBuffer);
		StencilingGeometryParameters.Set(RHICmdList, this, View, LightSceneInfo);
	}

	void SetSimpleLightParameters(FRHICommandList& RHICmdList, const FViewInfo& View, const FSphere& LightBounds)
	{
		FGlobalShader::SetParameters<FViewUniformShaderParameters>(RHICmdList, RHICmdList.GetBoundVertexShader(), View.ViewUniformBuffer);

		FVector4 StencilingSpherePosAndScale;
		StencilingGeometry::GStencilSphereVertexBuffer.CalcTransform(StencilingSpherePosAndScale, LightBounds, View.ViewMatrices.GetPreViewTranslation());
		StencilingGeometryParameters.Set(RHICmdList, this, StencilingSpherePosAndScale);
	}

private:

	LAYOUT_FIELD(FStencilingGeometryShaderParameters, StencilingGeometryParameters);
};

/** 
* Stencil geometry parameters used by multiple shaders. 
*/
class FStencilingGeometryShaderParameters
{
	DECLARE_TYPE_LAYOUT(FStencilingGeometryShaderParameters, NonVirtual);
public:
	void Bind(const FShaderParameterMap& ParameterMap)
	{
		StencilGeometryPosAndScale.Bind(ParameterMap, TEXT("StencilingGeometryPosAndScale"));
		StencilConeParameters.Bind(ParameterMap, TEXT("StencilingConeParameters"));
		StencilConeTransform.Bind(ParameterMap, TEXT("StencilingConeTransform"));
		StencilPreViewTranslation.Bind(ParameterMap, TEXT("StencilingPreViewTranslation"));
	}

	void Set(FRHICommandList& RHICmdList, FShader* Shader, const FVector4& InStencilingGeometryPosAndScale) const
	{
		SetShaderValue(RHICmdList, RHICmdList.GetBoundVertexShader(), StencilGeometryPosAndScale, InStencilingGeometryPosAndScale);
		SetShaderValue(RHICmdList, RHICmdList.GetBoundVertexShader(), StencilConeParameters, FVector4(0.0f, 0.0f, 0.0f, 0.0f));
	}

	void Set(FRHICommandList& RHICmdList, FShader* Shader, const FSceneView& View, const FLightSceneInfo* LightSceneInfo) const
	{
		FVector4 GeometryPosAndScale;
		if( LightSceneInfo->Proxy->GetLightType() == LightType_Point ||
			LightSceneInfo->Proxy->GetLightType() == LightType_Rect )
		{
			StencilingGeometry::GStencilSphereVertexBuffer.CalcTransform(GeometryPosAndScale, LightSceneInfo->Proxy->GetBoundingSphere(), View.ViewMatrices.GetPreViewTranslation());
			SetShaderValue(RHICmdList, RHICmdList.GetBoundVertexShader(), StencilGeometryPosAndScale, GeometryPosAndScale);
			SetShaderValue(RHICmdList, RHICmdList.GetBoundVertexShader(), StencilConeParameters, FVector4(0.0f, 0.0f, 0.0f, 0.0f));
		}
		else if(LightSceneInfo->Proxy->GetLightType() == LightType_Spot)
		{
			SetShaderValue(RHICmdList, RHICmdList.GetBoundVertexShader(), StencilConeTransform, LightSceneInfo->Proxy->GetLightToWorld());
			SetShaderValue(
				RHICmdList, 
				RHICmdList.GetBoundVertexShader(),
				StencilConeParameters,
				FVector4(
					StencilingGeometry::FStencilConeIndexBuffer::NumSides,
					StencilingGeometry::FStencilConeIndexBuffer::NumSlices,
					LightSceneInfo->Proxy->GetOuterConeAngle(),
					LightSceneInfo->Proxy->GetRadius()));
			SetShaderValue(RHICmdList, RHICmdList.GetBoundVertexShader(), StencilPreViewTranslation, View.ViewMatrices.GetPreViewTranslation());
		}
	}

	/** Serializer. */ 
	friend FArchive& operator<<(FArchive& Ar,FStencilingGeometryShaderParameters& P)
	{
		Ar << P.StencilGeometryPosAndScale;
		Ar << P.StencilConeParameters;
		Ar << P.StencilConeTransform;
		Ar << P.StencilPreViewTranslation;
		return Ar;
	}

private:
	
		LAYOUT_FIELD(FShaderParameter, StencilGeometryPosAndScale)
		LAYOUT_FIELD(FShaderParameter, StencilConeParameters)
		LAYOUT_FIELD(FShaderParameter, StencilConeTransform)
		LAYOUT_FIELD(FShaderParameter, StencilPreViewTranslation)
	
};
template<typename ShaderRHIParamRef, class ParameterType, typename TRHICmdList>
void SetShaderValue(
	TRHICmdList& RHICmdList,
	const ShaderRHIParamRef& Shader,
	const FShaderParameter& Parameter,
	const ParameterType& Value,
	uint32 ElementIndex = 0
	)
{
	static_assert(!TIsPointer<ParameterType>::Value, "Passing by value is not valid.");

	const uint32 AlignedTypeSize = Align(sizeof(ParameterType), SHADER_PARAMETER_ARRAY_ELEMENT_ALIGNMENT);
	const int32 NumBytesToSet = FMath::Min<int32>(sizeof(ParameterType),Parameter.GetNumBytes() - ElementIndex * AlignedTypeSize);

	// This will trigger if the parameter was not serialized
	checkSlow(Parameter.IsInitialized());

	if(NumBytesToSet > 0)
	{
		RHICmdList.SetShaderParameter(
			Shader,
			Parameter.GetBufferIndex(),
			Parameter.GetBaseIndex() + ElementIndex * AlignedTypeSize,
			(uint32)NumBytesToSet,
			&Value
			);
	}
}

おすすめ

転載: blog.csdn.net/sh15285118586/article/details/121804353