LightmapGBuffer.usf 理解

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

/*=============================================================================
	LightmapGBuffer.usf
=============================================================================*/

#include "/Engine/Private/Common.ush"

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

#include "/Engine/Private/PathTracing/Utilities/PathTracingRandomSequence.ush"

float4 VirtualTexturePhysicalTileCoordinateScaleAndBias;
int2 ScratchTilePoolOffset; 
int RenderPassIndex;
int bMaterialTwoSided;

struct FLightmapGBufferVSToPS
{
	FVertexFactoryInterpolantsVSToPS FactoryInterpolants;
	float4 Position : SV_POSITION;
	float4 SavedWorldPosition : POSITION1;
	// Support WPO in the far future
	// float4 SavedWorldPositionWithShaderOffsets : POSITION2;
}; 

#if VERTEXSHADER
void LightmapGBufferVS(
	FVertexFactoryInput Input,
	out FLightmapGBufferVSToPS Output
	)
{
	ResolvedView = ResolveView();

	FVertexFactoryIntermediates VFIntermediates = GetVertexFactoryIntermediates(Input);
	float3 WorldPosition = VertexFactoryGetWorldPosition(Input, VFIntermediates).xyz;
	float3x3 TangentToLocal = VertexFactoryGetTangentToLocal(Input, VFIntermediates);

	FMaterialVertexParameters VertexParameters = GetMaterialVertexParameters(Input, VFIntermediates, WorldPosition, TangentToLocal);

	Output.FactoryInterpolants = VertexFactoryGetInterpolantsVSToPS(Input, VFIntermediates, VertexParameters);

	float2 LightmapUV, UnusedLightmapUV1;
	uint UnusedLightmapDataIndex;
    GetLightMapCoordinates(Output.FactoryInterpolants, LightmapUV, UnusedLightmapUV1, UnusedLightmapDataIndex);
	// Unscale with float2(1, 2)
    LightmapUV *= float2(1, 2);
	// Transform to tile [-1, 1] uv space
    float2 LightmapUVYInverted = (LightmapUV * VirtualTexturePhysicalTileCoordinateScaleAndBias.xy + VirtualTexturePhysicalTileCoordinateScaleAndBias.zw) * 2.0f - 1.0f;
    LightmapUVYInverted.y = -LightmapUVYInverted.y;

    uint SampleIndex = 0;
	float2 RandSample = float2(
		Halton(RenderPassIndex, 2), 
		Halton(RenderPassIndex, 3)
	);

	const float FilterWidth = 2.0f;
    float2 RandOffset = FilterWidth * (- 1.0f + 2 * RandSample) / GPreviewLightmapPhysicalTileSize;

    Output.Position = float4(LightmapUVYInverted + RandOffset, 0.0f, 1.0f);
	Output.SavedWorldPosition = VertexFactoryGetWorldPosition(Input, VFIntermediates);
	// Support WPO in the far future
	// Output.SavedWorldPositionWithShaderOffsets = Output.SavedWorldPosition + float4(GetMaterialWorldPositionOffset(VertexParameters), 0.0f);
}
#endif

#define WorldPositionScalar 0.00001f

