Files
UnrealEngine/Engine/Plugins/Enterprise/LidarPointCloud/Shaders/Private/LidarPointCloudVertexFactory.ush
2025-05-18 13:04:45 +08:00

631 lines
20 KiB
HLSL

// Copyright Epic Games, Inc. All Rights Reserved.
#include "/Engine/Private/Common.ush"
#include "/Engine/Private/VertexFactoryCommon.ush"
/*=============================================================================
LidarPointCloudVertexFactory.usf: LiDAR Point Cloud vertex factory shader code.
=============================================================================*/
// First half is normal, second half has inverted V
static float2 PrecomputedUV_Quad[8] = { float2(-0.5, -0.5), float2(0.5, -0.5), float2(0.5, 0.5), float2(-0.5, 0.5), float2(0, 1), float2(1, 1), float2(1, 0), float2(0, 0) };
// Used to detect if the instance is rendered inside the editor viewport
uint bEditorView;
// Selection
half3 SelectionColor;
// Alignment
float3 LocationOffset;
// Used for sprite size calculation
float VirtualDepth;
float SpriteSizeMultiplier;
float RootCellSize;
float3 RootExtent;
uint bUsePerPointScaling;
float ReversedVirtualDepthMultiplier;
#if !RAYHITGROUPSHADER
Buffer<float> TreeBuffer;
#endif
// Needed for WPO calculations
float3 ViewRightVector;
float3 ViewUpVector;
uint bUseCameraFacing;
uint bUseScreenSizeScaling;
uint bUseStaticBuffers;
// Used for coloration override
float3 BoundsSize;
half3 ElevationColorBottom;
half3 ElevationColorTop;
// Color Adjustment
half4 Offset;
half4 Contrast;
half4 Saturation;
half4 Gamma;
half3 Tint;
float IntensityInfluence;
// Flags
uint bUseCircle;
uint bUseColorOverride;
uint bUseElevationColor;
uint bUseClassification;
uint bUseClassificationAlpha;
float4 ClassificationColors[32];
/**
* [Tx, Ty, Tz, Invert]
* [Fx, Fy, Fz, Ex]
* [Rx, Ry, Rz, Ey]
* [Ux, Uy, Uz, Ez]
*/
float4x4 ClippingVolume[16];
uint NumClippingVolumes;
uint bStartClipped;
struct FVertexFactoryInput
{
float4 Position : ATTRIBUTE0;
half4 Color : ATTRIBUTE1;
uint MetaData : ATTRIBUTE2;
uint VertexId : SV_VertexID;
VF_INSTANCED_STEREO_DECLARE_INPUT_BLOCK()
VF_MOBILE_MULTI_VIEW_DECLARE_INPUT_BLOCK()
};
struct FPositionOnlyVertexFactoryInput
{
float4 Position : ATTRIBUTE0;
uint VertexId : SV_VertexID;
VF_INSTANCED_STEREO_DECLARE_INPUT_BLOCK()
VF_MOBILE_MULTI_VIEW_DECLARE_INPUT_BLOCK()
};
struct FPositionAndNormalOnlyVertexFactoryInput
{
float4 Position : ATTRIBUTE0;
float4 Normal : ATTRIBUTE2;
uint VertexId : SV_VertexID;
VF_INSTANCED_STEREO_DECLARE_INPUT_BLOCK()
VF_MOBILE_MULTI_VIEW_DECLARE_INPUT_BLOCK()
};
struct FVertexFactoryInterpolantsVSToPS
{
TANGENTTOWORLD_INTERPOLATOR_BLOCK
half4 Color : COLOR0;
half Alpha : COLOR1;
float2 TexCoords : TEXCOORD0;
};
struct FVertexFactoryIntermediates
{
half3x3 TangentToLocal;
half3x3 TangentToWorld;
half TangentToWorldSign;
half4 Color;
half Alpha;
float3 Position;
/** Cached primitive and instance data */
FSceneDataIntermediates SceneData;
};
float3 ApplyClipping(float3 Position)
{
bool bClip = bStartClipped;
// Only process clipping if not in the editor view
if (!bEditorView)
{
for (uint i = 0; i < NumClippingVolumes; i++)
{
float3 DeltaPosition = DFDemote(TransformLocalToWorld(Position)).xyz - ClippingVolume[i][0].xyz;
bool bInsideClippingBox = abs(dot(DeltaPosition, ClippingVolume[i][1].xyz)) <= ClippingVolume[i][1].w && abs(dot(DeltaPosition, ClippingVolume[i][2].xyz)) <= ClippingVolume[i][2].w && abs(dot(DeltaPosition, ClippingVolume[i][3].xyz)) <= ClippingVolume[i][3].w;
if (ClippingVolume[i][0][3] == 1)
{
if (bInsideClippingBox)
{
bClip = true;
}
}
else
{
if (bInsideClippingBox)
{
bClip = false;
}
}
}
}
return (!bEditorView && bClip) ? 0.0f / 0 : Position;
}
half3x3 CalcTangentToLocal(uint MetaData)
{
half3x3 TangentToLocal;
if (bUseCameraFacing)
{
// In this mode, [0] and [1] are only really used for scaling
TangentToLocal[0] = ViewRightVector;
TangentToLocal[1] = ViewUpVector;
// Hardcoded to have the lighting behave more correctly
TangentToLocal[2] = float3(0, 0, 1);
}
else
{
half3 Normal = half3((0x000000FF & MetaData) / 127.5f - 1, (0x000000FF & (MetaData >> 8)) / 127.5f - 1, (0x000000FF & (MetaData >> 16)) / 127.5f - 1);
// Force camera facing
if (dot(Normal, Normal) < 0.1f)
{
// In this mode, [0] and [1] are only really used for scaling
TangentToLocal[0] = ViewRightVector;
TangentToLocal[1] = ViewUpVector;
// Hardcoded to have the lighting behave more correctly
TangentToLocal[2] = float3(0, 0, 1);
}
else
{
half3 N = abs(Normal);
half3 Tangent = half3(1, 0, 0);
// Find best basis vectors.
if (N.z > N.x && N.z > N.y)
{
Tangent = half3(1, 0, 0);
}
else
{
Tangent = half3(0, 0, 1);
}
Tangent = (Tangent - Normal * dot(Tangent, Normal));
Tangent = Tangent * rsqrt(dot(Tangent, Tangent));
TangentToLocal[0] = Tangent;
TangentToLocal[1] = cross(Tangent, Normal);
TangentToLocal[2] = Normal;
}
}
return TangentToLocal;
}
half3x3 CalcTangentToWorldNoScale(in half3x3 TangentToLocal)
{
half3x3 LocalToWorld = GetLocalToWorld3x3();
half3 InvScale = Primitive.InvNonUniformScale;
LocalToWorld[0] *= InvScale.x;
LocalToWorld[1] *= InvScale.y;
LocalToWorld[2] *= InvScale.z;
return mul(TangentToLocal, LocalToWorld);
}
float CalcSpriteSize(float3 Position)
{
float VD = VirtualDepth;
#if !RAYHITGROUPSHADER
if (bUsePerPointScaling)
{
VD = 0;
uint Idx = 0;
float3 NodeExtent = RootExtent;
float3 NodeCenter = LocationOffset;
while (true)
{
uint TreeBufferData = asuint(TreeBuffer[Idx]);
uint ChildrenBitmask = 0x000000FF & TreeBufferData;
float3 CenterRelativeLocation = Position - NodeCenter;
uint ChildNodeIndex = (CenterRelativeLocation.x > 0 ? 4 : 0) + (CenterRelativeLocation.y > 0 ? 2 : 0) + (CenterRelativeLocation.z > 0);
if ((ChildrenBitmask & (1u << ChildNodeIndex)) == 0)
{
break;
}
Idx += (0x0000FFFF & (TreeBufferData >> 8));
for (uint i = 0; i < 8; i++)
{
if (i == ChildNodeIndex)
{
break;
}
if ((ChildrenBitmask & (1u << i)) != 0)
{
Idx++;
}
}
VD = (0x000000FF & (TreeBufferData >> 24)) * ReversedVirtualDepthMultiplier;
NodeCenter += NodeExtent * (float3((ChildNodeIndex & 4) == 4, (ChildNodeIndex & 2) == 2, (ChildNodeIndex & 1) == 1) - 0.5f);
NodeExtent *= 0.5f;
}
}
#endif
return RootCellSize / pow(2.0f, VD);
}
float3 ProcessPosition(float3 Position, half3x3 TangentToLocal, int VertexID)
{
const float Size = bUseScreenSizeScaling ? mul(float4(Position.xyz, 1), ResolvedView.TranslatedWorldToView).z * 0.01f : CalcSpriteSize(Position);
const half2 Scale = PrecomputedUV_Quad[VertexID % 4];
return Position + (TangentToLocal[0] * Scale.x + TangentToLocal[1] * Scale.y) * SpriteSizeMultiplier * Size;
}
float3 ProcessPosition(float3 Position, int VertexID)
{
half3x3 TangentToLocal;
TangentToLocal[0] = ViewRightVector;
TangentToLocal[1] = ViewUpVector;
return ProcessPosition(Position, TangentToLocal, VertexID);
}
float3 LidarGetInstancePosition(uint VertexId)
{
uint Idx = (VertexId / 4) * 5;
return float3(LidarVF.VertexFetch_Buffer[Idx], LidarVF.VertexFetch_Buffer[Idx + 1], LidarVF.VertexFetch_Buffer[Idx + 2]);
}
float3 LidarGetInstanceNormal(uint VertexId)
{
uint Idx = (VertexId / 4) * 5;
return CalcTangentToLocal(asuint(LidarVF.VertexFetch_Buffer[Idx + 4]))[2];
}
FVertexFactoryIntermediates GetVertexFactoryIntermediates(FVertexFactoryInput Input)
{
FVertexFactoryIntermediates Intermediates = (FVertexFactoryIntermediates)0;
Intermediates.SceneData = VF_GPUSCENE_GET_INTERMEDIATES(Input);
float3 Position;
half3 Color;
half Intensity;
uint MetaData;
if (bUseStaticBuffers)
{
Position = Input.Position.xyz;
MetaData = Input.MetaData;
Color = Input.Color.rgb;
Intensity = Input.Color.a;
}
else
{
uint Idx = (Input.VertexId / 4) * 5;
Position = float3(LidarVF.VertexFetch_Buffer[Idx], LidarVF.VertexFetch_Buffer[Idx + 1], LidarVF.VertexFetch_Buffer[Idx + 2]);
uint ColorData = asuint(LidarVF.VertexFetch_Buffer[Idx + 3]);
Color = half3(0x000000FF & (ColorData >> 16), 0x000000FF & (ColorData >> 8), 0x000000FF & ColorData) * 0.003921568627451;
Intensity = (0x000000FF & (ColorData >> 24)) * 0.003921568627451;
MetaData = asuint(LidarVF.VertexFetch_Buffer[Idx + 4]);
}
Intermediates.TangentToLocal = CalcTangentToLocal(MetaData);
Intermediates.TangentToWorldSign = Intermediates.SceneData.InstanceData.DeterminantSign;
Intermediates.TangentToWorld = CalcTangentToWorldNoScale(Intermediates.TangentToLocal);
Intermediates.Position = ApplyClipping(Position + LocationOffset);
// Color
{
MetaData = 0x000000FF & (MetaData >> 24);
uint bSelected = clamp(0x00000040 & MetaData, 0, 1);
uint Classification = 0x0000001F & (MetaData >> 1);
half3 ElevationColor = lerp(ElevationColorBottom, ElevationColorTop, clamp((Position.z + BoundsSize.z * 0.5) / BoundsSize.z, 0, 1));
half3 PositionColor = (Position + BoundsSize * 0.5) / BoundsSize;
float4 ClassificationColor = ClassificationColors[Classification];
// Pick color source
Color = lerp(Color, lerp(lerp(PositionColor, ClassificationColor.rgb, bUseClassification), ElevationColor, bUseElevationColor), bUseColorOverride);
// Mix with Intensity
Color = lerp(Color, Color * Intensity, IntensityInfluence);
// Color Adjustment
{
Color = lerp(dot(Color, half3(0.299, 0.587, 0.144)), Color, Saturation.rgb * Saturation.a);
Color *= Tint;
Color = pow(Color, 2.2 * Gamma.rgb * Gamma.a);
Color = (Color - 0.5) * Contrast.rgb * Contrast.a + 0.5;
Color += Offset.rgb * Offset.a;
Color = clamp(Color, 0, 1);
}
// Selection
Color = lerp(Color, SelectionColor, bSelected);
Intermediates.Color = half4(Color, bUseCircle);
Intermediates.Alpha = lerp(1, ClassificationColor.a, bUseClassification || bUseClassificationAlpha);
}
return Intermediates;
}
FVertexFactoryInterpolantsVSToPS VertexFactoryGetInterpolantsVSToPS(FVertexFactoryInput Input, FVertexFactoryIntermediates Intermediates, FMaterialVertexParameters VertexParameters)
{
FVertexFactoryInterpolantsVSToPS Interpolants = (FVertexFactoryInterpolantsVSToPS)0;
Interpolants.TangentToWorld0 = float4(Intermediates.TangentToWorld[0], 0);
Interpolants.TangentToWorld2 = float4(Intermediates.TangentToWorld[2], Intermediates.TangentToWorldSign);
Interpolants.Color = VertexParameters.VertexColor;
Interpolants.Alpha = Intermediates.Alpha;
Interpolants.TexCoords = PrecomputedUV_Quad[Input.VertexId % 4 + 4]; // Using inverted V
return Interpolants;
}
half3x3 VertexFactoryGetTangentToLocal(FVertexFactoryInput Input, FVertexFactoryIntermediates Intermediates)
{
return Intermediates.TangentToLocal;
}
// @return translated world position
float4 VertexFactoryGetWorldPosition(FVertexFactoryInput Input, FVertexFactoryIntermediates Intermediates)
{
float4 WorldPosition = TransformLocalToTranslatedWorld(Intermediates.Position, Intermediates.SceneData.Primitive.LocalToWorld);
WorldPosition.xyz = ProcessPosition(WorldPosition.xyz, Intermediates.TangentToLocal, Input.VertexId);
return WorldPosition;
}
// local position relative to instance
float3 VertexFactoryGetInstanceSpacePosition(FVertexFactoryInput Input, FVertexFactoryIntermediates Intermediates)
{
// No support for instancing, so instance == primitive
return Intermediates.Position;
}
float4 VertexFactoryGetWorldPosition(FPositionOnlyVertexFactoryInput Input)
{
float4 WorldPosition = TransformLocalToTranslatedWorld(
ApplyClipping((bUseStaticBuffers ? Input.Position.xyz : LidarGetInstancePosition(Input.VertexId)) + LocationOffset),
GetPrimitiveDataFromUniformBuffer().LocalToWorld);
WorldPosition.xyz = ProcessPosition(WorldPosition.xyz, Input.VertexId);
return WorldPosition;
}
float4 VertexFactoryGetWorldPosition(FPositionAndNormalOnlyVertexFactoryInput Input)
{
float4 WorldPosition = TransformLocalToTranslatedWorld(
ApplyClipping((bUseStaticBuffers ? Input.Position.xyz : LidarGetInstancePosition(Input.VertexId)) + LocationOffset),
GetPrimitiveDataFromUniformBuffer().LocalToWorld);
WorldPosition.xyz = ProcessPosition(WorldPosition.xyz, Input.VertexId);
return WorldPosition;
}
float4 VertexFactoryGetRasterizedWorldPosition(FVertexFactoryInput Input, FVertexFactoryIntermediates Intermediates, float4 InWorldPosition)
{
return InWorldPosition;
}
float3 VertexFactoryGetPositionForVertexLighting(FVertexFactoryInput Input, FVertexFactoryIntermediates Intermediates, float3 TranslatedWorldPosition)
{
return TranslatedWorldPosition;
}
float3 VertexFactoryGetWorldNormal(FPositionAndNormalOnlyVertexFactoryInput Input)
{
return RotateLocalToWorld(bUseStaticBuffers ? Input.Normal.xyz : LidarGetInstanceNormal(Input.VertexId));
}
float3 VertexFactoryGetWorldNormal(FVertexFactoryInput Input, FVertexFactoryIntermediates Intermediates)
{
return Intermediates.TangentToWorld[2];
}
// @return previous translated world position
float4 VertexFactoryGetPreviousWorldPosition(FVertexFactoryInput Input, FVertexFactoryIntermediates Intermediates)
{
return mul(float4(Intermediates.Position, 1), DFMultiplyTranslationDemote(Intermediates.SceneData.InstanceData.PrevLocalToWorld, ResolvedView.PrevPreViewTranslation));
}
// local position relative to instance
float3 VertexFactoryGetPreviousInstanceSpacePosition(FVertexFactoryInput Input, FVertexFactoryIntermediates Intermediates)
{
// No support for instancing, so instance == primitive
return Intermediates.Position;
}
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,
half3x3 TangentToLocal,
bool bIsPreviousFrame = false)
{
FMaterialVertexParameters Result = MakeInitializedMaterialVertexParameters();
Result.SceneData = Intermediates.SceneData;
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.TangentToWorld = Intermediates.TangentToWorld;
Result.PreSkinnedNormal = TangentToLocal[2];
Result.PreSkinnedPosition = WorldPosition;
Result.VertexColor = Intermediates.Color;
#if NUM_MATERIAL_TEXCOORDS_VERTEX
Result.TexCoords[0] = PrecomputedUV_Quad[Input.VertexId % 4];
#endif
Result.LWCData = MakeMaterialLWCData(Result);
return Result;
}
FMaterialPixelParameters GetMaterialPixelParameters(FVertexFactoryInterpolantsVSToPS Interpolants, float4 SvPosition)
{
FMaterialPixelParameters Result = MakeInitializedMaterialPixelParameters();
Result.Particle.Color = half4(1, 1, 1, 1);
Result.TwoSidedSign = 1;
Result.VertexColor = Interpolants.Color;
Result.VertexColor.a = saturate((lerp(1, 1 - distance(Interpolants.TexCoords, 0.5), Interpolants.Color.a) - 0.5) * 10000) * Interpolants.Alpha;
half3 TangentToWorld0 = Interpolants.TangentToWorld0.xyz;
half4 TangentToWorld2 = Interpolants.TangentToWorld2;
Result.UnMirrored = TangentToWorld2.w;
Result.TangentToWorld = AssembleTangentToWorld(TangentToWorld0, TangentToWorld2);
#if NUM_TEX_COORD_INTERPOLATORS
Result.TexCoords[0] = Interpolants.TexCoords;
#endif
return Result;
}
#if USE_INSTANCING
float4 VertexFactoryGetInstanceHitProxyId(FVertexFactoryInput Input, FVertexFactoryIntermediates Intermediates) { return 0; }
#endif
float4 VertexFactoryGetTranslatedPrimitiveVolumeBounds(FVertexFactoryInterpolantsVSToPS Interpolants)
{
FPrimitiveSceneData PrimitiveData = GetPrimitiveDataFromUniformBuffer();
return float4(DFFastToTranslatedWorld(PrimitiveData.ObjectWorldPosition, ResolvedView.PreViewTranslation), PrimitiveData.ObjectRadius);
}
#if NEEDS_VERTEX_FACTORY_INTERPOLATION
struct FVertexFactoryRayTracingInterpolants
{
FVertexFactoryInterpolantsVSToPS InterpolantsVSToPS;
};
float2 VertexFactoryGetRayTracingTextureCoordinate( FVertexFactoryRayTracingInterpolants Interpolants )
{
#if NUM_MATERIAL_TEXCOORDS
return Interpolants.InterpolantsVSToPS.TexCoords.xy;
#else // #if NUM_MATERIAL_TEXCOORDS
return float2(0,0);
#endif // #if NUM_MATERIAL_TEXCOORDS
}
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.Color);
#endif
#if NUM_TEX_COORD_INTERPOLATORS
INTERPOLATE_MEMBER(InterpolantsVSToPS.TexCoords);
#endif
return O;
}
#endif // #if NEEDS_VERTEX_FACTORY_INTERPOLATION
uint VertexFactoryGetPrimitiveId(FVertexFactoryInterpolantsVSToPS Interpolants)
{
return 0;
}
#if RAYHITGROUPSHADER || COMPUTESHADER
uint GetNumRayTracingDynamicMeshVerticesIndirect()
{
return 0;
}
#endif
FVertexFactoryInput LoadVertexFactoryInputFromIndices(uint TriangleIndex, int VertexIndex)
{
FVertexFactoryInput Input = (FVertexFactoryInput)0;
Input.VertexId = TriangleIndex * 3 + VertexIndex;
/**
* When using static buffers we duplicate the data for each of the 4 vertices of the plane so we can use the VertexId directly
* When using dynamic buffers, each 4 vertices of the plane will share the same data element so we need to divide by 4
*
* The buffer stride is 20 bytes and data is held in floats, so we need to multiply the starting offset by 5
*/
uint VertexOffset = (bUseStaticBuffers ? Input.VertexId : floor(Input.VertexId / 4)) * 5;
// Helps minimize incorrect self-shadowing due to camera-facing planes
float ZOffset = 0.3;
Input.Position.x = LidarVF.VertexFetch_Buffer[VertexOffset + 0];
Input.Position.y = LidarVF.VertexFetch_Buffer[VertexOffset + 1];
Input.Position.z = LidarVF.VertexFetch_Buffer[VertexOffset + 2] - ZOffset;
uint ColorData = asuint(LidarVF.VertexFetch_Buffer[VertexOffset + 3]);
Input.Color = half4(0x000000FF & (ColorData >> 16), 0x000000FF & (ColorData >> 8), 0x000000FF & ColorData, 0x000000FF & (ColorData >> 24)) * 0.003921568627451;
Input.MetaData = asuint(LidarVF.VertexFetch_Buffer[VertexOffset + 4]);
return Input;
}
#if RAYHITGROUPSHADER
FVertexFactoryInput LoadVertexFactoryInputForHGS(uint TriangleIndex, int VertexIndex)
{
FVertexFactoryInput Input = LoadVertexFactoryInputFromIndices(TriangleIndex, VertexIndex);
#if VF_USE_PRIMITIVE_SCENE_DATA
VF_GPUSCENE_SET_INPUT_FOR_RT(Input, GetInstanceUserData(), 0U);
#endif // VF_USE_PRIMITIVE_SCENE_DATA
return Input;
}
#endif
#if COMPUTESHADER
FVertexFactoryInput LoadVertexFactoryInputForDynamicUpdate(uint TriangleIndex, int VertexIndex, uint PrimitiveId, uint DrawInstanceId)
{
FVertexFactoryInput Input = LoadVertexFactoryInputFromIndices(TriangleIndex, VertexIndex);
FPrimitiveSceneData PrimitiveData = GetPrimitiveData(PrimitiveId);
VF_GPUSCENE_SET_INPUT_FOR_RT(Input, PrimitiveData.InstanceSceneDataOffset + DrawInstanceId, DrawInstanceId);
return Input;
}
#endif
#include "/Engine/Private/VertexFactoryDefaultInterface.ush"