Files
UnrealEngine/Engine/Plugins/FX/Niagara/Shaders/Private/NiagaraMeshVertexFactory.ush
Brandyn / Techy fcc1b09210 init
2026-04-04 15:40:51 -05:00

994 lines
36 KiB
HLSL

// Copyright Epic Games, Inc. All Rights Reserved.
/*=============================================================================
MeshParticleVertexFactory.usf: Mesh particle vertex factory shader code.
=============================================================================*/
#include "/Engine/Private/VertexFactoryCommon.ush"
#include "NiagaraCommon.ush"
#include "NiagaraVFCommon.usf"
#include "NiagaraMeshParticleUtils.ush"
#if COMPUTESHADER || RAYHITGROUPSHADER
#include "/Engine/Private/RayTracing/RayTracingCommon.ush"
#include "/Engine/Private/RayTracing/RayTracingHitGroupCommon.ush"
#endif
#define USE_PARTICLE_POSITION (NEEDS_PARTICLE_POSITION)
#define USE_PARTICLE_VELOCITY (NEEDS_PARTICLE_VELOCITY)
#define USE_PARTICLE_TIME (NEEDS_PARTICLE_TIME)
#define USE_PARTICLE_RANDOM (NEEDS_PARTICLE_RANDOM)
#define USE_PARTICLE_TRANSFORM (NEEDS_PARTICLE_TRANSFORM)
#define USE_PARTICLE_LOCAL_TO_WORLD (NEEDS_PARTICLE_LOCAL_TO_WORLD || NEEDS_INSTANCE_LOCAL_TO_WORLD_PS)
#define USE_PARTICLE_WORLD_TO_LOCAL (NEEDS_PARTICLE_WORLD_TO_LOCAL || NEEDS_INSTANCE_WORLD_TO_LOCAL_PS)
#ifndef MANUAL_VERTEX_FETCH
#define MANUAL_VERTEX_FETCH 0
#endif
#if MANUAL_VERTEX_FETCH
#define VF_ColorIndexMask_Index 0
#define VF_NumTexcoords_Index 1
#endif // MANUAL_VERTEX_FETCH
struct FVertexFactoryInput
{
float4 Position : ATTRIBUTE0;
#if !MANUAL_VERTEX_FETCH
half3 TangentX : ATTRIBUTE1;
// TangentZ.w contains sign of tangent basis determinant
half4 TangentZ : ATTRIBUTE2;
half4 VertexColor : ATTRIBUTE3;
#if NUM_MATERIAL_TEXCOORDS_VERTEX
#if NUM_MATERIAL_TEXCOORDS_VERTEX == 1
float2 TexCoords0 : ATTRIBUTE4;
#elif NUM_MATERIAL_TEXCOORDS_VERTEX >= 2
float4 TexCoords01 : ATTRIBUTE4;
#endif
#if NUM_MATERIAL_TEXCOORDS_VERTEX == 3
float2 TexCoords2 : ATTRIBUTE5;
#elif NUM_MATERIAL_TEXCOORDS_VERTEX >= 4
float4 TexCoords23 : ATTRIBUTE5;
#endif
#if NUM_MATERIAL_TEXCOORDS_VERTEX == 5
float2 TexCoords4 : ATTRIBUTE6;
#elif NUM_MATERIAL_TEXCOORDS_VERTEX >= 6
float4 TexCoords45 : ATTRIBUTE6;
#endif
#if NUM_MATERIAL_TEXCOORDS_VERTEX == 7
float2 TexCoords6 : ATTRIBUTE7;
#elif NUM_MATERIAL_TEXCOORDS_VERTEX >= 8
float4 TexCoords67 : ATTRIBUTE7;
#endif
#elif USE_PARTICLE_SUBUVS
float2 TexCoords0 : ATTRIBUTE4;
#endif // NUM_MATERIAL_TEXCOORDS_VERTEX
#endif // !MANUAL_VERTEX_FETCH
#if (VF_USE_PRIMITIVE_SCENE_DATA == 1)
VF_GPUSCENE_DECLARE_INPUT_BLOCK(13)
VF_INSTANCED_STEREO_DECLARE_INPUT_BLOCK()
#else
#undef GetInstanceIdFromVF
#define GetInstanceIdFromVF(VFInput) (VFInput.InstanceId)
uint InstanceId : SV_InstanceID;
#endif
VF_MOBILE_MULTI_VIEW_DECLARE_INPUT_BLOCK()
#if PASS_NEEDS_VERTEX_ID || MANUAL_VERTEX_FETCH
uint VertexId : SV_VertexID;
#endif // #if PASS_NEEDS_VERTEX_ID
};
struct FVertexFactoryInterpolantsVSToPS
{
TANGENTTOWORLD_INTERPOLATOR_BLOCK
#if USE_PARTICLE_SUBUVS
float4 SubUV0AndTexCoord0 : TEXCOORD1;
float4 SubUV1AndLerp : TEXCOORD2;
#else
#if NUM_TEX_COORD_INTERPOLATORS
float4 TexCoords[(NUM_TEX_COORD_INTERPOLATORS+1)/2] : TEXCOORD0;
#endif
#endif
#if INTERPOLATE_VERTEX_COLOR
float4 VertexColor : COLOR0;
#endif
#if NEEDS_PARTICLE_COLOR
nointerpolation float4 ParticleColor : COLOR1;
#endif
#if (DYNAMIC_PARAMETERS_MASK & 1)
nointerpolation float4 DynamicParameter : COLOR2;
#endif
#if (DYNAMIC_PARAMETERS_MASK & 2)
nointerpolation float4 DynamicParameter1 : COLOR3;
#endif
#if (DYNAMIC_PARAMETERS_MASK & 4)
nointerpolation float4 DynamicParameter2 : COLOR4;
#endif
#if (DYNAMIC_PARAMETERS_MASK & 8)
nointerpolation float4 DynamicParameter3 : COLOR5;
#endif
#if USE_PARTICLE_POSITION
/** Particle position in camera-centered translated world space */
nointerpolation float3 ParticleTranslatedWorldPosition : PARTICLE_POSITION;
#endif
#if USE_PARTICLE_VELOCITY
/** The velocity of the particle, XYZ: direction, W: speed. */
nointerpolation float4 ParticleVelocity : PARTICLE_VELOCITY;
#endif
#if USE_PARTICLE_TIME
/** Relative alive time of the particle */
nointerpolation float RelativeTime : PARTICLE_TIME;
#endif
#if USE_PARTICLE_RANDOM
nointerpolation float ParticleRandom : PARTICLE_RANDOM;
#endif
#if USE_PARTICLE_LOCAL_TO_WORLD
nointerpolation float4 ParticleToWorld[3] : PARTICLE_LOCAL_TO_WORLD;
#endif
#if USE_PARTICLE_WORLD_TO_LOCAL
nointerpolation float4 WorldToParticle[3] : PARTICLE_WORLD_TO_LOCAL;
#endif
#if (VF_USE_PRIMITIVE_SCENE_DATA == 1)
nointerpolation uint PrimitiveId : PRIMITIVE_ID;
#endif
};
struct FVertexFactoryIntermediates
{
/** The index of the particle to use when accessing data buffers */
uint ParticleIndex;
/** The color of the vertex. */
float4 VertexColor;
/** The color of the particle. */
float4 ParticleColor;
/** The texture coordinates for the vertex. */
#if NUM_MATERIAL_TEXCOORDS_VERTEX
float2 TexCoords[NUM_MATERIAL_TEXCOORDS_VERTEX];
#endif
#if USE_PARTICLE_SUBUVS
float4 SubUVCoords;
nointerpolation float SubUVLerp;
#endif
/** Optional dynamic parameters for the particle. */
#if (DYNAMIC_PARAMETERS_MASK & 1)
float4 DynamicParameter;
#endif
#if (DYNAMIC_PARAMETERS_MASK & 2)
float4 DynamicParameter1;
#endif
#if (DYNAMIC_PARAMETERS_MASK & 4)
float4 DynamicParameter2;
#endif
#if (DYNAMIC_PARAMETERS_MASK & 8)
float4 DynamicParameter3;
#endif
/** The velocity of the particle, XYZ: direction, W: speed. */
float4 ParticleVelocity;
/** Particle position in camera-centered translated world space. */
float3 ParticleTranslatedWorldPosition;
#if NEEDS_PARTICLE_TIME
/** Relative time. */
float RelativeTime;
#endif
#if NEEDS_PARTICLE_RANDOM
/** Particle Random value */
float ParticleRandom;
#endif
FLWCMatrix ParticleToWorld;
FLWCInverseMatrix WorldToParticle;
FLWCMatrix PrevParticleToWorld;
float3x3 ParticleToWorldNoScale;
float3x3 TangentToLocal;
float TangentDeterminant;
/** Cached primitive and instance data */
FSceneDataIntermediates SceneData;
};
FPrimitiveSceneData GetPrimitiveData(FVertexFactoryIntermediates Intermediates)
{
return Intermediates.SceneData.Primitive;
}
FDFMatrix GetParticleTransform(FVertexFactoryIntermediates Inters)
{
return DFFromTileOffset(Inters.ParticleToWorld);
}
FDFInverseMatrix GetParticleInvTransform(FVertexFactoryIntermediates Inters)
{
return DFFromTileOffset(Inters.WorldToParticle);
}
FDFMatrix GetParticlePrevTransform(FVertexFactoryIntermediates Inters)
{
return DFFromTileOffset(Inters.PrevParticleToWorld);
}
float3x3 GetParticleRotationNoScale(FVertexFactoryIntermediates Inters)
{
return Inters.ParticleToWorldNoScale;
}
float2 GetUV(FVertexFactoryInterpolantsVSToPS Interpolants, int UVIndex)
{
#if USE_PARTICLE_SUBUVS
return 0;
#elif NUM_TEX_COORD_INTERPOLATORS
float4 UVVector = Interpolants.TexCoords[UVIndex / 2];
return UVIndex % 2 ? UVVector.zw : UVVector.xy;
#else
return 0;
#endif
}
/** 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 USE_PARTICLE_SUBUVS
#if NUM_TEX_COORD_INTERPOLATORS
UNROLL
for( int CoordinateIndex = 0; CoordinateIndex < NUM_TEX_COORD_INTERPOLATORS; CoordinateIndex++ )
{
Result.TexCoords[CoordinateIndex] = Interpolants.SubUV0AndTexCoord0.zw;
}
#endif
Result.Particle.SubUVCoords[0] = Interpolants.SubUV0AndTexCoord0.xy;
Result.Particle.SubUVCoords[1] = Interpolants.SubUV1AndLerp.xy;
Result.Particle.SubUVLerp = Interpolants.SubUV1AndLerp.z;
#elif NUM_TEX_COORD_INTERPOLATORS
UNROLL
for (int CoordinateIndex = 0; CoordinateIndex < NUM_TEX_COORD_INTERPOLATORS / 2; ++CoordinateIndex)
{
Result.TexCoords[CoordinateIndex * 2] = Interpolants.TexCoords[CoordinateIndex].xy;
Result.TexCoords[CoordinateIndex * 2 + 1] = Interpolants.TexCoords[CoordinateIndex].wz;
}
#if NUM_TEX_COORD_INTERPOLATORS & 1
Result.TexCoords[NUM_TEX_COORD_INTERPOLATORS - 1] = Interpolants.TexCoords[NUM_TEX_COORD_INTERPOLATORS / 2].xy;
#endif // #if NUM_TEX_COORD_INTERPOLATORS & 1
#endif
half3 TangentToWorld0 = Interpolants.TangentToWorld0.xyz;
half4 TangentToWorld2 = Interpolants.TangentToWorld2;
Result.UnMirrored = TangentToWorld2.w;
#if INTERPOLATE_VERTEX_COLOR
Result.VertexColor = Interpolants.VertexColor;
#else
Result.VertexColor = 0;
#endif
#if NEEDS_PARTICLE_COLOR
Result.Particle.Color = Interpolants.ParticleColor;
#endif
#if (DYNAMIC_PARAMETERS_MASK != 0)
Result.Particle.DynamicParameterValidMask = NiagaraMeshVF.MaterialParamValidMask;
#endif
#if (DYNAMIC_PARAMETERS_MASK & 1)
Result.Particle.DynamicParameter = Interpolants.DynamicParameter;
#endif
#if (DYNAMIC_PARAMETERS_MASK & 2)
Result.Particle.DynamicParameter1 = Interpolants.DynamicParameter1;
#endif
#if (DYNAMIC_PARAMETERS_MASK & 4)
Result.Particle.DynamicParameter2 = Interpolants.DynamicParameter2;
#endif
#if (DYNAMIC_PARAMETERS_MASK & 8)
Result.Particle.DynamicParameter3 = Interpolants.DynamicParameter3;
#endif
#if USE_PARTICLE_POSITION
Result.Particle.TranslatedWorldPositionAndSize.xyz = Interpolants.ParticleTranslatedWorldPosition;
Result.Particle.TranslatedWorldPositionAndSize.w = 1;
Result.Particle.PrevTranslatedWorldPositionAndSize = Result.Particle.TranslatedWorldPositionAndSize;
#endif
#if USE_PARTICLE_VELOCITY
Result.Particle.Velocity = Interpolants.ParticleVelocity;
#endif
#if USE_PARTICLE_TIME
Result.Particle.RelativeTime = Interpolants.RelativeTime;
#endif
#if USE_PARTICLE_RANDOM
Result.Particle.Random = Interpolants.ParticleRandom;
#else
Result.Particle.Random = 0.0f;
#endif
#if USE_PARTICLE_LOCAL_TO_WORLD
//-TODO: LWC Precision Loss
FLWCMatrix ParticleToWorld = LWCPromote(transpose(float4x4(Interpolants.ParticleToWorld[0], Interpolants.ParticleToWorld[1], Interpolants.ParticleToWorld[2], float4(0.0f, 0.0f, 0.0f, 1.0f))));
#if NEEDS_PARTICLE_LOCAL_TO_WORLD
Result.Particle.ParticleToWorld = DFFromTileOffset(ParticleToWorld);
#endif
#if NEEDS_INSTANCE_LOCAL_TO_WORLD_PS
Result.InstanceLocalToWorld = DFFromTileOffset(ParticleToWorld);
#endif
#endif
#if USE_PARTICLE_WORLD_TO_LOCAL
//-TODO: LWC Precision Loss
FLWCInverseMatrix WorldToParticle = LWCPromoteInverse(transpose(float4x4(Interpolants.WorldToParticle[0], Interpolants.WorldToParticle[1], Interpolants.WorldToParticle[2], float4(0.0f, 0.0f, 0.0f, 1.0f))));
#if NEEDS_PARTICLE_WORLD_TO_LOCAL
Result.Particle.WorldToParticle = DFFromTileOffset(WorldToParticle);
#endif
#if NEEDS_INSTANCE_WORLD_TO_LOCAL_PS
Result.InstanceWorldToLocal = DFFromTileOffset(WorldToParticle);
#endif
#endif
Result.Particle.MotionBlurFade = 1.0f;
Result.TangentToWorld = AssembleTangentToWorld( TangentToWorld0, TangentToWorld2 );
Result.TwoSidedSign = 1;
#if USE_WORLDVERTEXNORMAL_CENTER_INTERPOLATION
Result.WorldVertexNormal_Center = Interpolants.TangentToWorld2_Center.xyz;
#endif
#if VF_USE_PRIMITIVE_SCENE_DATA
Result.PrimitiveId = Interpolants.PrimitiveId;
#endif
return Result;
}
float3 VertexFactoryGetPreviousInstanceSpacePosition(FVertexFactoryInput Input, FVertexFactoryIntermediates Intermediates);
float3 VertexFactoryGetInstanceSpacePosition(FVertexFactoryInput Input, FVertexFactoryIntermediates Intermediates);
/** 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,
float3x3 TangentToLocal,
bool bIsPreviousFrame = false)
{
FMaterialVertexParameters Result = MakeInitializedMaterialVertexParameters();
Result.SceneData = Intermediates.SceneData;
#if VF_USE_PRIMITIVE_SCENE_DATA
Result.PrimitiveId = Intermediates.SceneData.PrimitiveId;
#endif
Result.WorldPosition = WorldPosition;
if (bIsPreviousFrame)
{
Result.PositionInstanceSpace = VertexFactoryGetPreviousInstanceSpacePosition(Input, Intermediates);
}
else
{
Result.PositionInstanceSpace = VertexFactoryGetInstanceSpacePosition(Input, Intermediates);
}
Result.PositionPrimitiveSpace = Result.PositionInstanceSpace; // No support for instancing, so instance == primitive
Result.VertexColor = Intermediates.VertexColor;
Result.PreSkinnedPosition = Input.Position.xyz;
Result.PreSkinnedNormal = Intermediates.TangentToLocal[2];
#if NEEDS_PARTICLE_POSITION
Result.Particle.TranslatedWorldPositionAndSize.xyz = Intermediates.ParticleTranslatedWorldPosition;
Result.Particle.TranslatedWorldPositionAndSize.w = 1;
Result.Particle.PrevTranslatedWorldPositionAndSize.xyz = LWCToFloat(LWCAdd(LWCGetOrigin(Intermediates.PrevParticleToWorld), ResolvedView.TileOffset.PrevPreViewTranslation));
Result.Particle.PrevTranslatedWorldPositionAndSize.w = 1;
#endif
#if NEEDS_PARTICLE_VELOCITY
Result.Particle.Velocity = Intermediates.ParticleVelocity;
#endif
#if NEEDS_PARTICLE_TIME
Result.Particle.RelativeTime = Intermediates.RelativeTime;
#endif
#if NEEDS_PARTICLE_RANDOM
Result.Particle.Random = Intermediates.ParticleRandom;
#else
Result.Particle.Random = 0.0f;
#endif
Result.Particle.Color = Intermediates.ParticleColor;
#if (DYNAMIC_PARAMETERS_MASK != 0)
Result.Particle.DynamicParameterValidMask = NiagaraMeshVF.MaterialParamValidMask;
#endif
#if (DYNAMIC_PARAMETERS_MASK & 1)
Result.Particle.DynamicParameter = Intermediates.DynamicParameter;
#endif
#if (DYNAMIC_PARAMETERS_MASK & 2)
Result.Particle.DynamicParameter1 = Intermediates.DynamicParameter1;
#endif
#if (DYNAMIC_PARAMETERS_MASK & 4)
Result.Particle.DynamicParameter2 = Intermediates.DynamicParameter2;
#endif
#if (DYNAMIC_PARAMETERS_MASK & 8)
Result.Particle.DynamicParameter3 = Intermediates.DynamicParameter3;
#endif
Result.InstanceLocalToWorld = GetParticleTransform(Intermediates);
Result.InstanceWorldToLocal = GetParticleInvTransform(Intermediates);
Result.Particle.ParticleToWorld = Result.InstanceLocalToWorld;
Result.Particle.WorldToParticle = Result.InstanceWorldToLocal;
// Use the particle's unscaled transform for rotating normals to match static mesh
Result.TangentToWorld = mul(TangentToLocal, GetParticleRotationNoScale(Intermediates));
Result.PrevFrameLocalToWorld = GetParticlePrevTransform(Intermediates);
#if NUM_MATERIAL_TEXCOORDS_VERTEX
for(int CoordinateIndex = 0; CoordinateIndex < NUM_MATERIAL_TEXCOORDS_VERTEX; CoordinateIndex++)
{
Result.TexCoords[CoordinateIndex] = Intermediates.TexCoords[CoordinateIndex];
}
#endif
#if ENABLE_NEW_HLSL_GENERATOR
EvaluateVertexMaterialAttributes(Result);
#endif
Result.LWCData = MakeMaterialLWCData(Result);
return Result;
}
float3x3 CalculateTangentToLocal(FVertexFactoryInput Input, out float TangentDeterminant)
{
float3x3 Result=0;
#if MANUAL_VERTEX_FETCH
float3 TangentX = NiagaraMeshVF.VertexFetch_PackedTangentsBuffer[2 * Input.VertexId + 0].xyz;
float4 TangentZ = NiagaraMeshVF.VertexFetch_PackedTangentsBuffer[2 * Input.VertexId + 1].xyzw;
#else
float3 TangentX = TangentBias(Input.TangentX);
float4 TangentZ = TangentBias(Input.TangentZ);
#endif // MANUAL_VERTEX_FETCH
// pass-thru the tangent
Result[0] = TangentX;
// pass-thru the normal
Result[2] = TangentZ.xyz;
// derive the binormal by getting the cross product of the normal and tangent
Result[1] = cross(Result[2], Result[0]) * TangentZ.w;
// Recalculate TangentX off of the other two vectors
// This corrects quantization error since TangentX was passed in as a quantized vertex input
// The error shows up most in specular off of a mesh with a smoothed UV seam (normal is smooth, but tangents vary across the seam)
Result[0] = cross(Result[1], Result[2]) * TangentZ.w;
TangentDeterminant = TangentZ.w;
return Result;
}
FVertexFactoryIntermediates GetVertexFactoryIntermediates(FVertexFactoryInput Input)
{
FVertexFactoryIntermediates Intermediates = (FVertexFactoryIntermediates)0;
#if (VF_USE_PRIMITIVE_SCENE_DATA == 1)
Intermediates.SceneData = VF_GPUSCENE_GET_INTERMEDIATES(Input);
// Pull the particle index from the custom data for the instance
Intermediates.ParticleIndex = asuint(LoadInstanceCustomDataFloat(Intermediates.SceneData.InstanceData, 0));
#else
Intermediates.SceneData = GetSceneDataIntermediates();
const uint InstanceId = GetInstanceId(GetInstanceIdFromVF(Input)); // NOTE: Handles instanced stereo
BRANCH
if (NiagaraMeshVF.SortedIndicesOffset == -1)
{
Intermediates.ParticleIndex = InstanceId;
}
else
{
Intermediates.ParticleIndex = NiagaraMeshVF.SortedIndices[NiagaraMeshVF.SortedIndicesOffset + InstanceId];
}
#endif // (VF_USE_PRIMITIVE_SCENE_DATA == 1)
Intermediates.ParticleColor = SafeGetVec4(NiagaraMeshVF.ColorDataOffset, Intermediates.ParticleIndex, NiagaraMeshVF.DefaultColor);
Intermediates.ParticleVelocity = NiagaraGetVelocityDirMag(NiagaraMeshVF.VelocityDataOffset, NiagaraMeshVF.DefaultVelocity, Intermediates.ParticleIndex);
#if (DYNAMIC_PARAMETERS_MASK & 1)
Intermediates.DynamicParameter = SafeGetVec4(NiagaraMeshVF.MaterialParamDataOffset, Intermediates.ParticleIndex, NiagaraMeshVF.DefaultDynamicMaterialParameter0);
#endif
#if (DYNAMIC_PARAMETERS_MASK & 2)
Intermediates.DynamicParameter1 = SafeGetVec4(NiagaraMeshVF.MaterialParam1DataOffset, Intermediates.ParticleIndex, NiagaraMeshVF.DefaultDynamicMaterialParameter1);
#endif
#if (DYNAMIC_PARAMETERS_MASK & 4)
Intermediates.DynamicParameter2 = SafeGetVec4(NiagaraMeshVF.MaterialParam2DataOffset, Intermediates.ParticleIndex, NiagaraMeshVF.DefaultDynamicMaterialParameter2);
#endif
#if (DYNAMIC_PARAMETERS_MASK & 8)
Intermediates.DynamicParameter3 = SafeGetVec4(NiagaraMeshVF.MaterialParam3DataOffset, Intermediates.ParticleIndex, NiagaraMeshVF.DefaultDynamicMaterialParameter3);
#endif
#if NEEDS_PARTICLE_TIME
Intermediates.RelativeTime = SafeGetFloat(NiagaraMeshVF.NormalizedAgeDataOffset, Intermediates.ParticleIndex, NiagaraMeshVF.DefaultNormAge);
#endif
#if NEEDS_PARTICLE_RANDOM
Intermediates.ParticleRandom = SafeGetFloat(NiagaraMeshVF.MaterialRandomDataOffset, Intermediates.ParticleIndex, NiagaraMeshVF.DefaultMatRandom);
#endif
// Compute transforms
#if (VF_USE_PRIMITIVE_SCENE_DATA == 1)
Intermediates.ParticleToWorld = DFToTileOffset(Intermediates.SceneData.InstanceData.LocalToWorld);
Intermediates.WorldToParticle = DFToTileOffset(Intermediates.SceneData.InstanceData.WorldToLocal);
Intermediates.PrevParticleToWorld = DFToTileOffset(Intermediates.SceneData.InstanceData.PrevLocalToWorld);
const float3 InstInvScale = Intermediates.SceneData.InstanceData.InvNonUniformScale;
Intermediates.ParticleToWorldNoScale = LWCToFloat3x3(Intermediates.ParticleToWorld);
Intermediates.ParticleToWorldNoScale[0] *= InstInvScale.x;
Intermediates.ParticleToWorldNoScale[1] *= InstInvScale.y;
Intermediates.ParticleToWorldNoScale[2] *= InstInvScale.z;
#else
NiagaraMeshParticleTransformsParams Params;
Params.ParticleIndex = Intermediates.ParticleIndex;
Params.SystemLWCTile = NiagaraMeshVF.SystemLWCTile;
Params.bLocalSpace = NiagaraMeshVF.bLocalSpace;
Params.bPreciseMotionVectors = NiagaraMeshVF.AccurateMotionVectors != 0;
Params.FacingMode = NiagaraMeshVF.FacingMode;
Params.DeltaSeconds = NiagaraMeshVF.DeltaSeconds;
Params.MeshScale = NiagaraMeshVF.MeshScale;
Params.MeshRotation = NiagaraMeshVF.MeshRotation;
Params.MeshOffset = NiagaraMeshVF.MeshOffset;
Params.bMeshOffsetIsWorldSpace = NiagaraMeshVF.bMeshOffsetIsWorldSpace;
Params.bLockedAxisEnable = NiagaraMeshVF.bLockedAxisEnable;
Params.LockedAxis = NiagaraMeshVF.LockedAxis;
Params.LockedAxisSpace = NiagaraMeshVF.LockedAxisSpace;
Params.ScaleDataOffset = NiagaraMeshVF.ScaleDataOffset;
Params.RotationDataOffset = NiagaraMeshVF.RotationDataOffset;
Params.PositionDataOffset = NiagaraMeshVF.PositionDataOffset;
Params.CameraOffsetDataOffset = NiagaraMeshVF.CameraOffsetDataOffset;
Params.PrevScaleDataOffset = NiagaraMeshVF.PrevScaleDataOffset;
Params.PrevRotationDataOffset = NiagaraMeshVF.PrevRotationDataOffset;
Params.PrevPositionDataOffset = NiagaraMeshVF.PrevPositionDataOffset;
Params.PrevCameraOffsetDataOffset = NiagaraMeshVF.PrevCameraOffsetDataOffset;
Params.DefaultScale = NiagaraMeshVF.DefaultScale;
Params.DefaultRotation = NiagaraMeshVF.DefaultRotation;
Params.DefaultPosition = NiagaraMeshVF.DefaultPosition;
Params.DefaultCameraOffset = NiagaraMeshVF.DefaultCameraOffset;
Params.DefaultPrevScale = NiagaraMeshVF.DefaultPrevScale;
Params.DefaultPrevRotation = NiagaraMeshVF.DefaultPrevRotation;
Params.DefaultPrevPosition = NiagaraMeshVF.DefaultPrevPosition;
Params.DefaultPrevCameraOffset = NiagaraMeshVF.DefaultPrevCameraOffset;
Params.VelocityDirMag = Intermediates.ParticleVelocity;
Params.PrevVelocityDirMag = NiagaraGetVelocityDirMag(NiagaraMeshVF.PrevVelocityDataOffset, NiagaraMeshVF.DefaultPrevVelocity, Intermediates.ParticleIndex);
Params.CameraOrigin = ResolvedView.TileOffset.WorldCameraOrigin;
Params.CameraForwardDir = ResolvedView.ViewForward;
Params.CameraUpDir = ResolvedView.ViewUp;
Params.PrevCameraOrigin = ResolvedView.TileOffset.PrevWorldCameraOrigin;
Params.PrevCameraForwardDir = ResolvedView.PrevViewToTranslatedWorld[2].xyz;
Params.PrevCameraUpDir = ResolvedView.PrevViewToTranslatedWorld[1].xyz;
Params.PrimitiveLocalToWorld = DFToTileOffset(Intermediates.SceneData.Primitive.LocalToWorld);
Params.PrimitiveWorldToLocal = DFToTileOffset(Intermediates.SceneData.Primitive.WorldToLocal);
Params.PrimitivePrevLocalToWorld = DFToTileOffset(Intermediates.SceneData.Primitive.PreviousLocalToWorld);
Params.PrimitiveInvNonUniformScale = Intermediates.SceneData.Primitive.InvNonUniformScale;
NiagaraMeshParticleTransforms Transforms = NiagaraCalculateMeshParticleTransforms(Params);
Intermediates.ParticleToWorld = Transforms.LocalToWorld;
Intermediates.WorldToParticle = Transforms.WorldToLocal;
Intermediates.PrevParticleToWorld = Transforms.PrevLocalToWorld;
Intermediates.ParticleToWorldNoScale = Transforms.LocalToWorldNoScale;
#endif // (VF_USE_PRIMITIVE_SCENE_DATA == 1)
// Particle translated world position.
Intermediates.ParticleTranslatedWorldPosition = LWCToFloat(LWCAdd(LWCGetOrigin(Intermediates.ParticleToWorld), ResolvedView.TileOffset.PreViewTranslation));
#if NUM_MATERIAL_TEXCOORDS_VERTEX
#if MANUAL_VERTEX_FETCH
const uint NumFetchTexCoords = NiagaraMeshVF.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);
Intermediates.TexCoords[CoordinateIndex] = NiagaraMeshVF.VertexFetch_TexCoordBuffer[NumFetchTexCoords * Input.VertexId + ClampedCoordinateIndex];
}
#else
#if NUM_MATERIAL_TEXCOORDS_VERTEX == 1
Intermediates.TexCoords[0] = Input.TexCoords0;
#elif NUM_MATERIAL_TEXCOORDS_VERTEX >= 2
Intermediates.TexCoords[0] = Input.TexCoords01.xy;
Intermediates.TexCoords[1] = Input.TexCoords01.zw;
#endif
#if NUM_MATERIAL_TEXCOORDS_VERTEX == 3
Intermediates.TexCoords[2] = Input.TexCoords2;
#elif NUM_MATERIAL_TEXCOORDS_VERTEX >= 4
Intermediates.TexCoords[2] = Input.TexCoords23.xy;
Intermediates.TexCoords[3] = Input.TexCoords23.zw;
#endif
#if NUM_MATERIAL_TEXCOORDS_VERTEX == 5
Intermediates.TexCoords[4] = Input.TexCoords4;
#elif NUM_MATERIAL_TEXCOORDS_VERTEX >= 6
Intermediates.TexCoords[4] = Input.TexCoords45.xy;
Intermediates.TexCoords[5] = Input.TexCoords45.zw;
#endif
#if NUM_MATERIAL_TEXCOORDS_VERTEX == 7
Intermediates.TexCoords[6] = Input.TexCoords6;
#elif NUM_MATERIAL_TEXCOORDS_VERTEX >= 8
Intermediates.TexCoords[6] = Input.TexCoords67.xy;
Intermediates.TexCoords[7] = Input.TexCoords67.zw;
#endif
#endif // MANUAL_VERTEX_FETCH
#endif // NUM_MATERIAL_TEXCOORDS_VERTEX
#if USE_PARTICLE_SUBUVS
// SubUV.
float SubImageIndex = SafeGetFloat(NiagaraMeshVF.SubImageDataOffset, Intermediates.ParticleIndex, NiagaraMeshVF.DefaultSubImage);
float SubImageLerp = frac(SubImageIndex);
float SubImageA = SubImageIndex - SubImageLerp;
float SubImageB = SubImageA + 1;
float SubImageAH = fmod(SubImageA, NiagaraMeshVF.SubImageSize.x);
float SubImageBH = fmod(SubImageB, NiagaraMeshVF.SubImageSize.x);
float SubImageAV = floor(SubImageA * NiagaraMeshVF.SubImageSize.z);
float SubImageBV = floor(SubImageB * NiagaraMeshVF.SubImageSize.z);
Intermediates.SubUVLerp = (NiagaraMeshVF.SubImageBlendMode == 1) ? SubImageLerp : 0.0f;
#if MANUAL_VERTEX_FETCH
const uint NumFetchSubUvTexCoords = NiagaraMeshVF.VertexFetch_Parameters[VF_NumTexcoords_Index];
const float2 SubUvTexCoord = NiagaraMeshVF.VertexFetch_TexCoordBuffer[NumFetchSubUvTexCoords * Input.VertexId];
#else
#if NUM_MATERIAL_TEXCOORDS_VERTEX == 1
const float2 SubUvTexCoord = Input.TexCoords0;
#elif NUM_MATERIAL_TEXCOORDS_VERTEX >= 2
const float2 SubUvTexCoord = Input.TexCoords01.xy;
#else
const float2 SubUvTexCoord = float2(0.0f, 0.0f);
#endif
#endif // MANUAL_VERTEX_FETCH
Intermediates.SubUVCoords.xy = (float2(SubImageAH, SubImageAV) + SubUvTexCoord) * NiagaraMeshVF.SubImageSize.zw;
Intermediates.SubUVCoords.zw = (float2(SubImageBH, SubImageBV) + SubUvTexCoord) * NiagaraMeshVF.SubImageSize.zw;
#endif // USE_PARTICLE_SUBUVS
#if MANUAL_VERTEX_FETCH
Intermediates.VertexColor = NiagaraMeshVF.VertexFetch_ColorComponentsBuffer[Input.VertexId & NiagaraMeshVF.VertexFetch_Parameters[VF_ColorIndexMask_Index]] FMANUALFETCH_COLOR_COMPONENT_SWIZZLE; // Swizzle vertex color.
#else
// Swizzle vertex color.
Intermediates.VertexColor = Input.VertexColor FCOLOR_COMPONENT_SWIZZLE;
#endif // MANUAL_VERTEX_FETCH
Intermediates.TangentToLocal = CalculateTangentToLocal(Input, Intermediates.TangentDeterminant);
return Intermediates;
}
/**
* Get the 3x3 tangent basis vectors for this vertex factory
* this vertex factory will calculate the binormal on-the-fly
*
* @param Input - vertex input stream structure
* @return 3x3 matrix
*/
float3x3 VertexFactoryGetTangentToLocal( FVertexFactoryInput Input, FVertexFactoryIntermediates Intermediates )
{
return Intermediates.TangentToLocal;
}
// @return translated world position
float4 VertexFactoryGetWorldPosition(FVertexFactoryInput Input, FVertexFactoryIntermediates Intermediates)
{
FLWCMatrix Transform = Intermediates.ParticleToWorld;
float3 WorldPosition = LWCToFloat(LWCAdd(LWCMultiply(Input.Position.xyz, Transform), ResolvedView.TileOffset.PreViewTranslation));
return float4(WorldPosition, Input.Position.w);
}
float3 VertexFactoryGetInstanceSpacePosition(FVertexFactoryInput Input, FVertexFactoryIntermediates Intermediates)
{
return Input.Position.xyz; // No support for instancing, so instance == primitive
}
float4 VertexFactoryGetRasterizedWorldPosition(FVertexFactoryInput Input, FVertexFactoryIntermediates Intermediates, float4 InWorldPosition)
{
return InWorldPosition;
}
float3 VertexFactoryGetWorldNormal(FVertexFactoryInput Input, FVertexFactoryIntermediates Intermediates)
{
return LWCToFloat3x3(Intermediates.ParticleToWorld)[2].xyz;
}
float3 VertexFactoryGetPositionForVertexLighting(FVertexFactoryInput Input, FVertexFactoryIntermediates Intermediates, float3 TranslatedWorldPosition)
{
return TranslatedWorldPosition;
}
void CalcTangentToWorld(FVertexFactoryInput Input, FVertexFactoryIntermediates Intermediates, out float3 TangentToWorld0, out float4 TangentToWorld2)
{
const float3x3 TangentToLocal = VertexFactoryGetTangentToLocal(Input, Intermediates);
// Use the particle's unscaled transform for rotating normals to match static mesh
const float3x3 TransformNoScale = GetParticleRotationNoScale(Intermediates);
const float3x3 TangentToWorld = mul(TangentToLocal, TransformNoScale);
const float DetSign = Intermediates.SceneData.InstanceData.DeterminantSign;
// Note: We do not normalize to match localvertexfactory.ush and the above transform does not contain scale
// If for some reason we need to add the normalize back in you will need to consider UE-195371 as some mesh data is 0,0,0
TangentToWorld0 = TangentToWorld[0];
TangentToWorld2 = float4(TangentToWorld[2], TangentBias(Intermediates.TangentDeterminant) * DetSign);
}
FVertexFactoryInterpolantsVSToPS VertexFactoryGetInterpolantsVSToPS(FVertexFactoryInput Input, FVertexFactoryIntermediates Intermediates, FMaterialVertexParameters VertexParameters)
{
FVertexFactoryInterpolantsVSToPS Interpolants;
#if USE_PARTICLE_SUBUVS
Interpolants.SubUV0AndTexCoord0.xy = Intermediates.SubUVCoords.xy;
Interpolants.SubUV1AndLerp.xy = Intermediates.SubUVCoords.zw;
Interpolants.SubUV1AndLerp.zw = Intermediates.SubUVLerp.xx;
#if NUM_TEX_COORD_INTERPOLATORS
float2 CustomizedUVs[ NUM_TEX_COORD_INTERPOLATORS];
GetMaterialCustomizedUVs(VertexParameters, CustomizedUVs);
Interpolants.SubUV0AndTexCoord0.zw = CustomizedUVs[0];
#else
Interpolants.SubUV0AndTexCoord0.zw = 0;
#endif
#elif NUM_TEX_COORD_INTERPOLATORS
// Ensure the unused components of the last packed texture coordinate are initialized.
Interpolants.TexCoords[( NUM_TEX_COORD_INTERPOLATORS + 1) / 2 - 1] = 0;
float2 CustomizedUVs[ NUM_TEX_COORD_INTERPOLATORS];
GetMaterialCustomizedUVs(VertexParameters, CustomizedUVs);
GetCustomInterpolators(VertexParameters, CustomizedUVs);
UNROLL
for (int CoordinateIndex = 0; CoordinateIndex < NUM_TEX_COORD_INTERPOLATORS / 2; ++CoordinateIndex)
{
Interpolants.TexCoords[CoordinateIndex].xy = CustomizedUVs[CoordinateIndex * 2];
Interpolants.TexCoords[CoordinateIndex].wz = CustomizedUVs[CoordinateIndex * 2 + 1];
}
#if NUM_TEX_COORD_INTERPOLATORS & 1
Interpolants.TexCoords[NUM_TEX_COORD_INTERPOLATORS / 2].xy = CustomizedUVs[NUM_TEX_COORD_INTERPOLATORS - 1];
#endif // #if NUM_TEX_COORD_INTERPOLATORS & 1
#endif
Interpolants.TangentToWorld0.w = 0;
CalcTangentToWorld(Input, Intermediates, Interpolants.TangentToWorld0.xyz, Interpolants.TangentToWorld2);
#if USE_WORLDVERTEXNORMAL_CENTER_INTERPOLATION
Interpolants.TangentToWorld2_Center = Interpolants.TangentToWorld2;
#endif
#if INTERPOLATE_VERTEX_COLOR
Interpolants.VertexColor = Intermediates.VertexColor;
#endif
#if NEEDS_PARTICLE_COLOR
Interpolants.ParticleColor = Intermediates.ParticleColor;
#endif
#if (DYNAMIC_PARAMETERS_MASK & 1)
Interpolants.DynamicParameter = Intermediates.DynamicParameter;
#endif
#if (DYNAMIC_PARAMETERS_MASK & 2)
Interpolants.DynamicParameter1 = Intermediates.DynamicParameter1;
#endif
#if (DYNAMIC_PARAMETERS_MASK & 4)
Interpolants.DynamicParameter2 = Intermediates.DynamicParameter2;
#endif
#if (DYNAMIC_PARAMETERS_MASK & 8)
Interpolants.DynamicParameter3 = Intermediates.DynamicParameter3;
#endif
#if USE_PARTICLE_POSITION
Interpolants.ParticleTranslatedWorldPosition = Intermediates.ParticleTranslatedWorldPosition;
#endif
#if USE_PARTICLE_VELOCITY
Interpolants.ParticleVelocity = Intermediates.ParticleVelocity;
#endif
#if USE_PARTICLE_TIME
Interpolants.RelativeTime = Intermediates.RelativeTime;
#endif
#if USE_PARTICLE_RANDOM
Interpolants.ParticleRandom = Intermediates.ParticleRandom;
#endif
#if USE_PARTICLE_LOCAL_TO_WORLD
//-TODO: LWC Precision Loss
float4x4 ParticleToWorldT = transpose(LWCHackToFloat(Intermediates.ParticleToWorld));
Interpolants.ParticleToWorld[0] = ParticleToWorldT[0];
Interpolants.ParticleToWorld[1] = ParticleToWorldT[1];
Interpolants.ParticleToWorld[2] = ParticleToWorldT[2];
#endif
#if USE_PARTICLE_WORLD_TO_LOCAL
//-TODO: LWC Precision Loss
float4x4 WorldToParticleT = transpose(LWCHackToFloat(Intermediates.WorldToParticle));
Interpolants.WorldToParticle[0] = WorldToParticleT[0];
Interpolants.WorldToParticle[1] = WorldToParticleT[1];
Interpolants.WorldToParticle[2] = WorldToParticleT[2];
#endif
#if VF_USE_PRIMITIVE_SCENE_DATA
Interpolants.PrimitiveId = Intermediates.SceneData.PrimitiveId;
#endif
return Interpolants;
}
// @return previous translated world position
float4 VertexFactoryGetPreviousWorldPosition(FVertexFactoryInput Input, FVertexFactoryIntermediates Intermediates)
{
FLWCMatrix Transform = Intermediates.PrevParticleToWorld;
float3 WorldPosition = LWCToFloat(LWCAdd(LWCMultiply(Input.Position.xyz, Transform), ResolvedView.TileOffset.PrevPreViewTranslation));
return float4(WorldPosition, Input.Position.w);
}
// local position relative to primitive
float3 VertexFactoryGetPreviousInstanceSpacePosition(FVertexFactoryInput Input, FVertexFactoryIntermediates Intermediates)
{
return Input.Position.xyz; // No support for instancing, so instance == primitive
}
uint VertexFactoryGetPrimitiveId(FVertexFactoryInterpolantsVSToPS Interpolants)
{
#if VF_USE_PRIMITIVE_SCENE_DATA
return Interpolants.PrimitiveId;
#else
return 0;
#endif
}
float4 VertexFactoryGetInstanceHitProxyId(FVertexFactoryInput Input, FVertexFactoryIntermediates Intermediates)
{
return 0;
}
float4 VertexFactoryGetTranslatedPrimitiveVolumeBounds(FVertexFactoryInterpolantsVSToPS Interpolants)
{
return float4(0,0,0,0);
}
#if NEEDS_VERTEX_FACTORY_INTERPOLATION || RAYHITGROUPSHADER
struct FVertexFactoryRayTracingInterpolants
{
FVertexFactoryInterpolantsVSToPS InterpolantsVSToPS;
};
float2 VertexFactoryGetRayTracingTextureCoordinate( FVertexFactoryRayTracingInterpolants Interpolants )
{
#if USE_PARTICLE_SUBUVS
return Interpolants.InterpolantsVSToPS.SubUV0AndTexCoord0.zw;
#elif NUM_TEX_COORD_INTERPOLATORS
return Interpolants.InterpolantsVSToPS.TexCoords[0].xy;
#else
return float2(0,0);
#endif
}
FVertexFactoryInterpolantsVSToPS VertexFactoryAssignInterpolants(FVertexFactoryRayTracingInterpolants Input)
{
return Input.InterpolantsVSToPS;
}
FVertexFactoryRayTracingInterpolants VertexFactoryGetRayTracingInterpolants(FVertexFactoryInput Input, FVertexFactoryIntermediates Intermediates, FMaterialVertexParameters VertexParameters)
{
FVertexFactoryRayTracingInterpolants Interpolants;
Interpolants.InterpolantsVSToPS = VertexFactoryGetInterpolantsVSToPS(Input, Intermediates, VertexParameters);
return Interpolants;
}
FVertexFactoryRayTracingInterpolants VertexFactoryInterpolate(FVertexFactoryRayTracingInterpolants a, float aInterp, FVertexFactoryRayTracingInterpolants b, float bInterp)
{
FVertexFactoryRayTracingInterpolants O;
// Do we really need to interpolate TangentToWorld2 here? It should be replaced by the
// interpolated normal from 'whatever' interpolation scheme we're using
INTERPOLATE_MEMBER(InterpolantsVSToPS.TangentToWorld0.xyz);
INTERPOLATE_MEMBER(InterpolantsVSToPS.TangentToWorld2);
#if INTERPOLATE_VERTEX_COLOR
INTERPOLATE_MEMBER(InterpolantsVSToPS.VertexColor);
#endif
#if NEEDS_PARTICLE_COLOR
INTERPOLATE_MEMBER(InterpolantsVSToPS.ParticleColor);
#endif
#if USE_PARTICLE_SUBUVS
INTERPOLATE_MEMBER(InterpolantsVSToPS.SubUV0AndTexCoord0);
#elif NUM_TEX_COORD_INTERPOLATORS
for (int i = 0; i < ( NUM_TEX_COORD_INTERPOLATORS + 1) / 2; ++i)
{
INTERPOLATE_MEMBER(InterpolantsVSToPS.TexCoords[i]);
}
#endif
#if (DYNAMIC_PARAMETERS_MASK & 1)
INTERPOLATE_MEMBER(InterpolantsVSToPS.DynamicParameter);
#endif
#if (DYNAMIC_PARAMETERS_MASK & 2)
INTERPOLATE_MEMBER(InterpolantsVSToPS.DynamicParameter1);
#endif
#if (DYNAMIC_PARAMETERS_MASK & 4)
INTERPOLATE_MEMBER(InterpolantsVSToPS.DynamicParameter2);
#endif
#if (DYNAMIC_PARAMETERS_MASK & 8)
INTERPOLATE_MEMBER(InterpolantsVSToPS.DynamicParameter3);
#endif
#if USE_PARTICLE_LOCAL_TO_WORLD
INTERPOLATE_MEMBER(InterpolantsVSToPS.ParticleToWorld[0]);
INTERPOLATE_MEMBER(InterpolantsVSToPS.ParticleToWorld[1]);
INTERPOLATE_MEMBER(InterpolantsVSToPS.ParticleToWorld[2]);
#endif
#if USE_PARTICLE_WORLD_TO_LOCAL
INTERPOLATE_MEMBER(InterpolantsVSToPS.WorldToParticle[0]);
INTERPOLATE_MEMBER(InterpolantsVSToPS.WorldToParticle[1]);
INTERPOLATE_MEMBER(InterpolantsVSToPS.WorldToParticle[2]);
#endif
#if VF_USE_PRIMITIVE_SCENE_DATA
O.InterpolantsVSToPS.PrimitiveId = a.InterpolantsVSToPS.PrimitiveId;
#endif
return O;
}
#endif // #if NEEDS_VERTEX_FACTORY_INTERPOLATION
// RHI_RAYTRACING
#if RAYHITGROUPSHADER
FVertexFactoryInput LoadVertexFactoryInputForHGS(uint TriangleIndex, int VertexIndex)
{
FVertexFactoryInput Input = (FVertexFactoryInput) 0;
FTriangleBaseAttributes Tri = LoadTriangleBaseAttributes(TriangleIndex);
uint VertexId = Tri.Indices[VertexIndex];
// Fill FVertexFactoryInput with dummy values, the real ones will be fetched later from NiagaraMeshVF using InstanceId
Input.Position = float4(Tri.LocalPositions[VertexIndex], 1.0f);
#if PASS_NEEDS_VERTEX_ID || MANUAL_VERTEX_FETCH
Input.VertexId = VertexId;
#endif // #if PASS_NEEDS_VERTEX_ID
#if (VF_USE_PRIMITIVE_SCENE_DATA == 1)
const uint GPUSceneInstanceId = GetInstanceUserData();
const FInstanceSceneData InstanceSceneData = GetInstanceSceneData(GPUSceneInstanceId);
VF_GPUSCENE_SET_INPUT_FOR_RT(Input, GPUSceneInstanceId, InstanceSceneData.RelativeId);
#else
#error "HGS requires GPU Scene support"
#endif
return Input;
}
#endif // #if COMPUTESHADER || RAYHITGROUPSHADER
#include "/Engine/Private/VertexFactoryDefaultInterface.ush"