void LightmapGBufferPS(
	FLightmapGBufferVSToPS Input
	OPTIONAL_IsFrontFace
	)
{ 
	ResolvedView = ResolveView();
	FMaterialPixelParameters MaterialParameters = GetMaterialPixelParameters(Input.FactoryInterpolants, Input.SavedWorldPosition);
	FPixelMaterialInputs PixelMaterialInputs;
	// Support WPO in the far future
	// CalcMaterialParametersEx(MaterialParameters, PixelMaterialInputs, float4(0, 0, 0, 0), float4(0, 0, 0, 0), bIsFrontFace, Input.SavedWorldPositionWithShaderOffsets, Input.SavedWorldPosition);
	CalcMaterialParametersEx(MaterialParameters, PixelMaterialInputs, float4(0, 0, 0, 0), float4(0, 0, 0, 0), bIsFrontFace, Input.SavedWorldPosition, Input.SavedWorldPosition);
	
	float4 OutWorldPosition = float4(LWCHackToFloat(MaterialParameters.AbsoluteWorldPosition) * WorldPositionScalar, 1.0f);
	// Faceted triangle normal
    float4 OutWorldNormal = float4(normalize(cross(ddx(OutWorldPosition.xyz), ddy(OutWorldPosition.xyz))), 1.0f);
    OutWorldNormal *= CondMask(bIsFrontFace, 1.0f, -1.0f);
	OutWorldNormal *= GetPrimitive_DeterminantSign(MaterialParameters.PrimitiveId);
	// Interpolated vertex normal
	float4 OutShadingNormal = float4(MaterialParameters.TangentToWorld[2], bMaterialTwoSided);

	// GBuffer Outputs
	LightmapGBufferParams.ScratchTilePoolLayer0[ScratchTilePoolOffset + Input.Position.xy] = OutWorldPosition;
	LightmapGBufferParams.ScratchTilePoolLayer1[ScratchTilePoolOffset + Input.Position.xy] = OutWorldNormal;
	LightmapGBufferParams.ScratchTilePoolLayer2[ScratchTilePoolOffset + Input.Position.xy] = OutShadingNormal;
}
FVertexFactoryIntermediates GetVertexFactoryIntermediates(FVertexFactoryInput Input)
{
	FVertexFactoryIntermediates Intermediates = (FVertexFactoryIntermediates)0;
	Intermediates.SceneData = VF_GPUSCENE_GET_INTERMEDIATES(Input);

	FPrimitiveSceneData PrimitiveData = GetPrimitiveData(Intermediates);

#if VF_USE_PRIMITIVE_SCENE_DATA
	// Calculate the local (within the range of instance IDs belonging to a given primitive), as this can be used to load custom stuff
	Intermediates.PrimitiveLocalInstanceIndex = Intermediates.SceneData.InstanceId - PrimitiveData.InstanceSceneDataOffset;

#if USE_INSTANCE_CULLING
	Intermediates.InstanceLightmapAndShadowMapUVBias = Intermediates.SceneData.InstanceData.LightMapAndShadowMapUVBias;

#if USE_EDITOR_SHADERS
	Intermediates.IsSelected = Intermediates.SceneData.InstanceData.EditorData.bIsSelected ? 1.0f : 0.0f;
	Intermediates.HitProxyId = float4(Intermediates.SceneData.InstanceData.EditorData.HitProxyId, 0.0f);
#else // !USE_EDITOR_SHADERS
	Intermediates.IsSelected = 0.0f;
	Intermediates.HitProxyId = float4(0.0f, 0.0f, 0.0f, 0.0f);
#endif // USE_EDITOR_SHADERS

	{
		// This repackaging is stupid-seeming but these params are propably packed off to some interpolator or something
		
		// PerInstanceParams.x: per-instance fade out amount
		float3 InstanceTranslatedLocation = TransformLocalToTranslatedWorld(GetInstanceData(Intermediates).LocalBoundsCenter, GetInstanceData(Intermediates).LocalToWorld).xyz;
		Intermediates.PerInstanceParams.x = 1.0 - saturate((length(InstanceTranslatedLocation) - InstancingFadeOutParams.x) * InstancingFadeOutParams.y);
		
		// InstancingFadeOutParams.z,w are RenderSelected and RenderDeselected respectively.

		// PerInstanceParams.y = hide / show flag, 
		Intermediates.IsVisible = lerp(InstancingFadeOutParams.w, InstancingFadeOutParams.z, Intermediates.IsSelected);
		Intermediates.PerInstanceParams.y = Intermediates.IsVisible;

		// PerInstanceParams.z dither fade cutoff
	#if USE_DITHERED_LOD_TRANSITION
		float RandomLOD = InstancingViewZCompareZero.w * Intermediates.SceneData.InstanceData.RandomID;
		float ViewZZero = length(InstanceTranslatedLocation - InstancingTranslatedWorldViewOriginZero.xyz) + RandomLOD;
		float ViewZOne = length(InstanceTranslatedLocation - InstancingTranslatedWorldViewOriginOne.xyz) + RandomLOD;
		Intermediates.PerInstanceParams.z =
			dot(float3(ViewZZero.xxx > InstancingViewZCompareZero.xyz), InstancingViewZConstant.xyz) * InstancingTranslatedWorldViewOriginZero.w +
			dot(float3(ViewZOne.xxx > InstancingViewZCompareOne.xyz), InstancingViewZConstant.xyz) * InstancingTranslatedWorldViewOriginOne.w;
		Intermediates.PerInstanceParams.y *= abs(Intermediates.PerInstanceParams.z) < .999;
		Intermediates.IsVisible = Intermediates.PerInstanceParams.y;
	#else
		Intermediates.PerInstanceParams.z = 0;
	#endif
	}
#endif // USE_INSTANCE_CULLING
#endif // VF_USE_PRIMITIVE_SCENE_DATA

#if MANUAL_VERTEX_FETCH
	Intermediates.Color = LocalVF.VertexFetch_ColorComponentsBuffer[(LocalVF.VertexFetch_Parameters[VF_VertexOffset] + Input.VertexId) & LocalVF.VertexFetch_Parameters[VF_ColorIndexMask_Index]] FMANUALFETCH_COLOR_COMPONENT_SWIZZLE; // Swizzle vertex color.
#else
	Intermediates.Color = Input.Color FCOLOR_COMPONENT_SWIZZLE; // Swizzle vertex color.
#endif

#if USE_INSTANCING && MANUAL_VERTEX_FETCH
	uint InstanceId = GetInstanceId(Input.InstanceId);
	Intermediates.InstanceTransform1 = InstanceVF.VertexFetch_InstanceTransformBuffer[3 * (InstanceId + InstanceOffset) + 0];
	Intermediates.InstanceTransform2 = InstanceVF.VertexFetch_InstanceTransformBuffer[3 * (InstanceId + InstanceOffset) + 1];
	Intermediates.InstanceTransform3 = InstanceVF.VertexFetch_InstanceTransformBuffer[3 * (InstanceId + InstanceOffset) + 2];
	Intermediates.InstanceOrigin = InstanceVF.VertexFetch_InstanceOriginBuffer[(InstanceId + InstanceOffset)];
	Intermediates.InstanceLightmapAndShadowMapUVBias = InstanceVF.VertexFetch_InstanceLightmapBuffer[(InstanceId + InstanceOffset)];
#elif USE_INSTANCING
	Intermediates.InstanceTransform1 = Input.InstanceTransform1;
	Intermediates.InstanceTransform2 = Input.InstanceTransform2;
	Intermediates.InstanceTransform3 = Input.InstanceTransform3;
	Intermediates.InstanceOrigin = Input.InstanceOrigin;
	Intermediates.InstanceLightmapAndShadowMapUVBias = Input.InstanceLightmapAndShadowMapUVBias;
#endif

	float TangentSign = 1.0;
	Intermediates.TangentToLocal = CalcTangentToLocal(Input, TangentSign);
	Intermediates.TangentToWorld = CalcTangentToWorld(Intermediates, Intermediates.TangentToLocal);
	Intermediates.TangentToWorldSign = TangentSign * GetInstanceData(Intermediates).DeterminantSign;

#if USE_INSTANCING
	// x = per-instance fade out factor, y = zero or one depending of if it is shown at all, z is dither cutoff 

	// PerInstanceParams.y stores a hide/show flag for this instance
	float SelectedValue = GetInstanceSelected(Intermediates);
	// GPUCULL_TODO: This can't be right
	float3 InstanceTranslatedLocation = TransformLocalToTranslatedWorld(GetInstanceOrigin(Intermediates), PrimitiveData.LocalToWorld).xyz;
	Intermediates.PerInstanceParams.x = 1.0 - saturate((length(InstanceTranslatedLocation) - InstancingFadeOutParams.x) * InstancingFadeOutParams.y);
	// InstancingFadeOutParams.z,w are RenderSelected and RenderDeselected respectively.
	Intermediates.PerInstanceParams.y = InstancingFadeOutParams.z * SelectedValue + InstancingFadeOutParams.w * (1-SelectedValue);
	#if USE_DITHERED_LOD_TRANSITION
		float RandomLOD = InstancingViewZCompareZero.w * Intermediates.SceneData.InstanceData.RandomID;
		float ViewZZero = length(InstanceTranslatedLocation - InstancingTranslatedWorldViewOriginZero.xyz) + RandomLOD;
		float ViewZOne = length(InstanceTranslatedLocation - InstancingTranslatedWorldViewOriginOne.xyz) + RandomLOD;
		Intermediates.PerInstanceParams.z = 
			dot(float3(ViewZZero.xxx > InstancingViewZCompareZero.xyz), InstancingViewZConstant.xyz) * InstancingTranslatedWorldViewOriginZero.w +
			dot(float3(ViewZOne.xxx > InstancingViewZCompareOne.xyz), InstancingViewZConstant.xyz) * InstancingTranslatedWorldViewOriginOne.w;
		Intermediates.PerInstanceParams.y *= abs(Intermediates.PerInstanceParams.z) < .999;
	#else
		Intermediates.PerInstanceParams.z = 0;
	#endif
	
	#if USES_PER_INSTANCE_CUSTOM_DATA
		// index into instance CustomData
		Intermediates.PerInstanceParams.w = asfloat(GetInstanceId(Input.InstanceId) + InstanceOffset);
	#endif
#endif	// USE_INSTANCING

	if (IsGPUSkinPassThrough())
	{
	#if SUPPORT_GPUSKIN_PASSTHROUGH
	#if MANUAL_VERTEX_FETCH
		uint PreSkinVertexOffset = LocalVF.PreSkinBaseVertexIndex + Input.VertexId * 3;
		Intermediates.PreSkinPosition.x = LocalVF.VertexFetch_PreSkinPositionBuffer[PreSkinVertexOffset + 0];
		Intermediates.PreSkinPosition.y = LocalVF.VertexFetch_PreSkinPositionBuffer[PreSkinVertexOffset + 1];
		Intermediates.PreSkinPosition.z = LocalVF.VertexFetch_PreSkinPositionBuffer[PreSkinVertexOffset + 2];
	#else
		Intermediates.PreSkinPosition = Input.PreSkinPosition.xyz;
	#endif
	#endif
	}
	else
	{
	Intermediates.PreSkinPosition = Input.Position.xyz;
	}

	return Intermediates;
}

	#define VF_GPUSCENE_GET_INTERMEDIATES(VFInput) \
		GetSceneDataIntermediates( \
			VFInput.InstanceIdOffset, \
			VFInput.DrawInstanceId)

FSceneDataIntermediates GetSceneDataIntermediates(uint InstanceIdOffset, uint DrawInstanceId)
{
	FSceneDataIntermediates Intermediates = (FSceneDataIntermediates)0;

	Intermediates.InstanceIdLoadIndex = InstanceIdOffset + DrawInstanceId;
	// GPUCULL_TODO: workaround for the fact that DrawDynamicMeshPassPrivate et al. don't work with GPU-Scene instancing
	//				 instead they mark the top bit in the primitive ID and disable auto instancing such that there is an 1:1:1
	//               drawcmd:primitive:instance. Then we can just look up the primitive and fetch the instance data index.
	// GPUCULL_TODO: Workaround also used for ray tracing interfacing with the VFs, that also supply a DrawInstanceId. 
	// We mark the PrimitiveID with the top bit in dynamic draw passes
	if ((InstanceIdOffset & VF_TREAT_INSTANCE_ID_OFFSET_AS_PRIMITIVE_ID_FLAG) != 0U)
	{
		// mask off the flag
		uint PrimitiveID = InstanceIdOffset & (VF_TREAT_INSTANCE_ID_OFFSET_AS_PRIMITIVE_ID_FLAG - 1U);
		Intermediates.InstanceId = GetPrimitiveData(PrimitiveID).InstanceSceneDataOffset + DrawInstanceId;
		Intermediates.ViewIndex = 0;
	}
// Workaround for Vulkan SPIRV issue when "else" branch is not removed when it should, which leads to higher level code expecting InstanceCulling buffer to be bound.
// See: https://github.com/KhronosGroup/SPIRV-Tools/issues/4902
#if USE_INSTANCE_CULLING_DATA
	else
	{
		Intermediates.InstanceId = InstanceCulling.InstanceIdsBuffer[InstanceIdOffset + DrawInstanceId] & ((1U << 28U) - 1);
		// We store the view index (which can be used for instanced stereo or other multi-view in the top four bits of the instance ID)
		// Note: this is an index of views for this render pass, not the view ID in the culling manager.
		Intermediates.ViewIndex = InstanceCulling.InstanceIdsBuffer[InstanceIdOffset + DrawInstanceId] >> 28U;
	}
#endif

	Intermediates.InstanceData = GetInstanceSceneData(Intermediates.InstanceId, View.InstanceSceneDataSOAStride);
	Intermediates.PrimitiveId = Intermediates.InstanceData.PrimitiveId;
	Intermediates.Primitive = GetPrimitiveData(Intermediates.PrimitiveId);

	return Intermediates;
}

// Fetch from scene primitive buffer
FInstanceSceneData GetInstanceSceneData(uint InstanceId, uint SOAStride, bool bCheckValid = true)
{
	FInstanceSceneData InstanceData = (FInstanceSceneData)0;

	//
	// NOTE: When changing the packed data layout, ensure that GPUScene/GPUSceneWriter.ush is kept in sync!
	//       Also, please update the GetInstanceSceneData function in GPUScene.cpp for validation purposes.
	//

	// Only process valid instances
	LoadInstancePrimitiveIdAndFlags(InstanceId, SOAStride, InstanceData.PrimitiveId, InstanceData.Flags);
	InstanceData.ValidInstance = InstanceData.PrimitiveId != INVALID_PRIMITIVE_ID;

	// Payload Data Layout
	// NOTE: Per-instance local bounds and hierarchy offset are always mutually inclusive, so pack together.
	// Random ID				<packed inline>
	// Custom Data Count		<packed inline>
	// HierarchyOffset			float0.x
	// LocalBounds Center		float0.yzw
	// LocalBounds Extent		float1.xyz
	// __UNUSED					float1.w
#if PLATFORM_ALLOW_SCENE_DATA_COMPRESSED_TRANSFORMS
	// Previous Transform[0]	float2.xyzw
	// Previous Transform[1]	float3.xyzw
	// LM/SM Scale Bias			float4.xyzw
	// Custom Data Float4s		float5.xyzw ... floatN.xyzw
#else
	// Previous Transform[0]	float2.xyzw
	// Previous Transform[1]	float3.xyzw
	// Previous Transform[2]	float4.xyzw
	// LM/SM Scale Bias			float5.xyzw
	// Custom Data Float4s		float6.xyzw ... floatN.xyzw
#endif

	BRANCH
	if (!bCheckValid || InstanceData.ValidInstance)
	{
		uint CustomDataCount;
		LoadInstanceRelativeIdAndCustomDataCount(InstanceId, SOAStride, InstanceData.RelativeId, CustomDataCount);

		FInstancePayloadDataOffsets Offsets 	= GetInstancePayloadDataOffsets(InstanceData.PrimitiveId, InstanceData.Flags, InstanceData.RelativeId);
	
	#if ENABLE_PER_INSTANCE_CUSTOM_DATA
		InstanceData.CustomDataCount			= CustomDataCount;
		InstanceData.CustomDataOffset			= Offsets.CustomData;
	#endif
		InstanceData.LastUpdateSceneFrameNumber	= asuint(LoadInstanceSceneDataElement(0 * SOAStride + InstanceId).z);
	#if USES_PER_INSTANCE_RANDOM || USE_DITHERED_LOD_TRANSITION
		InstanceData.RandomID					= LoadInstanceSceneDataElement(0 * SOAStride + InstanceId).w;
	#endif

		FPrimitiveSceneData PrimitiveData		= GetPrimitiveData(InstanceData.PrimitiveId);

		float3 TilePosition 									= PrimitiveData.TilePosition;

#if PLATFORM_ALLOW_SCENE_DATA_COMPRESSED_TRANSFORMS
		uint4  RotationScale									= asuint(LoadInstanceSceneDataElement(1 * SOAStride + InstanceId));
		float3 Translation										= LoadInstanceSceneDataElement(2 * SOAStride + InstanceId).xyz;
		float3 Scale = 0;
		float4x4 LocalToRelativeWorld							= DecodeTransform( RotationScale, Translation, Scale );

		uint4  PrevRotationScale								= asuint(LoadInstanceSceneDataElement(3 * SOAStride + InstanceId));
		float3 PrevTranslation									= LoadInstanceSceneDataElement(4 * SOAStride + InstanceId).xyz;
		float3 PrevScale = 0;
		float4x4 PrevLocalToRelativeWorld						= DecodeTransform( PrevRotationScale, PrevTranslation, PrevScale );

		InstanceData.NonUniformScale.xyz						= abs(Scale);
		InstanceData.InvNonUniformScale							= rcp(InstanceData.NonUniformScale.xyz);
#else
		float4x4 LocalToRelativeWorld							= transpose(float4x4(LoadInstanceSceneDataElement(1 * SOAStride + InstanceId),
																			LoadInstanceSceneDataElement(2 * SOAStride + InstanceId),
																	                LoadInstanceSceneDataElement(3 * SOAStride + InstanceId),
																	                float4(0.0f, 0.0f, 0.0f, 1.0f)));

		float4x4 PrevLocalToRelativeWorld						= transpose(float4x4(LoadInstanceSceneDataElement(4 * SOAStride + InstanceId),
																	                LoadInstanceSceneDataElement(5 * SOAStride + InstanceId),
																	                LoadInstanceSceneDataElement(6 * SOAStride + InstanceId),
																	                float4(0.0f, 0.0f, 0.0f, 1.0f)));

#endif


		InstanceData.LocalToWorld	= MakeLWCMatrix(TilePosition, LocalToRelativeWorld);
		InstanceData.PrevLocalToWorld	= MakeLWCMatrix(TilePosition, PrevLocalToRelativeWorld);
		ComputeInstanceDerivedData(InstanceData, TilePosition, LocalToRelativeWorld);

		InstanceData.NaniteRuntimeResourceID	= PrimitiveData.NaniteResourceID;
		InstanceData.NaniteHierarchyOffset		= PrimitiveData.NaniteHierarchyOffset;

		BRANCH
		if (Offsets.HierarchyOffset != INVALID_INSTANCE_PAYLOAD_OFFSET)
		{
			const uint HierarchyRootOffset = asuint(LoadInstancePayloadDataElement(Offsets.HierarchyOffset)).x;

			// Combine this instance's hierarchy offset with the primitive's root hierarchy offset
			InstanceData.NaniteHierarchyOffset += HierarchyRootOffset;
		}

	#if USE_EDITOR_SHADERS
		BRANCH
		if (Offsets.EditorData != INVALID_INSTANCE_PAYLOAD_OFFSET)
		{
			const uint PackedEditorData = asuint(LoadInstancePayloadDataElement(Offsets.EditorData)).y;

			InstanceData.EditorData.bIsSelected    = (PackedEditorData >> 24u) != 0;
			InstanceData.EditorData.HitProxyPacked =  PackedEditorData & 0x00FFFFFFu;
			InstanceData.EditorData.HitProxyId = UnpackHitProxyId(InstanceData.EditorData.HitProxyPacked);
		}
	#endif

		BRANCH
		if (Offsets.LocalBounds != INVALID_INSTANCE_PAYLOAD_OFFSET)
		{
			InstanceData.LocalBoundsCenter = float3(LoadInstancePayloadDataElement(Offsets.LocalBounds + 0).zw, LoadInstancePayloadDataElement(Offsets.LocalBounds + 1).x);
			InstanceData.LocalBoundsExtent = LoadInstancePayloadDataElement(Offsets.LocalBounds + 1).yzw;
		}
		else
		{
			InstanceData.LocalBoundsCenter = PrimitiveData.InstanceLocalBoundsCenter;
			InstanceData.LocalBoundsExtent = PrimitiveData.InstanceLocalBoundsExtent;
		}

		BRANCH
		if (Offsets.DynamicData != INVALID_INSTANCE_PAYLOAD_OFFSET)
		{
		#if PLATFORM_ALLOW_SCENE_DATA_COMPRESSED_TRANSFORMS
			uint4  PrevRotationScale			= asuint(LoadInstancePayloadDataElement(Offsets.DynamicData + 0));
			float3 PrevTranslation				= LoadInstancePayloadDataElement(Offsets.DynamicData + 1).xyz;
			float3 PrevScale					= 0;
			float4x4 PrevLocalToRelativeWorld	= DecodeTransform(PrevRotationScale, PrevTranslation, PrevScale);
		#else
			float4x4 PrevLocalToRelativeWorld	= transpose(float4x4(LoadInstancePayloadDataElement(Offsets.DynamicData + 0),
																 LoadInstancePayloadDataElement(Offsets.DynamicData + 1),
																 LoadInstancePayloadDataElement(Offsets.DynamicData + 2),
																 float4(0.0f, 0.0f, 0.0f, 1.0f)));
		#endif

			float3 TilePosition 				= PrimitiveData.TilePosition;
			InstanceData.PrevLocalToWorld		= MakeLWCMatrix(TilePosition, PrevLocalToRelativeWorld);
		}

	#if 1 //NEEDS_LIGHTMAP_COORDINATE
		BRANCH
		if (Offsets.LightShadowUVBias != INVALID_INSTANCE_PAYLOAD_OFFSET)
		{
			InstanceData.LightMapAndShadowMapUVBias = LoadInstancePayloadDataElement(Offsets.LightShadowUVBias);
		}
	#endif
	}

	return InstanceData;
}

FLWCMatrix MakeLWCMatrix(float3 Tile, float4x4 InMatrix)
{
	FLWCMatrix Result;
	LWCSetTile(Result, Tile);
	Result.M = InMatrix;
	return Result;
}

// @return translated world position
float4 VertexFactoryGetWorldPosition(FVertexFactoryInput Input, FVertexFactoryIntermediates Intermediates)
{
	FLWCMatrix LocalToWorld = GetInstanceData(Intermediates).LocalToWorld;

#if USE_INSTANCING
	return CalcWorldPosition(Input.Position, GetInstanceTransform(Intermediates), LocalToWorld) * Intermediates.PerInstanceParams.y;
#elif USE_INSTANCE_CULLING
	// Scale to zero if not visible, seems a bit wild but whatever
	return CalcWorldPosition(Input.Position, LocalToWorld) * Intermediates.IsVisible;
#else
	return CalcWorldPosition(Input.Position, LocalToWorld);
#endif	// USE_INSTANCING
}

#if USE_INSTANCING
float4 CalcWorldPosition(float4 Position, float4x4 InstanceTransform, FLWCMatrix LocalToWorld)
#else
float4 CalcWorldPosition(float4 Position, FLWCMatrix LocalToWorld)
#endif	// USE_INSTANCING
{
#if USE_INSTANCING
	return TransformLocalToTranslatedWorld(mul(Position, InstanceTransform).xyz, LocalToWorld);
#elif USE_SPLINEDEFORM
/*
	// Make transform for this point along spline
	float4x3 SliceTransform = CalcSliceTransform(dot(Position.xyz, SplineMeshDir));

	// Transform into mesh space
	float4 LocalPos = float4(mul(Position, SliceTransform), Position.w);
	// Transform from mesh to world space
	return TransformLocalToTranslatedWorld(LocalPos.xyz);
	*/
	return TransformLocalToTranslatedWorld(float3(mul(Position, CalcSliceTransform(dot(Position.xyz, SplineMeshDir))).xyz), LocalToWorld);
#else
	return TransformLocalToTranslatedWorld(Position.xyz, LocalToWorld);
#endif
}

FInstanceSceneData GetInstanceData(FVertexFactoryIntermediates Intermediates)
{
	return Intermediates.SceneData.InstanceData;
}
/** Converts from vertex factory specific input to a FMaterialVertexParameters, which is used by vertex shader material inputs. */
FMaterialVertexParameters GetMaterialVertexParameters(FVertexFactoryInput Input, FVertexFactoryIntermediates Intermediates, float3 WorldPosition, half3x3 TangentToLocal)
{
	FMaterialVertexParameters Result = (FMaterialVertexParameters)0;
	Result.SceneData = Intermediates.SceneData;
	// FIXME: just for compatibility with assets that use custom HLSL expressions, will be removed once we fix up all these assets
	Result.PrimitiveId = Intermediates.SceneData.PrimitiveId;

	Result.WorldPosition = WorldPosition;
	Result.VertexColor = Intermediates.Color;

	// does not handle instancing!
	Result.TangentToWorld = Intermediates.TangentToWorld;

	FPrimitiveSceneData PrimitiveData = GetPrimitiveData(Intermediates);

#if USE_INSTANCING
	float4x4 InstanceToLocal = GetInstanceTransform(Intermediates);
	Result.InstanceLocalToWorld = LWCMultiply(InstanceToLocal, PrimitiveData.LocalToWorld);
	Result.InstanceLocalPosition = Input.Position.xyz;
	Result.PerInstanceParams = Intermediates.PerInstanceParams;
	Result.InstanceId = GetInstanceId(Input.InstanceId); 
	Result.InstanceOffset = InstanceOffset;
	Result.PrevFrameLocalToWorld = LWCMultiply(GetInstancePrevTransform(Intermediates), PrimitiveData.PreviousLocalToWorld);

	// Calculate derived world to local
	{
		float3 Scale2;
		Scale2.x = length2(InstanceToLocal[0].xyz);
		Scale2.y = length2(InstanceToLocal[1].xyz);
		Scale2.z = length2(InstanceToLocal[2].xyz);

		float3 InvNonUniformScale = rsqrt(Scale2);

		float4x4 LocalToInstance = InstanceToLocal;
		LocalToInstance[0].xyz	*= Pow2(InvNonUniformScale.x);
		LocalToInstance[1].xyz	*= Pow2(InvNonUniformScale.y);
		LocalToInstance[2].xyz	*= Pow2(InvNonUniformScale.z);
		LocalToInstance[3].xyz	 = 0.0f;
		LocalToInstance			 = transpose(LocalToInstance);
		LocalToInstance[3].xyz	 = mul(float4(-InstanceToLocal[3].xyz, 0.0f), LocalToInstance).xyz;

		Result.InstanceWorldToLocal = LWCMultiply(PrimitiveData.WorldToLocal, LocalToInstance);
	}
#else
	Result.PrevFrameLocalToWorld = GetInstanceData(Intermediates).PrevLocalToWorld;
	#if USE_INSTANCE_CULLING
		Result.InstanceLocalPosition = Input.Position.xyz;
		Result.InstanceLocalToWorld = GetInstanceData(Intermediates).LocalToWorld;
		Result.InstanceWorldToLocal = GetInstanceData(Intermediates).WorldToLocal;
		Result.PerInstanceParams = Intermediates.PerInstanceParams;
	#endif
	#if USES_PER_INSTANCE_CUSTOM_DATA && VF_USE_PRIMITIVE_SCENE_DATA
		Result.CustomDataOffset = Intermediates.SceneData.InstanceData.CustomDataOffset;
		Result.CustomDataCount = Intermediates.SceneData.InstanceData.CustomDataCount;
	#endif
	#if USES_PER_INSTANCE_RANDOM && VF_USE_PRIMITIVE_SCENE_DATA
		Result.PerInstanceRandom = Intermediates.SceneData.InstanceData.RandomID;
	#endif
#endif

	Result.PreSkinnedPosition = Intermediates.PreSkinPosition.xyz;
	Result.PreSkinnedNormal = TangentToLocal[2]; //TangentBias(Input.TangentZ.xyz);

#if MANUAL_VERTEX_FETCH && NUM_MATERIAL_TEXCOORDS_VERTEX
		const uint NumFetchTexCoords = LocalVF.VertexFetch_Parameters[VF_NumTexcoords_Index];
		UNROLL
		for (uint CoordinateIndex = 0; CoordinateIndex < NUM_MATERIAL_TEXCOORDS_VERTEX; CoordinateIndex++)
		{
			// Clamp coordinates to mesh's maximum as materials can request more than are available
			uint ClampedCoordinateIndex = min(CoordinateIndex, NumFetchTexCoords-1);
			Result.TexCoords[CoordinateIndex] = LocalVF.VertexFetch_TexCoordBuffer[NumFetchTexCoords * (LocalVF.VertexFetch_Parameters[VF_VertexOffset] + Input.VertexId) + ClampedCoordinateIndex];
		}
#elif NUM_MATERIAL_TEXCOORDS_VERTEX
			#if NUM_MATERIAL_TEXCOORDS_VERTEX > 0
				Result.TexCoords[0] = Input.TexCoords0.xy;
			#endif
			#if NUM_MATERIAL_TEXCOORDS_VERTEX > 1
				Result.TexCoords[1] = Input.TexCoords0.zw;
			#endif
			#if NUM_MATERIAL_TEXCOORDS_VERTEX > 2
				Result.TexCoords[2] = Input.TexCoords1.xy;
			#endif
			#if NUM_MATERIAL_TEXCOORDS_VERTEX > 3
				Result.TexCoords[3] = Input.TexCoords1.zw;
			#endif
			#if NUM_MATERIAL_TEXCOORDS_VERTEX > 4
				Result.TexCoords[4] = Input.TexCoords2.xy;
			#endif
			#if NUM_MATERIAL_TEXCOORDS_VERTEX > 5
				Result.TexCoords[5] = Input.TexCoords2.zw;
			#endif
			#if NUM_MATERIAL_TEXCOORDS_VERTEX > 6
				Result.TexCoords[6] = Input.TexCoords3.xy;
			#endif
			#if NUM_MATERIAL_TEXCOORDS_VERTEX > 7
				Result.TexCoords[7] = Input.TexCoords3.zw;
			#endif
#endif  //MANUAL_VERTEX_FETCH && NUM_MATERIAL_TEXCOORDS_VERTEX

	Result.Particle.Color = half4(1,1,1,1);

#if NEEDS_PARTICLE_LOCAL_TO_WORLD
	Result.Particle.ParticleToWorld = PrimitiveData.LocalToWorld;
#endif

#if NEEDS_PARTICLE_WORLD_TO_LOCAL
	Result.Particle.WorldToParticle = PrimitiveData.WorldToLocal;
#endif

#if ENABLE_NEW_HLSL_GENERATOR
	EvaluateVertexMaterialAttributes(Result);
#endif
	return Result;
}
FVertexFactoryInterpolantsVSToPS VertexFactoryGetInterpolantsVSToPS(FVertexFactoryInput Input, FVertexFactoryIntermediates Intermediates, FMaterialVertexParameters VertexParameters)
{
	FVertexFactoryInterpolantsVSToPS Interpolants;

	// Initialize the whole struct to 0
	// Really only the last two components of the packed UVs have the opportunity to be uninitialized
	Interpolants = (FVertexFactoryInterpolantsVSToPS)0;

#if NUM_TEX_COORD_INTERPOLATORS
	float2 CustomizedUVs[NUM_TEX_COORD_INTERPOLATORS];
	GetMaterialCustomizedUVs(VertexParameters, CustomizedUVs);
	GetCustomInterpolators(VertexParameters, CustomizedUVs);
	
	UNROLL
	for (int CoordinateIndex = 0; CoordinateIndex < NUM_TEX_COORD_INTERPOLATORS; CoordinateIndex++)
	{
		SetUV(Interpolants, CoordinateIndex, CustomizedUVs[CoordinateIndex]);
	}

#elif NUM_MATERIAL_TEXCOORDS_VERTEX == 0 && USE_PARTICLE_SUBUVS
	#if MANUAL_VERTEX_FETCH
		SetUV(Interpolants, 0, LocalVF.VertexFetch_TexCoordBuffer[LocalVF.VertexFetch_Parameters[VF_NumTexcoords_Index] * (LocalVF.VertexFetch_Parameters[VF_VertexOffset] + Input.VertexId)]);
	#else
		SetUV(Interpolants, 0, Input.TexCoords0);
	#endif
#endif

#if NEEDS_LIGHTMAP_COORDINATE
	float2 LightMapCoordinate = 0;
	float2 ShadowMapCoordinate = 0;
	#if MANUAL_VERTEX_FETCH
		float2 LightMapCoordinateInput = LocalVF.VertexFetch_TexCoordBuffer[LocalVF.VertexFetch_Parameters[VF_NumTexcoords_Index] * (LocalVF.VertexFetch_Parameters[VF_VertexOffset] + Input.VertexId) + LocalVF.VertexFetch_Parameters[FV_LightMapIndex_Index]];
	#else
		float2 LightMapCoordinateInput = Input.LightMapCoordinate;
	#endif

	FPrimitiveSceneData PrimitiveData = GetPrimitiveData(Intermediates);

	uint LightmapDataIndex = PrimitiveData.LightmapDataIndex + LocalVF.LODLightmapDataIndex;
	uint LightmapUVIndex = PrimitiveData.LightmapUVIndex;
	float4 LightMapCoordinateScaleBias = VF_GPUSCENE_GET_LIGHTMAP_UV_SCALE_BIAS(Input, LightmapDataIndex);

	#if USE_INSTANCING || USE_INSTANCE_CULLING
		LightMapCoordinate = LightMapCoordinateInput * LightMapCoordinateScaleBias.xy + GetInstanceLightMapBias(Intermediates);
	#else
		LightMapCoordinate = LightMapCoordinateInput * LightMapCoordinateScaleBias.xy + LightMapCoordinateScaleBias.zw;
	#endif
	#if STATICLIGHTING_TEXTUREMASK
		float4 ShadowMapCoordinateScaleBias = VF_GPUSCENE_GET_SHADOWMAP_UV_SCALE_BIAS(Input, LightmapDataIndex);

		#if USE_INSTANCING || USE_INSTANCE_CULLING
			ShadowMapCoordinate = LightMapCoordinateInput * ShadowMapCoordinateScaleBias.xy + GetInstanceShadowMapBias(Intermediates);
		#else
			ShadowMapCoordinate = LightMapCoordinateInput * ShadowMapCoordinateScaleBias.xy + ShadowMapCoordinateScaleBias.zw;
		#endif
	#endif	// STATICLIGHTING_TEXTUREMASK

	SetLightMapCoordinate(Interpolants, LightMapCoordinate, ShadowMapCoordinate);
	SetLightmapDataIndex(Interpolants, LightmapDataIndex);
#endif	// NEEDS_LIGHTMAP_COORDINATE

	SetTangents(Interpolants, Intermediates.TangentToWorld[0], Intermediates.TangentToWorld[2], Intermediates.TangentToWorldSign);
	SetColor(Interpolants, Intermediates.Color);

#if USE_INSTANCING || USE_INSTANCE_CULLING
	Interpolants.PerInstanceParams = Intermediates.PerInstanceParams;
#endif

#if USES_PER_INSTANCE_CUSTOM_DATA && VF_USE_PRIMITIVE_SCENE_DATA
	Interpolants.CustomDataOffset = Intermediates.SceneData.InstanceData.CustomDataOffset;
	Interpolants.CustomDataCount  = Intermediates.SceneData.InstanceData.CustomDataCount;
#endif

#if USES_PER_INSTANCE_RANDOM && VF_USE_PRIMITIVE_SCENE_DATA
	Interpolants.PerInstanceRandom = Intermediates.SceneData.InstanceData.RandomID;
#endif

#if INSTANCED_STEREO
	Interpolants.EyeIndex = 0;
#endif

	SetPrimitiveId(Interpolants, Intermediates.SceneData.PrimitiveId);

#if HAS_INSTANCE_LOCAL_TO_WORLD_PS
	SetInstanceLocalToWorld(Interpolants, VertexParameters.InstanceLocalToWorld);
#endif
#if HAS_INSTANCE_WORLD_TO_LOCAL_PS
	SetInstanceWorldToLocal(Interpolants, VertexParameters.InstanceWorldToLocal);
#endif

	return Interpolants;
}

/** Converts from vertex factory specific interpolants to a FMaterialPixelParameters, which is used by material inputs. */
FMaterialPixelParameters GetMaterialPixelParameters(FVertexFactoryInterpolantsVSToPS Interpolants, float4 SvPosition)
{
	// GetMaterialPixelParameters is responsible for fully initializing the result
	FMaterialPixelParameters Result = MakeInitializedMaterialPixelParameters();

#if NUM_TEX_COORD_INTERPOLATORS
	UNROLL
	for( int CoordinateIndex = 0; CoordinateIndex < NUM_TEX_COORD_INTERPOLATORS; CoordinateIndex++ )
	{
		Result.TexCoords[CoordinateIndex] = GetUV(Interpolants, CoordinateIndex);
	}
#endif

#if USE_PARTICLE_SUBUVS
	// Output TexCoord0 for when previewing materials that use ParticleSubUV.
	Result.Particle.SubUVCoords[0] = GetUV(Interpolants, 0);
	Result.Particle.SubUVCoords[1] = GetUV(Interpolants, 0);
#endif	// USE_PARTICLE_SUBUVS

	half3 TangentToWorld0 = GetTangentToWorld0(Interpolants).xyz;
	half4 TangentToWorld2 = GetTangentToWorld2(Interpolants);
	Result.UnMirrored = TangentToWorld2.w;

	Result.VertexColor = GetColor(Interpolants);

	// Required for previewing materials that use ParticleColor
	Result.Particle.Color = half4(1,1,1,1);
#if USE_INSTANCING || USE_INSTANCE_CULLING 
	Result.PerInstanceParams = Interpolants.PerInstanceParams;
#endif

	Result.TangentToWorld = AssembleTangentToWorld( TangentToWorld0, TangentToWorld2 );
#if USE_WORLDVERTEXNORMAL_CENTER_INTERPOLATION
	Result.WorldVertexNormal_Center = Interpolants.TangentToWorld2_Center.xyz;
#endif

#if LIGHTMAP_UV_ACCESS
#if NEEDS_LIGHTMAP_COORDINATE
	#if (ES3_1_PROFILE)
		// Not supported in pixel shader
		Result.LightmapUVs = float2(0, 0);
	#else
		Result.LightmapUVs = Interpolants.LightMapCoordinate.xy;
	#endif	// ES3_1_PROFILE
#endif	// NEEDS_LIGHTMAP_COORDINATE
#endif	// LIGHTMAP_UV_ACCESS

	Result.TwoSidedSign = 1;
	Result.PrimitiveId = GetPrimitiveId(Interpolants);

#if USES_PER_INSTANCE_CUSTOM_DATA && VF_USE_PRIMITIVE_SCENE_DATA
	Result.CustomDataOffset = Interpolants.CustomDataOffset;
	Result.CustomDataCount  = Interpolants.CustomDataCount;
#endif

#if USES_PER_INSTANCE_RANDOM && VF_USE_PRIMITIVE_SCENE_DATA
	Result.PerInstanceRandom = Interpolants.PerInstanceRandom;
#endif

#if HAS_INSTANCE_LOCAL_TO_WORLD_PS
	Result.InstanceLocalToWorld = GetInstanceLocalToWorld(Interpolants);
#endif
#if HAS_INSTANCE_WORLD_TO_LOCAL_PS
	Result.InstanceWorldToLocal = GetInstanceWorldToLocal(Interpolants);
#endif

#if NEEDS_PARTICLE_LOCAL_TO_WORLD || NEEDS_PARTICLE_WORLD_TO_LOCAL
	FPrimitiveSceneData PrimitiveData = GetPrimitiveData(Result.PrimitiveId);
#endif

#if NEEDS_PARTICLE_LOCAL_TO_WORLD
	Result.Particle.ParticleToWorld = PrimitiveData.LocalToWorld;
#endif

#if NEEDS_PARTICLE_WORLD_TO_LOCAL
	Result.Particle.WorldToParticle = PrimitiveData.WorldToLocal;
#endif

	return Result;
}
/** Initializes the subset of Parameters that was not set in GetMaterialPixelParameters. */
void CalcMaterialParametersEx(
	in out FMaterialPixelParameters Parameters,
	in out FPixelMaterialInputs PixelMaterialInputs,
	float4 SvPosition,
	float4 ScreenPosition,
	FIsFrontFace bIsFrontFace,
	float3 TranslatedWorldPosition,
	float3 TranslatedWorldPositionExcludingShaderOffsets)
{
	// Remove the pre view translation
	Parameters.WorldPosition_CamRelative = TranslatedWorldPosition.xyz;
	Parameters.AbsoluteWorldPosition = LWCSubtract(TranslatedWorldPosition.xyz, ResolvedView.PreViewTranslation);

	// If the material uses any non-offset world position expressions, calculate those parameters. If not, 
	// the variables will have been initialised to 0 earlier.
#if USE_WORLD_POSITION_EXCLUDING_SHADER_OFFSETS
	Parameters.WorldPosition_NoOffsets_CamRelative = TranslatedWorldPositionExcludingShaderOffsets;
	Parameters.WorldPosition_NoOffsets = LWCSubtract(TranslatedWorldPositionExcludingShaderOffsets, ResolvedView.PreViewTranslation);
#endif

	Parameters.SvPosition = SvPosition;
	Parameters.ScreenPosition = ScreenPosition;
	Parameters.ViewBufferUV = ScreenPositionToBufferUV(ScreenPosition);

	// CameraVector is a normalised vector representing the "from surface to camera" direction.
	#if RAYHITGROUPSHADER
		Parameters.CameraVector = -WorldRayDirection();
	#else
		if (IsOrthoProjection(ResolvedView))
		{
			// CameraVector is just ViewForward in an ortho mode
			Parameters.CameraVector = -ResolvedView.ViewForward;
		}
		else
		{
			// TranslatedWorldPosition is the world position translated to the camera position, which is just -CameraVector in perspective projection
			Parameters.CameraVector = normalize(-Parameters.WorldPosition_CamRelative.xyz);
		}
	#endif

	Parameters.LightVector = 0;

#if IS_NANITE_PASS
	// Nanite does not support OPTIONAL_IsFrontFace, so Nanite sets the following to 1.0f or -1.0f in
	// GetMaterialPixelParameters - here we pull it out into our own front facing bool.
	const bool bNaniteIsFrontFace = Parameters.TwoSidedSign < 0.0f;
#endif

	Parameters.TwoSidedSign = 1.0f;

#if MATERIAL_TWOSIDED && HAS_PRIMITIVE_UNIFORM_BUFFER
	// #dxr: DirectX Raytracing's HitKind() intrinsic already accounts for negative scaling
	#if PIXELSHADER
		Parameters.TwoSidedSign *= ResolvedView.CullingSign * GetPrimitive_DeterminantSign(Parameters.PrimitiveId);
	#endif
#endif

#if (MATERIAL_TWOSIDED && !MATERIAL_TWOSIDED_SEPARATE_PASS) || RAYHITGROUPSHADER
	// Either we have a two-sided material that needs a sign flip, or we have a ray tracing material
	// that needs to consider rays arriving from either side
	#if IS_NANITE_PASS
		Parameters.TwoSidedSign *= GetFloatFacingSign(bNaniteIsFrontFace);
	#else
		Parameters.TwoSidedSign *= GetFloatFacingSign(bIsFrontFace);
	#endif
#endif

#if NUM_VIRTUALTEXTURE_SAMPLES || LIGHTMAP_VT_ENABLED
	InitializeVirtualTextureFeedback(Parameters.VirtualTextureFeedback, (uint2)SvPosition.xy, View.FrameNumber);
#endif

#if USE_ANALYTIC_DERIVATIVES
	if(!TEXTURE_SAMPLE_DEBUG || View.GeneralPurposeTweak >= 1.0f)
		CalcPixelMaterialInputsAnalyticDerivatives(Parameters, PixelMaterialInputs);
	else
#endif
	{
		CalcPixelMaterialInputs(Parameters, PixelMaterialInputs);
	}
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值