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

1224 lines
55 KiB
HLSL

// Copyright Epic Games, Inc. All Rights Reserved.
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Parameters
Buffer<uint> {ParameterName}_MeshIndexBuffer;
Buffer<float> {ParameterName}_MeshVertexBuffer;
Buffer<uint> {ParameterName}_MeshSkinWeightBuffer;
Buffer<uint> {ParameterName}_MeshSkinWeightLookupBuffer;
Buffer<float4> {ParameterName}_MeshCurrBonesBuffer;
Buffer<float4> {ParameterName}_MeshPrevBonesBuffer;
Buffer<float4> {ParameterName}_MeshCurrSamplingBonesBuffer;
Buffer<float4> {ParameterName}_MeshPrevSamplingBonesBuffer;
Buffer<float4> {ParameterName}_MeshTangentBuffer;
Buffer<float2> {ParameterName}_MeshTexCoordBuffer;
Buffer<float4> {ParameterName}_MeshColorBuffer;
Buffer<uint> {ParameterName}_MeshTriangleSamplerProbAliasBuffer;
uint {ParameterName}_MeshNumSamplingRegionTriangles;
uint {ParameterName}_MeshNumSamplingRegionVertices;
Buffer<uint> {ParameterName}_MeshSamplingRegionsProbAliasBuffer;
Buffer<uint> {ParameterName}_MeshSampleRegionsTriangleIndices;
Buffer<uint> {ParameterName}_MeshSampleRegionsVertices;
Buffer<uint> {ParameterName}_MeshTriangleMatricesOffsetBuffer;
uint {ParameterName}_MeshTriangleCount;
uint {ParameterName}_MeshVertexCount;
uint {ParameterName}_MeshNumTexCoord;
uint {ParameterName}_MeshNumWeights;
uint {ParameterName}_MeshBoneWeightStride;
uint {ParameterName}_MeshBoneIndexSizeBytes;
uint {ParameterName}_MeshBoneWeightSizeBytes;
int {ParameterName}_NumBones;
int {ParameterName}_NumFilteredBones;
int {ParameterName}_NumUnfilteredBones;
int {ParameterName}_RandomMaxBone;
int {ParameterName}_ExcludeBoneIndex;
Buffer<uint> {ParameterName}_FilteredAndUnfilteredBones;
int {ParameterName}_NumFilteredSockets;
int {ParameterName}_FilteredSocketBoneOffset;
Buffer<int> {ParameterName}_UvMappingBuffer;
uint {ParameterName}_UvMappingBufferLength;
uint {ParameterName}_UvMappingSet;
Buffer<uint> {ParameterName}_ConnectivityBuffer;
uint {ParameterName}_ConnectivityBufferLength;
uint {ParameterName}_ConnectivityMaxAdjacentPerVertex;
float4x4 {ParameterName}_InstanceTransform;
float4x4 {ParameterName}_InstancePrevTransform;
float4 {ParameterName}_InstanceRotation;
float4 {ParameterName}_InstancePrevRotation;
float {ParameterName}_InstanceInvDeltaTime;
float3 {ParameterName}_PreSkinnedLocalBoundsCenter;
float3 {ParameterName}_PreSkinnedLocalBoundsExtents;
uint {ParameterName}_EnabledFeatures;
#if DISKELMESH_ALLOW_DEFORMED
Buffer<float> {ParameterName}_DeformedCurrPositionBuffer;
Buffer<float> {ParameterName}_DeformedPrevPositionBuffer;
Buffer<float4> {ParameterName}_DeformedTangentBuffer;
#endif
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Flags test
bool UniformTriangleSamplingEnable_{ParameterName}() { return ({ParameterName}_EnabledFeatures & 0x01) == 0x01; }
bool UniformSamplingRegionEnabled_{ParameterName}() { return ({ParameterName}_EnabledFeatures & 0x02) == 0x02; }
bool UnlimitedBoneInfluences_{ParameterName}() { return ({ParameterName}_EnabledFeatures & 0x04) == 0x04; }
bool HasMeshColors_{ParameterName}() { return ({ParameterName}_EnabledFeatures & 0x08) == 0x08; }
#if DISKELMESH_ALLOW_DEFORMED
bool UseDeformedPositions_{ParameterName}() { return ({ParameterName}_EnabledFeatures & 0x10) == 0x10; }
bool UseDeformedTangents_{ParameterName}() { return ({ParameterName}_EnabledFeatures & 0x20) == 0x20; }
#endif
void GetIndexWeight_{ParameterName}(int BoneIndexOffset, int BoneWeightOffset, int Layer, out int4 BlendIndices, out float4 BlendWeights)
{
#if DISKELMESH_ALLOW_16BIT
BlendIndices = {ParameterName}_MeshBoneIndexSizeBytes == 1 ?
DISkelMesh_UnpackIndices4x8({ParameterName}_MeshSkinWeightBuffer[BoneIndexOffset + Layer]) :
DISkelMesh_UnpackIndices4x16({ParameterName}_MeshSkinWeightBuffer[BoneIndexOffset + (Layer << 1)], {ParameterName}_MeshSkinWeightBuffer[BoneIndexOffset + (Layer << 1) + 1]);
BlendWeights = {ParameterName}_MeshBoneWeightSizeBytes == 1 ?
DISkelMesh_UnpackWeights4x8({ParameterName}_MeshSkinWeightBuffer[BoneWeightOffset + Layer]) :
DISkelMesh_UnpackWeights4x16({ParameterName}_MeshSkinWeightBuffer[BoneWeightOffset + (Layer << 1)], {ParameterName}_MeshSkinWeightBuffer[BoneWeightOffset + (Layer << 1) + 1]);
#else
BlendIndices = DISkelMesh_UnpackIndices4x8({ParameterName}_MeshSkinWeightBuffer[BoneIndexOffset + Layer]);
BlendWeights = DISkelMesh_UnpackWeights4x8({ParameterName}_MeshSkinWeightBuffer[BoneWeightOffset + Layer]);
#endif
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Misc functions
void GetPreSkinnedLocalBounds_{ParameterName}(out float3 OutCenter, out float3 OutExtentsMin, out float3 OutExtentsMax, out float3 OutExtents, out float3 OutHalfExtents)
{
OutCenter = {ParameterName}_PreSkinnedLocalBoundsCenter;
OutExtents = {ParameterName}_PreSkinnedLocalBoundsExtents;
OutHalfExtents = OutExtents * 0.5f;
OutExtentsMin = OutCenter - OutHalfExtents;
OutExtentsMax = OutCenter + OutHalfExtents;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Triangle Sampling
float3x4 GetPrevBoneSkinningMatrix_{ParameterName}(uint Bone)
{
return float3x4({ParameterName}_MeshPrevBonesBuffer[Bone * 3], {ParameterName}_MeshPrevBonesBuffer[Bone * 3 + 1], {ParameterName}_MeshPrevBonesBuffer[Bone * 3 + 2]);
}
float3x4 GetPrevSkinningMatrix_{ParameterName}(uint SectionBoneOffset, int4 BlendIndices, float4 BlendWeights)
{
float3x4 Result;
Result = GetPrevBoneSkinningMatrix_{ParameterName}(SectionBoneOffset + BlendIndices.x) * BlendWeights.x;
Result += GetPrevBoneSkinningMatrix_{ParameterName}(SectionBoneOffset + BlendIndices.y) * BlendWeights.y;
Result += GetPrevBoneSkinningMatrix_{ParameterName}(SectionBoneOffset + BlendIndices.z) * BlendWeights.z;
Result += GetPrevBoneSkinningMatrix_{ParameterName}(SectionBoneOffset + BlendIndices.w) * BlendWeights.w;
return Result;
}
float3x4 GetCurrBoneSkinningMatrix_{ParameterName}(uint Bone)
{
return float3x4({ParameterName}_MeshCurrBonesBuffer[Bone * 3], {ParameterName}_MeshCurrBonesBuffer[Bone * 3 + 1], {ParameterName}_MeshCurrBonesBuffer[Bone * 3 + 2]);
}
float3x4 GetCurrSkinningMatrix_{ParameterName}(uint SectionBoneOffset, int4 BlendIndices, float4 BlendWeights)
{
float3x4 Result;
Result = GetCurrBoneSkinningMatrix_{ParameterName}(SectionBoneOffset + BlendIndices.x) * BlendWeights.x;
Result += GetCurrBoneSkinningMatrix_{ParameterName}(SectionBoneOffset + BlendIndices.y) * BlendWeights.y;
Result += GetCurrBoneSkinningMatrix_{ParameterName}(SectionBoneOffset + BlendIndices.z) * BlendWeights.z;
Result += GetCurrBoneSkinningMatrix_{ParameterName}(SectionBoneOffset + BlendIndices.w) * BlendWeights.w;
return Result;
}
void IsValidTriCoord_{ParameterName}(in int TriangleIndex, out bool IsValid)
{
IsValid = TriangleIndex >= 0 && TriangleIndex < {ParameterName}_MeshTriangleCount;
}
void GetVertex_{ParameterName}(uint VertexIndex, out float3 OutPosition, out float3 OutTangentX, out float3 OutTangentY, out float3 OutTangentZ)
{
// Early out for bad data
if ( {ParameterName}_MeshVertexCount == 0 )
{
OutPosition = float3(0.0f, 0.0f, 0.0f);
OutTangentX = float3(1.0f, 0.0f, 0.0f);
OutTangentY = float3(0.0f, 1.0f, 0.0f);
OutTangentZ = float3(0.0f, 0.0f, 1.0f);
return;
}
VertexIndex = clamp(VertexIndex, 0, {ParameterName}_MeshVertexCount - 1);
//-TODO: Use a R32G32B32 format
float3 Position = float3({ParameterName}_MeshVertexBuffer[VertexIndex * 3], {ParameterName}_MeshVertexBuffer[VertexIndex * 3 + 1], {ParameterName}_MeshVertexBuffer[VertexIndex * 3 + 2]);
float3 TangentX = TangentBias({ParameterName}_MeshTangentBuffer[VertexIndex * 2 ].xyz);
float4 TangentZ = TangentBias({ParameterName}_MeshTangentBuffer[VertexIndex * 2 + 1].xyzw);
float3 TangentY = cross(TangentZ.xyz, TangentX.xyz) * TangentZ.w;
OutPosition = Position;
OutTangentX = cross(TangentY, TangentZ.xyz) * TangentZ.w;
OutTangentY = TangentY;
OutTangentZ = TangentZ.xyz;
}
void GetVertexData_{ParameterName}(int VertexIndex, out float3 OutPosition, out float3 OutTangentX, out float3 OutTangentY, out float3 OutTangentZ)
{
GetVertex_{ParameterName}(VertexIndex, OutPosition, OutTangentX, OutTangentY, OutTangentZ);
}
void GetPointOnTriangle_{ParameterName}(uint TriangleIndex, float3 BaryCoord, out float3 OutPosition, out float3 OutTangentX, out float3 OutTangentY, out float3 OutTangentZ)
{
// Early out for bad data
if ( {ParameterName}_MeshTriangleCount == 0 )
{
OutPosition = float3(0.0f, 0.0f, 0.0f);
OutTangentX = float3(1.0f, 0.0f, 0.0f);
OutTangentY = float3(0.0f, 1.0f, 0.0f);
OutTangentZ = float3(0.0f, 0.0f, 1.0f);
return;
}
TriangleIndex = clamp(TriangleIndex, 0, {ParameterName}_MeshTriangleCount - 1);
uint IndexBufferOffset = TriangleIndex * 3;
uint VertexIndex0 = {ParameterName}_MeshIndexBuffer[IndexBufferOffset];
uint VertexIndex1 = {ParameterName}_MeshIndexBuffer[IndexBufferOffset + 1];
uint VertexIndex2 = {ParameterName}_MeshIndexBuffer[IndexBufferOffset + 2];
float3 Positions[3], TangentsX[3], TangentsY[3], TangentsZ[3];
GetVertex_{ParameterName}(VertexIndex0, Positions[0], TangentsX[0], TangentsY[0], TangentsZ[0]);
GetVertex_{ParameterName}(VertexIndex1, Positions[1], TangentsX[1], TangentsY[1], TangentsZ[1]);
GetVertex_{ParameterName}(VertexIndex2, Positions[2], TangentsX[2], TangentsY[2], TangentsZ[2]);
OutPosition = Positions[0] * BaryCoord.x + Positions[1] * BaryCoord.y + Positions[2] * BaryCoord.z;
OutTangentX = TangentsX[0] * BaryCoord.x + TangentsX[1] * BaryCoord.y + TangentsX[2] * BaryCoord.z;
OutTangentY = TangentsY[0] * BaryCoord.x + TangentsY[1] * BaryCoord.y + TangentsY[2] * BaryCoord.z;
OutTangentZ = TangentsZ[0] * BaryCoord.x + TangentsZ[1] * BaryCoord.y + TangentsZ[2] * BaryCoord.z;
}
FDISkelMeshSkinnedVertex GetSkinnedVertex_{ParameterName}(uint VertexIndex)
{
// Early out for bad data
if ( {ParameterName}_MeshVertexCount == 0 )
{
FDISkelMeshSkinnedVertex SkinnedVertex;
SkinnedVertex.Position = float3(0.0f, 0.0f, 0.0f);
SkinnedVertex.PrevPosition = float3(0.0f, 0.0f, 0.0f);
SkinnedVertex.TangentX = float3(1.0f, 0.0f, 0.0f);
SkinnedVertex.TangentY = float3(0.0f, 1.0f, 0.0f);
SkinnedVertex.TangentZ = float3(0.0f, 0.0f, 1.0f);
return SkinnedVertex;
}
VertexIndex = clamp(VertexIndex, 0, {ParameterName}_MeshVertexCount - 1);
// Read Positions For Skinning
bool bNeedsSkinPositions = true;
float3 CurrPosition = 0;
float3 PrevPosition = 0;
#if DISKELMESH_ALLOW_DEFORMED
if (UseDeformedPositions_{ParameterName}())
{
bNeedsSkinPositions = false;
CurrPosition = float3({ParameterName}_DeformedCurrPositionBuffer[VertexIndex * 3], {ParameterName}_DeformedCurrPositionBuffer[VertexIndex * 3 + 1], {ParameterName}_DeformedCurrPositionBuffer[VertexIndex * 3 + 2]);
PrevPosition = float3({ParameterName}_DeformedPrevPositionBuffer[VertexIndex * 3], {ParameterName}_DeformedPrevPositionBuffer[VertexIndex * 3 + 1], {ParameterName}_DeformedPrevPositionBuffer[VertexIndex * 3 + 2]);
}
else
#endif
{
CurrPosition = float3({ParameterName}_MeshVertexBuffer[VertexIndex * 3], {ParameterName}_MeshVertexBuffer[VertexIndex * 3 + 1], {ParameterName}_MeshVertexBuffer[VertexIndex * 3 + 2]);
PrevPosition = CurrPosition;
}
// Read Tangents For Skinning
bool bNeedsSkinTangents = true;
float3 TangentX = 0;
float4 TangentZ = 0;
#if DISKELMESH_ALLOW_DEFORMED
if (UseDeformedTangents_{ParameterName}())
{
bNeedsSkinTangents = false;
TangentX = TangentBias({ParameterName}_DeformedTangentBuffer[VertexIndex * 2 ].xyz);
TangentZ = TangentBias({ParameterName}_DeformedTangentBuffer[VertexIndex * 2 + 1].xyzw);
}
else
#endif
{
TangentX = TangentBias({ParameterName}_MeshTangentBuffer[VertexIndex * 2 ].xyz);
TangentZ = TangentBias({ParameterName}_MeshTangentBuffer[VertexIndex * 2 + 1].xyzw);
}
// Perform skinning if needed
if ( {ParameterName}_MeshNumWeights > 0 && (bNeedsSkinPositions || bNeedsSkinTangents))
{
float3x4 PrevBoneMatrix;
float3x4 CurrBoneMatrix;
// Get the matrix offset for each vertex because BlendIndices are stored relatively to each section start vertex.
uint SectionBoneOffset = {ParameterName}_MeshTriangleMatricesOffsetBuffer[VertexIndex];
#if DISKELMESH_BONE_INFLUENCES == DISKELMESH_BONE_INFLUENCES_UNLIMITED
BRANCH
if (UnlimitedBoneInfluences_{ParameterName}())
{
const uint BlendOffsetCount = {ParameterName}_MeshSkinWeightLookupBuffer[VertexIndex];
const int NumBoneInfluences = BlendOffsetCount & 0xff;
const int StreamOffset = BlendOffsetCount >> 8;
const int WeightsOffset = StreamOffset + ({ParameterName}_MeshBoneIndexSizeBytes * NumBoneInfluences);
const float WeightNorm = {ParameterName}_MeshBoneWeightSizeBytes == 1 ? 1.0f / 255.0f : 1.0f / 65535.0f;
PrevBoneMatrix = float3x4(float4(0,0,0,0), float4(0,0,0,0), float4(0,0,0,0));
CurrBoneMatrix = float3x4(float4(0,0,0,0), float4(0,0,0,0), float4(0,0,0,0));
for (int InfluenceIdx = 0; InfluenceIdx < NumBoneInfluences; InfluenceIdx++)
{
const int BoneIndexOffset = StreamOffset + ({ParameterName}_MeshBoneIndexSizeBytes * InfluenceIdx);
int BoneIndex = {ParameterName}_MeshSkinWeightBuffer[BoneIndexOffset];
if ( {ParameterName}_MeshBoneIndexSizeBytes > 1 )
{
BoneIndex |= {ParameterName}_MeshSkinWeightBuffer[BoneIndexOffset + 1] << 8;
}
const int BoneWeightOffset = WeightsOffset + ({ParameterName}_MeshBoneWeightSizeBytes * InfluenceIdx);
int iBoneWeight = {ParameterName}_MeshSkinWeightBuffer[BoneWeightOffset];
if ( {ParameterName}_MeshBoneWeightSizeBytes > 1 )
{
iBoneWeight |= {ParameterName}_MeshSkinWeightBuffer[BoneWeightOffset + 1] << 8;
}
float BoneWeight = float(iBoneWeight) * WeightNorm;
PrevBoneMatrix += GetPrevBoneSkinningMatrix_{ParameterName}(SectionBoneOffset + BoneIndex) * BoneWeight;
CurrBoneMatrix += GetCurrBoneSkinningMatrix_{ParameterName}(SectionBoneOffset + BoneIndex) * BoneWeight;
}
}
else
#endif
{
const uint BoneIndexOffset = VertexIndex * {ParameterName}_MeshBoneWeightStride;
const uint BoneWeightOffset = BoneIndexOffset + (({ParameterName}_MeshNumWeights * {ParameterName}_MeshBoneIndexSizeBytes) >> 2);
int4 BlendIndices;
float4 BlendWeights;
{
GetIndexWeight_{ParameterName}(BoneIndexOffset, BoneWeightOffset, 0, BlendIndices, BlendWeights);
CurrBoneMatrix = GetCurrSkinningMatrix_{ParameterName}(SectionBoneOffset, BlendIndices, BlendWeights);
PrevBoneMatrix = GetPrevSkinningMatrix_{ParameterName}(SectionBoneOffset, BlendIndices, BlendWeights);
}
#if DISKELMESH_BONE_INFLUENCES != DISKELMESH_BONE_INFLUENCES_MAX4
// We are in 8 or unlimited mode so need to check for the extended weights
if ({ParameterName}_MeshNumWeights == 8)
{
GetIndexWeight_{ParameterName}(BoneIndexOffset, BoneWeightOffset, 1, BlendIndices, BlendWeights);
CurrBoneMatrix += GetCurrSkinningMatrix_{ParameterName}(SectionBoneOffset, BlendIndices, BlendWeights);
PrevBoneMatrix += GetPrevSkinningMatrix_{ParameterName}(SectionBoneOffset, BlendIndices, BlendWeights);
}
#endif
}
if ( bNeedsSkinPositions )
{
CurrPosition = mul(CurrBoneMatrix, float4(CurrPosition, 1.0f)).xyz;
PrevPosition = mul(PrevBoneMatrix, float4(PrevPosition, 1.0f)).xyz;
}
if ( bNeedsSkinTangents )
{
// Not using InverseTranspose of matrices so assuming uniform scaling only (same as SkinCache)
TangentX.xyz = mul(CurrBoneMatrix, float4(TangentX.xyz, 0.0f)).xyz;
TangentZ.xyz = mul(CurrBoneMatrix, float4(TangentZ.xyz, 0.0f)).xyz;
}
}
float3 TangentY = cross(TangentZ.xyz, TangentX.xyz) * TangentZ.w;
FDISkelMeshSkinnedVertex SkinnedVertex;
SkinnedVertex.Position = CurrPosition;
SkinnedVertex.PrevPosition = PrevPosition;
SkinnedVertex.TangentX = cross(TangentY, TangentZ.xyz) * TangentZ.w;
SkinnedVertex.TangentY = TangentY;
SkinnedVertex.TangentZ = TangentZ.xyz;
return SkinnedVertex;
}
FDISkelMeshSkinnedVertex GetSkinnedVertexWS_{ParameterName}(uint VertexIndex)
{
FDISkelMeshSkinnedVertex SkinnedVertex = GetSkinnedVertex_{ParameterName}(VertexIndex);
SkinnedVertex.Position = mul(float4(SkinnedVertex.Position, 1.0f), {ParameterName}_InstanceTransform).xyz;
SkinnedVertex.PrevPosition = mul(float4(SkinnedVertex.PrevPosition, 1.0f), {ParameterName}_InstancePrevTransform).xyz;
SkinnedVertex.TangentX = normalize(mul(float4(SkinnedVertex.TangentX, 0.0f), {ParameterName}_InstanceTransform).xyz);
SkinnedVertex.TangentY = normalize(mul(float4(SkinnedVertex.TangentY, 0.0f), {ParameterName}_InstanceTransform).xyz);
SkinnedVertex.TangentZ = normalize(mul(float4(SkinnedVertex.TangentZ, 0.0f), {ParameterName}_InstanceTransform).xyz);
return SkinnedVertex;
}
FDISkelMeshSkinnedVertex GetSkinnedPointOnTriangle_{ParameterName}(uint TriangleIndex, float3 BaryCoord)
{
// Early out for bad data
if ( {ParameterName}_MeshTriangleCount == 0 )
{
FDISkelMeshSkinnedVertex SkinnedVertex;
SkinnedVertex.Position = float3(0.0f, 0.0f, 0.0f);
SkinnedVertex.PrevPosition = float3(0.0f, 0.0f, 0.0f);
SkinnedVertex.TangentX = float3(1.0f, 0.0f, 0.0f);
SkinnedVertex.TangentY = float3(0.0f, 1.0f, 0.0f);
SkinnedVertex.TangentZ = float3(0.0f, 0.0f, 1.0f);
return SkinnedVertex;
}
TriangleIndex = clamp(TriangleIndex, 0, {ParameterName}_MeshTriangleCount - 1);
uint IndexBufferOffset = TriangleIndex * 3;
uint VertexIndex0 = {ParameterName}_MeshIndexBuffer[IndexBufferOffset];
uint VertexIndex1 = {ParameterName}_MeshIndexBuffer[IndexBufferOffset + 1];
uint VertexIndex2 = {ParameterName}_MeshIndexBuffer[IndexBufferOffset + 2];
FDISkelMeshSkinnedVertex SkinnedVertex0 = GetSkinnedVertex_{ParameterName}(VertexIndex0);
FDISkelMeshSkinnedVertex SkinnedVertex1 = GetSkinnedVertex_{ParameterName}(VertexIndex1);
FDISkelMeshSkinnedVertex SkinnedVertex2 = GetSkinnedVertex_{ParameterName}(VertexIndex2);
FDISkelMeshSkinnedVertex FinalVertex;
FinalVertex.Position = (SkinnedVertex0.Position * BaryCoord.x) + (SkinnedVertex1.Position * BaryCoord.y) + (SkinnedVertex2.Position * BaryCoord.z);
FinalVertex.PrevPosition = (SkinnedVertex0.PrevPosition * BaryCoord.x) + (SkinnedVertex1.PrevPosition * BaryCoord.y) + (SkinnedVertex2.PrevPosition * BaryCoord.z);
FinalVertex.TangentX = (SkinnedVertex0.TangentX * BaryCoord.x) + (SkinnedVertex1.TangentX * BaryCoord.y) + (SkinnedVertex2.TangentX * BaryCoord.z);
FinalVertex.TangentY = (SkinnedVertex0.TangentY * BaryCoord.x) + (SkinnedVertex1.TangentY * BaryCoord.y) + (SkinnedVertex2.TangentY * BaryCoord.z);
FinalVertex.TangentZ = (SkinnedVertex0.TangentZ * BaryCoord.x) + (SkinnedVertex1.TangentZ * BaryCoord.y) + (SkinnedVertex2.TangentZ * BaryCoord.z);
return FinalVertex;
}
FDISkelMeshSkinnedVertex GetSkinnedPointOnTriangleWS_{ParameterName}(uint TriangleIndex, float3 BaryCoord)
{
FDISkelMeshSkinnedVertex FinalVertex = GetSkinnedPointOnTriangle_{ParameterName}(TriangleIndex, BaryCoord);
FinalVertex.Position = mul(float4(FinalVertex.Position, 1.0f), {ParameterName}_InstanceTransform).xyz;
FinalVertex.PrevPosition = mul(float4(FinalVertex.PrevPosition, 1.0f), {ParameterName}_InstancePrevTransform).xyz;
FinalVertex.TangentX = mul(float4(FinalVertex.TangentX, 0.0f), {ParameterName}_InstanceTransform).xyz;
FinalVertex.TangentY = mul(float4(FinalVertex.TangentY, 0.0f), {ParameterName}_InstanceTransform).xyz;
FinalVertex.TangentZ = mul(float4(FinalVertex.TangentZ, 0.0f), {ParameterName}_InstanceTransform).xyz;
return FinalVertex;
}
void RandomTriCoord_{ParameterName}(uint Seed1, uint Seed2, uint Seed3, out int OutTriangle, out float3 OutBaryCoord)
{
// Early out for bad data
if ({ParameterName}_MeshTriangleCount == 0)
{
OutTriangle = -1;
OutBaryCoord = 1.0f / 3.0f;
return;
}
float RandT0 = DISKelMesh_Random(Seed1, Seed2, Seed3);
[branch]
if ( !UniformTriangleSamplingEnable_{ParameterName}() )
{
// Uniform triangle id selection
OutTriangle = min(uint(RandT0 * float({ParameterName}_MeshTriangleCount)), {ParameterName}_MeshTriangleCount - 1); // avoid % by using mul/min to Tri = MeshTriangleCountName
}
else
{
// Uniform area weighted position selection (using alias method from Alias method from FWeightedRandomSampler)
uint TriangleIndex = min(uint(RandT0*float({ParameterName}_MeshTriangleCount)), {ParameterName}_MeshTriangleCount - 1);
#if DISKELMESH_PROBALIAS_FORMAT == DISKELMESH_PROBALIAS_FORMAT_64
float TriangleProbability = asfloat({ParameterName}_MeshTriangleSamplerProbAliasBuffer[(TriangleIndex * 2) + 0]);
uint TriangleAlias = {ParameterName}_MeshTriangleSamplerProbAliasBuffer[(TriangleIndex * 2) + 1];
#elif DISKELMESH_PROBALIAS_FORMAT == DISKELMESH_PROBALIAS_FORMAT_24_8
uint TriangleProbAlias = {ParameterName}_MeshTriangleSamplerProbAliasBuffer[TriangleIndex];
float TriangleProbability = float(TriangleProbAlias & 0xff) / 255.0f;
uint TriangleAlias = TriangleProbAlias >> 8;
#elif DISKELMESH_PROBALIAS_FORMAT == DISKELMESH_PROBALIAS_FORMAT_23_9
uint TriangleProbAlias = {ParameterName}_MeshTriangleSamplerProbAliasBuffer[TriangleIndex];
float TriangleProbability = float(TriangleProbAlias & 0x1ff) / 511.0f;
uint TriangleAlias = TriangleProbAlias >> 9;
#endif
// Alias check
float RandT1 = DISKelMesh_Random(Seed1, Seed2, Seed3);
if( RandT1 > TriangleProbability )
{
TriangleIndex = TriangleAlias;
}
OutTriangle = int(TriangleIndex);
}
OutBaryCoord = DISKelMesh_RandomBarycentricCoord(Seed1, Seed2, Seed3);
}
void GetSkinnedTriangleDataWS_{ParameterName}(in uint TriangleIndex, in float3 BaryCoord, out float3 OutPosition, out float3 OutVelocity, out float3 OutNormal, out float3 OutBinormal, out float3 OutTangent)
{
FDISkelMeshSkinnedVertex SkinnedVertex = GetSkinnedPointOnTriangleWS_{ParameterName}(TriangleIndex, BaryCoord);
OutPosition = SkinnedVertex.Position;
OutVelocity = (SkinnedVertex.Position - SkinnedVertex.PrevPosition) * {ParameterName}_InstanceInvDeltaTime;
OutNormal = normalize(SkinnedVertex.TangentZ);
OutBinormal = normalize(SkinnedVertex.TangentY);
OutTangent = normalize(SkinnedVertex.TangentX);
}
void GetSkinnedTriangleData_{ParameterName}(in uint TriangleIndex, in float3 BaryCoord, out float3 OutPosition, out float3 OutVelocity, out float3 OutNormal, out float3 OutBinormal, out float3 OutTangent)
{
FDISkelMeshSkinnedVertex SkinnedVertex = GetSkinnedPointOnTriangle_{ParameterName}(TriangleIndex, BaryCoord);
OutPosition = SkinnedVertex.Position;
OutVelocity = (SkinnedVertex.Position - SkinnedVertex.PrevPosition) * {ParameterName}_InstanceInvDeltaTime;
OutNormal = normalize(SkinnedVertex.TangentZ);
OutBinormal = normalize(SkinnedVertex.TangentY);
OutTangent = normalize(SkinnedVertex.TangentX);
}
void GetSkinnedTriangleDataInterpolatedWS_{ParameterName}(in uint TriangleIndex, in float3 BaryCoord, in float Interp, out float3 OutPosition, out float3 OutVelocity, out float3 OutNormal, out float3 OutBinormal, out float3 OutTangent)
{
FDISkelMeshSkinnedVertex SkinnedVertex = GetSkinnedPointOnTriangleWS_{ParameterName}(TriangleIndex, BaryCoord);
OutPosition = lerp(SkinnedVertex.PrevPosition, SkinnedVertex.Position, Interp);
OutVelocity = (SkinnedVertex.Position - SkinnedVertex.PrevPosition) * {ParameterName}_InstanceInvDeltaTime;
OutNormal = normalize(SkinnedVertex.TangentZ);
OutBinormal = normalize(SkinnedVertex.TangentY);
OutTangent = normalize(SkinnedVertex.TangentX);
}
void GetSkinnedTriangleDataInterpolated_{ParameterName}(in uint TriangleIndex, in float3 BaryCoord, in float Interp, out float3 OutPosition, out float3 OutVelocity, out float3 OutNormal, out float3 OutBinormal, out float3 OutTangent)
{
FDISkelMeshSkinnedVertex SkinnedVertex = GetSkinnedPointOnTriangle_{ParameterName}(TriangleIndex, BaryCoord);
OutPosition = lerp(SkinnedVertex.PrevPosition, SkinnedVertex.Position, Interp);
OutVelocity = (SkinnedVertex.Position - SkinnedVertex.PrevPosition) * {ParameterName}_InstanceInvDeltaTime;
OutNormal = normalize(SkinnedVertex.TangentZ);
OutBinormal = normalize(SkinnedVertex.TangentY);
OutTangent = normalize(SkinnedVertex.TangentX);
}
void GetSkinnedTriangleVertexDataHelper_{ParameterName}(
int TriangleIndex,
float Interp,
bool bWorldSpace,
out float3 Position0, out float3 Velocity0, out float3 Normal0, out float3 Binormal0, out float3 Tangent0,
out float3 Position1, out float3 Velocity1, out float3 Normal1, out float3 Binormal1, out float3 Tangent1,
out float3 Position2, out float3 Velocity2, out float3 Normal2, out float3 Binormal2, out float3 Tangent2
)
{
int VertexIndex0 = 0;
int VertexIndex1 = 0;
int VertexIndex2 = 0;
if ( {ParameterName}_MeshTriangleCount != 0 )
{
TriangleIndex = clamp(TriangleIndex, 0, int({ParameterName}_MeshTriangleCount) - 1);
const uint IndexBufferOffset = TriangleIndex * 3;
VertexIndex0 = {ParameterName}_MeshIndexBuffer[IndexBufferOffset];
VertexIndex1 = {ParameterName}_MeshIndexBuffer[IndexBufferOffset + 1];
VertexIndex2 = {ParameterName}_MeshIndexBuffer[IndexBufferOffset + 2];
}
FDISkelMeshSkinnedVertex SkinnedVertex0;
FDISkelMeshSkinnedVertex SkinnedVertex1;
FDISkelMeshSkinnedVertex SkinnedVertex2;
BRANCH
if ( bWorldSpace )
{
SkinnedVertex0 = GetSkinnedVertexWS_{ParameterName}(VertexIndex0);
SkinnedVertex1 = GetSkinnedVertexWS_{ParameterName}(VertexIndex1);
SkinnedVertex2 = GetSkinnedVertexWS_{ParameterName}(VertexIndex2);
}
else
{
SkinnedVertex0 = GetSkinnedVertex_{ParameterName}(VertexIndex0);
SkinnedVertex1 = GetSkinnedVertex_{ParameterName}(VertexIndex1);
SkinnedVertex2 = GetSkinnedVertex_{ParameterName}(VertexIndex2);
}
Position0 = lerp(SkinnedVertex0.PrevPosition, SkinnedVertex0.Position, Interp);
Velocity0 = SkinnedVertex0.Position - SkinnedVertex0.PrevPosition;
Normal0 = SkinnedVertex0.TangentZ;
Binormal0 = SkinnedVertex0.TangentY;
Tangent0 = SkinnedVertex0.TangentX;
Position1 = lerp(SkinnedVertex1.PrevPosition, SkinnedVertex1.Position, Interp);
Velocity1 = SkinnedVertex1.Position - SkinnedVertex1.PrevPosition;
Normal1 = SkinnedVertex1.TangentZ;
Binormal1 = SkinnedVertex1.TangentY;
Tangent1 = SkinnedVertex1.TangentX;
Position2 = lerp(SkinnedVertex2.PrevPosition, SkinnedVertex2.Position, Interp);
Velocity2 = SkinnedVertex2.Position - SkinnedVertex2.PrevPosition;
Normal2 = SkinnedVertex2.TangentZ;
Binormal2 = SkinnedVertex2.TangentY;
Tangent2 = SkinnedVertex2.TangentX;
}
void GetSkinnedTriangleVertexData_{ParameterName}(
int TriangleIndex,
out float3 Position0, out float3 Velocity0, out float3 Normal0, out float3 Binormal0, out float3 Tangent0,
out float3 Position1, out float3 Velocity1, out float3 Normal1, out float3 Binormal1, out float3 Tangent1,
out float3 Position2, out float3 Velocity2, out float3 Normal2, out float3 Binormal2, out float3 Tangent2
)
{
GetSkinnedTriangleVertexDataHelper_{ParameterName}(
TriangleIndex, 1.0f, false,
Position0, Velocity0, Normal0, Binormal0, Tangent0, Position1, Velocity1, Normal1, Binormal1, Tangent1, Position2, Velocity2, Normal2, Binormal2, Tangent2
);
}
void GetSkinnedTriangleVertexDataWS_{ParameterName}(
int TriangleIndex,
out float3 Position0, out float3 Velocity0, out float3 Normal0, out float3 Binormal0, out float3 Tangent0,
out float3 Position1, out float3 Velocity1, out float3 Normal1, out float3 Binormal1, out float3 Tangent1,
out float3 Position2, out float3 Velocity2, out float3 Normal2, out float3 Binormal2, out float3 Tangent2
)
{
GetSkinnedTriangleVertexDataHelper_{ParameterName}(
TriangleIndex, 1.0f, true,
Position0, Velocity0, Normal0, Binormal0, Tangent0, Position1, Velocity1, Normal1, Binormal1, Tangent1, Position2, Velocity2, Normal2, Binormal2, Tangent2
);
}
void GetSkinnedTriangleVertexDataInterpolated_{ParameterName}(
int TriangleIndex,
float Interp,
out float3 Position0, out float3 Velocity0, out float3 Normal0, out float3 Binormal0, out float3 Tangent0,
out float3 Position1, out float3 Velocity1, out float3 Normal1, out float3 Binormal1, out float3 Tangent1,
out float3 Position2, out float3 Velocity2, out float3 Normal2, out float3 Binormal2, out float3 Tangent2
)
{
GetSkinnedTriangleVertexDataHelper_{ParameterName}(
TriangleIndex, Interp, false,
Position0, Velocity0, Normal0, Binormal0, Tangent0, Position1, Velocity1, Normal1, Binormal1, Tangent1, Position2, Velocity2, Normal2, Binormal2, Tangent2
);
}
void GetSkinnedTriangleVertexDataWSInterpolated_{ParameterName}(
int TriangleIndex,
float Interp,
out float3 Position0, out float3 Velocity0, out float3 Normal0, out float3 Binormal0, out float3 Tangent0,
out float3 Position1, out float3 Velocity1, out float3 Normal1, out float3 Binormal1, out float3 Tangent1,
out float3 Position2, out float3 Velocity2, out float3 Normal2, out float3 Binormal2, out float3 Tangent2
)
{
GetSkinnedTriangleVertexDataHelper_{ParameterName}(
TriangleIndex, Interp, true,
Position0, Velocity0, Normal0, Binormal0, Tangent0, Position1, Velocity1, Normal1, Binormal1, Tangent1, Position2, Velocity2, Normal2, Binormal2, Tangent2
);
}
void GetTriUV_{ParameterName}(in uint TriangleIndex, in float3 BaryCoord, in int UVSet, out float2 OutUV)
{
if ({ParameterName}_MeshNumTexCoord > 0)
{
uint IndexBufferOffset = TriangleIndex * 3;
uint VertexIndex0 = {ParameterName}_MeshIndexBuffer[IndexBufferOffset ];
uint VertexIndex1 = {ParameterName}_MeshIndexBuffer[IndexBufferOffset+1];
uint VertexIndex2 = {ParameterName}_MeshIndexBuffer[IndexBufferOffset+2];
uint Stride = {ParameterName}_MeshNumTexCoord;
uint SelectedUVSet = clamp((uint) UVSet, 0, {ParameterName}_MeshNumTexCoord - 1);
float2 UV0 = {ParameterName}_MeshTexCoordBuffer[VertexIndex0 * Stride + SelectedUVSet];
float2 UV1 = {ParameterName}_MeshTexCoordBuffer[VertexIndex1 * Stride + SelectedUVSet];
float2 UV2 = {ParameterName}_MeshTexCoordBuffer[VertexIndex2 * Stride + SelectedUVSet];
OutUV = UV0 * BaryCoord.x + UV1 * BaryCoord.y + UV2 * BaryCoord.z;
}
else
{
OutUV = 0.0f;
}
}
void RandomTriangle_{ParameterName}(uint Seed1, uint Seed2, uint Seed3, out int OutTriangle, out float3 OutBaryCoord)
{
float RandT0 = DISKelMesh_Random(Seed1, Seed2, Seed3);
int TriangleIndex = min(int(RandT0 * float({ParameterName}_MeshTriangleCount)), (int){ParameterName}_MeshTriangleCount - 1); // avoid % by using mul/min to Tri = MeshTriangleCountName
[branch]
if ( UniformTriangleSamplingEnable_{ParameterName}() )
{
// Uniform area weighted position selection (using alias method from Alias method from FWeightedRandomSampler)
#if DISKELMESH_PROBALIAS_FORMAT == DISKELMESH_PROBALIAS_FORMAT_64
float TriangleProbability = asfloat({ParameterName}_MeshTriangleSamplerProbAliasBuffer[(TriangleIndex * 2) + 0]);
uint TriangleAlias = {ParameterName}_MeshTriangleSamplerProbAliasBuffer[(TriangleIndex * 2) + 1];
#elif DISKELMESH_PROBALIAS_FORMAT == DISKELMESH_PROBALIAS_FORMAT_24_8
uint TriangleProbAlias = {ParameterName}_MeshTriangleSamplerProbAliasBuffer[TriangleIndex];
float TriangleProbability = float(TriangleProbAlias & 0xff) / 255.0f;
uint TriangleAlias = TriangleProbAlias >> 8;
#elif DISKELMESH_PROBALIAS_FORMAT == DISKELMESH_PROBALIAS_FORMAT_23_9
uint TriangleProbAlias = {ParameterName}_MeshTriangleSamplerProbAliasBuffer[TriangleIndex];
float TriangleProbability = float(TriangleProbAlias & 0x1ff) / 511.0f;
uint TriangleAlias = TriangleProbAlias >> 9;
#endif
// Alias check
float RandT1 = DISKelMesh_Random(Seed1, Seed2, Seed3);
if( RandT1 > TriangleProbability )
{
TriangleIndex = int(TriangleAlias);
}
}
OutTriangle = TriangleIndex;
OutBaryCoord = DISKelMesh_RandomBarycentricCoord(Seed1, Seed2, Seed3);
}
void GetTriangleCount_{ParameterName}(out int OutCount)
{
OutCount = {ParameterName}_MeshTriangleCount;
}
void RandomFilteredTriangle_{ParameterName}(uint Seed1, uint Seed2, uint Seed3, out int OutTriangle, out float3 OutBaryCoord)
{
// Early out for bad data
if ({ParameterName}_MeshNumSamplingRegionTriangles == 0)
{
OutTriangle = -1;
OutBaryCoord = 1.0f / 3.0f;
return;
}
float RandT0 = DISKelMesh_Random(Seed1, Seed2, Seed3);
uint RegionTriangle = min(uint(RandT0 * float({ParameterName}_MeshNumSamplingRegionTriangles)), {ParameterName}_MeshNumSamplingRegionTriangles - 1); // avoid % by using mul/min to Tri = MeshTriangleCountName
[branch]
if ( UniformSamplingRegionEnabled_{ParameterName}() )
{
#if DISKELMESH_PROBALIAS_FORMAT == DISKELMESH_PROBALIAS_FORMAT_64
float TriangleProbability = asfloat({ParameterName}_MeshSamplingRegionsProbAliasBuffer[(RegionTriangle * 2) + 0]);
uint TriangleAlias = {ParameterName}_MeshSamplingRegionsProbAliasBuffer[(RegionTriangle * 2) + 1];
#elif DISKELMESH_PROBALIAS_FORMAT == DISKELMESH_PROBALIAS_FORMAT_24_8
uint TriangleProbAlias = {ParameterName}_MeshSamplingRegionsProbAliasBuffer[RegionTriangle];
float TriangleProbability = float(TriangleProbAlias & 0xff) / 255.0f;
uint TriangleAlias = TriangleProbAlias >> 8;
#elif DISKELMESH_PROBALIAS_FORMAT == DISKELMESH_PROBALIAS_FORMAT_23_9
uint TriangleProbAlias = {ParameterName}_MeshSamplingRegionsProbAliasBuffer[RegionTriangle];
float TriangleProbability = float(TriangleProbAlias & 0x1ff) / 511.0f;
uint TriangleAlias = TriangleProbAlias >> 9;
#endif
float RandT1 = DISKelMesh_Random(Seed1, Seed2, Seed3);
if ( RandT1 > TriangleProbability )
{
RegionTriangle = TriangleAlias;
}
}
OutTriangle = (int){ParameterName}_MeshSampleRegionsTriangleIndices[RegionTriangle];
OutBaryCoord = DISKelMesh_RandomBarycentricCoord(Seed1, Seed2, Seed3);
}
void GetFilteredTriangleCount_{ParameterName}(out int OutCount)
{
OutCount = {ParameterName}_MeshNumSamplingRegionTriangles;
}
void GetFilteredTriangleAt_{ParameterName}(int FilteredIndex, out int OutTriangle)
{
if ( {ParameterName}_MeshNumSamplingRegionTriangles > 0 )
{
FilteredIndex = clamp(FilteredIndex, 0, (int){ParameterName}_MeshNumSamplingRegionTriangles - 1);
OutTriangle = (int){ParameterName}_MeshSampleRegionsTriangleIndices[FilteredIndex];
}
else
{
OutTriangle = 0;
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Uv Mapping
void GetTriangleCoordAtUV_{ParameterName}(bool Enabled, float2 InUv, float InTolerance, out int OutTriangle, out float3 OutBaryCoord, out bool OutIsValid)
{
UvMappingParameters MappingParam;
MappingParam.NumUVs = {ParameterName}_MeshNumTexCoord;
MappingParam.IndexBuffer = {ParameterName}_MeshIndexBuffer;
MappingParam.UVBuffer = {ParameterName}_MeshTexCoordBuffer;
MappingParam.UvMappingBuffer = {ParameterName}_UvMappingBuffer;
MappingParam.UvMappingBufferLength = {ParameterName}_UvMappingBufferLength;
MappingParam.UvMappingSet = {ParameterName}_UvMappingSet;
UvMapping_GetTriangleCoordAtUV(MappingParam, Enabled, InUv, InTolerance, OutTriangle, OutBaryCoord, OutIsValid);
}
void GetTriangleCoordInAabb_{ParameterName}(bool Enabled, float2 InUvMin, float2 InUvMax, out int OutTriangle, out float3 OutBaryCoord, out bool OutIsValid)
{
UvMappingParameters MappingParam;
MappingParam.NumUVs = {ParameterName}_MeshNumTexCoord;
MappingParam.IndexBuffer = {ParameterName}_MeshIndexBuffer;
MappingParam.UVBuffer = {ParameterName}_MeshTexCoordBuffer;
MappingParam.UvMappingBuffer = {ParameterName}_UvMappingBuffer;
MappingParam.UvMappingBufferLength = {ParameterName}_UvMappingBufferLength;
MappingParam.UvMappingSet = {ParameterName}_UvMappingSet;
UvMapping_GetTriangleCoordInAabb(MappingParam, Enabled, InUvMin, InUvMax, OutTriangle, OutBaryCoord, OutIsValid);
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Bone Sampling
void GetSkinnedBoneCommon_{ParameterName}(in int Bone, in float Interp, in bool bWorldSpace, out float3 OutPosition, out float4 OutRotation, out float3 OutScale, out float3 OutVelocity)
{
// Early out for bad data
if ( {ParameterName}_NumBones + {ParameterName}_NumFilteredSockets == 0 )
{
OutPosition = float3(0.0f, 0.0f, 0.0f);
OutRotation = float4(0.0f, 0.0f, 0.0f, 1.0f);
OutScale = float3(0.0f, 0.0f, 0.0f);
OutVelocity = float3(0.0f, 0.0f, 0.0f);
return;
}
Bone = clamp(Bone, 0, {ParameterName}_NumBones + {ParameterName}_NumFilteredSockets - 1);
float3 PrevPosition = {ParameterName}_MeshPrevSamplingBonesBuffer[Bone * 3].xyz;
float4 PrevRotation = {ParameterName}_MeshPrevSamplingBonesBuffer[Bone * 3 + 1];
float3 PrevScale = {ParameterName}_MeshPrevSamplingBonesBuffer[Bone * 3 + 2].xyz;
float3 CurrPosition = {ParameterName}_MeshCurrSamplingBonesBuffer[Bone * 3].xyz;
float4 CurrRotation = {ParameterName}_MeshCurrSamplingBonesBuffer[Bone * 3 + 1];
float3 CurrScale = {ParameterName}_MeshCurrSamplingBonesBuffer[Bone * 3 + 2].xyz;
if (bWorldSpace)
{
PrevPosition = mul(float4(PrevPosition, 1), {ParameterName}_InstancePrevTransform).xyz;
CurrPosition = mul(float4(CurrPosition, 1), {ParameterName}_InstanceTransform).xyz;
PrevRotation = NiagaraGPU_QuatMul({ParameterName}_InstancePrevRotation, PrevRotation);
CurrRotation = NiagaraGPU_QuatMul({ParameterName}_InstanceRotation, CurrRotation);
PrevScale = mul(PrevScale, (float3x3){ParameterName}_InstancePrevTransform);
CurrScale = mul(CurrScale, (float3x3){ParameterName}_InstanceTransform);
}
CurrPosition = lerp(PrevPosition, CurrPosition, Interp);
CurrScale = lerp(PrevScale, CurrScale, Interp);
OutPosition = CurrPosition;
OutRotation = DISKelMesh_QuatSlerp(PrevRotation, CurrRotation, Interp);
OutScale = CurrScale;
OutVelocity = (CurrPosition - PrevPosition) * {ParameterName}_InstanceInvDeltaTime;
}
void GetSkinnedBoneData_{ParameterName}(in int Bone, out float3 OutPosition, out float4 OutRotation, out float3 OutScale, out float3 OutVelocity)
{
GetSkinnedBoneCommon_{ParameterName}(Bone, 1.0f, false, OutPosition, OutRotation, OutScale, OutVelocity);
}
void GetSkinnedBoneDataInterpolated_{ParameterName}(in int Bone, in float Interp, out float3 OutPosition, out float4 OutRotation, out float3 OutScale, out float3 OutVelocity)
{
GetSkinnedBoneCommon_{ParameterName}(Bone, Interp, false, OutPosition, OutRotation, OutScale, OutVelocity);
}
void GetSkinnedBoneDataWS_{ParameterName}(in int Bone, out float3 OutPosition, out float4 OutRotation, out float3 OutScale, out float3 OutVelocity)
{
GetSkinnedBoneCommon_{ParameterName}(Bone, 1.0f, true, OutPosition, OutRotation, OutScale, OutVelocity);
}
void GetSkinnedBoneDataWSInterpolated_{ParameterName}(in int Bone, in float Interp, out float3 OutPosition, out float4 OutRotation, out float3 OutScale, out float3 OutVelocity)
{
GetSkinnedBoneCommon_{ParameterName}(Bone, Interp, true, OutPosition, OutRotation, OutScale, OutVelocity);
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Vertex Sampling
void GetTriVertices_{ParameterName}(in uint TriangleIndex, out int VertexIndex0, out int VertexIndex1, out int VertexIndex2)
{
// Early out for bad data
if ( {ParameterName}_MeshTriangleCount == 0 )
{
VertexIndex0 = 0;
VertexIndex1 = 0;
VertexIndex2 = 0;
return;
}
TriangleIndex = clamp(TriangleIndex, 0, {ParameterName}_MeshTriangleCount - 1);
uint IndexBufferOffset = TriangleIndex * 3;
VertexIndex0 = {ParameterName}_MeshIndexBuffer[IndexBufferOffset];
VertexIndex1 = {ParameterName}_MeshIndexBuffer[IndexBufferOffset + 1];
VertexIndex2 = {ParameterName}_MeshIndexBuffer[IndexBufferOffset + 2];
}
void GetTriCoordVertices_{ParameterName}(in int TriangleIndex, out int VertexIndex0, out int VertexIndex1, out int VertexIndex2)
{
GetTriVertices_{ParameterName}(TriangleIndex, VertexIndex0, VertexIndex1, VertexIndex2);
}
void GetTriangleIndices_{ParameterName}(int Tri, out int Index0, out int Index1, out int Index2)
{
GetTriVertices_{ParameterName}(Tri, Index0, Index1, Index2);
}
void GetTriColor_{ParameterName}(in uint TriangleIndex, in float3 BaryCoord, out float4 OutColor)
{
// Early out for bad data
if ( HasMeshColors_{ParameterName}() == false )
{
OutColor = float4(1, 1, 1, 1);
return;
}
TriangleIndex = clamp(TriangleIndex, 0, {ParameterName}_MeshTriangleCount - 1);
uint IndexBufferOffset = TriangleIndex * 3;
uint VertexIndex0 = {ParameterName}_MeshIndexBuffer[IndexBufferOffset];
uint VertexIndex1 = {ParameterName}_MeshIndexBuffer[IndexBufferOffset + 1];
uint VertexIndex2 = {ParameterName}_MeshIndexBuffer[IndexBufferOffset + 2];
OutColor = ({ParameterName}_MeshColorBuffer[VertexIndex0] FMANUALFETCH_COLOR_COMPONENT_SWIZZLE * BaryCoord.x) + ({ParameterName}_MeshColorBuffer[VertexIndex1] FMANUALFETCH_COLOR_COMPONENT_SWIZZLE * BaryCoord.y) + ({ParameterName}_MeshColorBuffer[VertexIndex2] FMANUALFETCH_COLOR_COMPONENT_SWIZZLE * BaryCoord.z);
}
void GetSkinnedVertexData_{ParameterName}(in int VertexIndex, out float3 OutPosition, out float3 OutVelocity, out float3 OutNormal, out float3 OutBinormal, out float3 OutTangent)
{
FDISkelMeshSkinnedVertex SkinnedVertex = GetSkinnedVertex_{ParameterName}(VertexIndex);
OutPosition = SkinnedVertex.Position;
OutVelocity = (SkinnedVertex.Position - SkinnedVertex.PrevPosition) * {ParameterName}_InstanceInvDeltaTime;
OutNormal = SkinnedVertex.TangentZ;
OutBinormal = SkinnedVertex.TangentY;
OutTangent = SkinnedVertex.TangentX;
}
void GetSkinnedVertexDataWS_{ParameterName}(in int VertexIndex, out float3 OutPosition, out float3 OutVelocity, out float3 OutNormal, out float3 OutBinormal, out float3 OutTangent)
{
FDISkelMeshSkinnedVertex SkinnedVertex = GetSkinnedVertex_{ParameterName}(VertexIndex);
OutPosition = mul(float4(SkinnedVertex.Position, 1.0f), {ParameterName}_InstanceTransform).xyz;
float3 PrevPosition = mul(float4(SkinnedVertex.PrevPosition, 1.0f), {ParameterName}_InstancePrevTransform).xyz;
OutVelocity = (SkinnedVertex.Position - SkinnedVertex.PrevPosition) * {ParameterName}_InstanceInvDeltaTime;
OutNormal = normalize(mul(float4(SkinnedVertex.TangentZ, 0.0f), {ParameterName}_InstanceTransform).xyz);
OutBinormal = normalize(mul(float4(SkinnedVertex.TangentY, 0.0f), {ParameterName}_InstanceTransform).xyz);
OutTangent = normalize(mul(float4(SkinnedVertex.TangentX, 0.0f), {ParameterName}_InstanceTransform).xyz);
}
void GetSkinnedVertexDataInterpolated_{ParameterName}(in int VertexIndex, in float Interp, out float3 OutPosition, out float3 OutVelocity, out float3 OutNormal, out float3 OutBinormal, out float3 OutTangent)
{
FDISkelMeshSkinnedVertex SkinnedVertex = GetSkinnedVertex_{ParameterName}(VertexIndex);
OutPosition = lerp(SkinnedVertex.PrevPosition, SkinnedVertex.Position, Interp);
OutVelocity = (SkinnedVertex.Position - SkinnedVertex.PrevPosition) * {ParameterName}_InstanceInvDeltaTime;
OutNormal = SkinnedVertex.TangentZ;
OutBinormal = SkinnedVertex.TangentY;
OutTangent = SkinnedVertex.TangentX;
}
void GetSkinnedVertexDataInterpolatedWS_{ParameterName}(in int VertexIndex, in float Interp, out float3 OutPosition, out float3 OutVelocity, out float3 OutNormal, out float3 OutBinormal, out float3 OutTangent)
{
FDISkelMeshSkinnedVertex SkinnedVertex = GetSkinnedVertex_{ParameterName}(VertexIndex);
OutPosition = mul(float4(SkinnedVertex.Position, 1.0f), {ParameterName}_InstanceTransform).xyz;
const float3 PrevPosition = mul(float4(SkinnedVertex.PrevPosition, 1.0f), {ParameterName}_InstancePrevTransform).xyz;
OutPosition = lerp(OutPosition, PrevPosition, Interp);
OutVelocity = (SkinnedVertex.Position - SkinnedVertex.PrevPosition) * {ParameterName}_InstanceInvDeltaTime;
OutNormal = normalize(mul(float4(SkinnedVertex.TangentZ, 0.0f), {ParameterName}_InstanceTransform).xyz);
OutBinormal = normalize(mul(float4(SkinnedVertex.TangentY, 0.0f), {ParameterName}_InstanceTransform).xyz);
OutTangent = normalize(mul(float4(SkinnedVertex.TangentX, 0.0f), {ParameterName}_InstanceTransform).xyz);
}
void GetVertexColor_{ParameterName}(in int VertexIndex, out float4 OutColor)
{
OutColor = HasMeshColors_{ParameterName}() ? {ParameterName}_MeshColorBuffer[VertexIndex] FMANUALFETCH_COLOR_COMPONENT_SWIZZLE : float4(1, 1, 1, 1);
}
void GetVertexUV_{ParameterName}(in int VertexIndex, in int UVSet, out float2 OutUV)
{
if ({ParameterName}_MeshNumTexCoord > 0)
{
uint Stride = {ParameterName}_MeshNumTexCoord;
uint SelectedUVSet = clamp((uint) UVSet, 0, {ParameterName}_MeshNumTexCoord - 1);
OutUV = {ParameterName}_MeshTexCoordBuffer[VertexIndex * Stride + SelectedUVSet];
}
else
{
OutUV = 0.0f;
}
}
void IsValidVertex_{ParameterName}(int Vertex, out bool IsValid)
{
IsValid = Vertex < (int){ParameterName}_MeshVertexCount;
}
void RandomVertex_{ParameterName}(NiagaraRandInfo RandInfo, out int OutVertex)
{
float RandT0 = NiagaraRandomFloat(RandInfo);
OutVertex = (int)min(uint(RandT0 * float({ParameterName}_MeshVertexCount)), {ParameterName}_MeshVertexCount - 1); // avoid % by using mul/min to Tri = MeshVertexCount
}
void GetVertexCount_{ParameterName}(out int VertexCount)
{
VertexCount = (int){ParameterName}_MeshVertexCount;
}
void IsValidFilteredVertex_{ParameterName}(int FilteredIndex, out bool IsValid)
{
IsValid = FilteredIndex < (int){ParameterName}_MeshNumSamplingRegionVertices;
}
void RandomFilteredVertex_{ParameterName}(NiagaraRandInfo RandInfo, out int OutVertex)
{
// Early out for bad data
if ( {ParameterName}_MeshNumSamplingRegionVertices == 0 )
{
OutVertex = -1;
return;
}
float RandT0 = NiagaraRandomFloat(RandInfo);
int FilteredIndex = (int)min(uint(RandT0 * float({ParameterName}_MeshNumSamplingRegionVertices)), {ParameterName}_MeshNumSamplingRegionVertices - 1); // avoid % by using mul/min to Tri = MeshVertexCount
OutVertex = (int){ParameterName}_MeshSampleRegionsVertices[FilteredIndex];
}
void GetFilteredVertexCount_{ParameterName}(out int VertexCount)
{
VertexCount = (int){ParameterName}_MeshNumSamplingRegionVertices;
}
void GetFilteredVertex_{ParameterName}(int FilteredIndex, out int VertexIndex)
{
// Early out for bad data
if ( {ParameterName}_MeshNumSamplingRegionVertices == 0 )
{
VertexIndex = -1;
return;
}
FilteredIndex = clamp(FilteredIndex, 0, (int){ParameterName}_MeshNumSamplingRegionVertices - 1);
VertexIndex = (int){ParameterName}_MeshSampleRegionsVertices[FilteredIndex];
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Filtered Bones / Sockets
void IsValidBone_{ParameterName}(in int BoneIndex, out bool IsValid)
{
IsValid = BoneIndex >= 0 && BoneIndex < {ParameterName}_NumBones;
}
void RandomBone_{ParameterName}(NiagaraRandInfo RandInfo, out int Bone)
{
float RandT0 = NiagaraRandomFloat(RandInfo);
Bone = min(int(RandT0 * float({ParameterName}_RandomMaxBone)), {ParameterName}_RandomMaxBone);
Bone = Bone != {ParameterName}_ExcludeBoneIndex ? Bone : Bone + 1;
}
void GetBoneCount_{ParameterName}(out int Count)
{
Count = {ParameterName}_NumBones;
}
void GetParentBone_{ParameterName}(int BoneIndex, out int ParentIndex)
{
ParentIndex = -1;
if ( BoneIndex >= 0 && BoneIndex < {ParameterName}_NumBones )
{
ParentIndex = asint({ParameterName}_MeshCurrSamplingBonesBuffer[BoneIndex * 3 + 2].w);
}
}
void GetFilteredBoneCount_{ParameterName}(out int Count)
{
Count = {ParameterName}_NumFilteredBones;
}
void GetFilteredBone_{ParameterName}(in int InBoneIndex, out int Bone)
{
int BoneIndex = min(InBoneIndex, {ParameterName}_NumFilteredBones - 1);
Bone = {ParameterName}_NumFilteredBones > 0 ? (int){ParameterName}_FilteredAndUnfilteredBones[BoneIndex] : -1;
}
void RandomFilteredBone_{ParameterName}(NiagaraRandInfo RandInfo, out int Bone)
{
float RandT0 = NiagaraRandomFloat(RandInfo);
int FilteredBone = min(int(RandT0 * float({ParameterName}_NumFilteredBones)), {ParameterName}_NumFilteredBones - 1); // avoid % by using mul/min to Tri = MeshVertexCount
Bone = {ParameterName}_NumFilteredBones > 0 ? (int){ParameterName}_FilteredAndUnfilteredBones[FilteredBone] : -1;
}
void GetUnfilteredBoneCount_{ParameterName}(out int Count)
{
Count = {ParameterName}_NumUnfilteredBones;
}
void GetUnfilteredBone_{ParameterName}(in int InBoneIndex, out int Bone)
{
int BoneIndex = min(InBoneIndex, {ParameterName}_NumUnfilteredBones - 1);
Bone = {ParameterName}_NumFilteredBones > 0 ? (int){ParameterName}_FilteredAndUnfilteredBones[BoneIndex + {ParameterName}_NumFilteredBones] : BoneIndex;
}
void RandomUnfilteredBone_{ParameterName}(NiagaraRandInfo RandInfo, out int Bone)
{
float RandT0 = NiagaraRandomFloat(RandInfo);
if ( {ParameterName}_NumFilteredBones == 0 )
{
Bone = min(int(RandT0 * float({ParameterName}_RandomMaxBone)), {ParameterName}_RandomMaxBone);
Bone = Bone != {ParameterName}_ExcludeBoneIndex ? Bone : Bone + 1;
}
else
{
int UnfilteredBone = min(int(RandT0 * float({ParameterName}_NumUnfilteredBones)), {ParameterName}_NumUnfilteredBones - 1); // avoid % by using mul/min to Tri = MeshVertexCount
Bone = {ParameterName}_NumFilteredBones > 0 ? (int){ParameterName}_FilteredAndUnfilteredBones[UnfilteredBone + {ParameterName}_NumFilteredBones] : UnfilteredBone;
}
}
void GetFilteredSocketCount_{ParameterName}(out int Count)
{
Count = {ParameterName}_NumFilteredSockets;
}
void GetFilteredSocketTransform_{ParameterName}(in int SocketIndex, in bool bApplyTransform, out float3 OutTranslation, out float4 OutRotation, out float3 OutScale)
{
if ( {ParameterName}_NumFilteredSockets > 0 )
{
SocketIndex = clamp(SocketIndex, 0, {ParameterName}_NumFilteredSockets - 1);
int BufferOffset = ({ParameterName}_FilteredSocketBoneOffset + SocketIndex) * 3;
OutTranslation = {ParameterName}_MeshCurrSamplingBonesBuffer[BufferOffset + 0].xyz;
OutRotation = {ParameterName}_MeshCurrSamplingBonesBuffer[BufferOffset + 1];
OutScale = {ParameterName}_MeshCurrSamplingBonesBuffer[BufferOffset + 2].xyz;
if (bApplyTransform)
{
OutTranslation = mul(float4(OutTranslation, 1), {ParameterName}_InstanceTransform).xyz;
OutRotation = NiagaraGPU_QuatMul({ParameterName}_InstanceRotation, OutRotation);
OutScale = mul(OutScale, (float3x3){ParameterName}_InstanceTransform);
}
}
else
{
OutTranslation = float3(0.0f, 0.0f, 0.0f);
OutRotation = float4(0.0f, 0.0f, 0.0f, 1.0f);
OutScale = float3(0.0f, 0.0f, 0.0f);
}
}
void GetFilteredSocket_{ParameterName}(in int InSocketIndex, out int Bone)
{
Bone = {ParameterName}_FilteredSocketBoneOffset + clamp(InSocketIndex, 0, {ParameterName}_NumFilteredSockets - 1);
}
void RandomFilteredSocket_{ParameterName}(NiagaraRandInfo RandInfo, out int SocketBone)
{
float RandT0 = NiagaraRandomFloat(RandInfo);
SocketBone = {ParameterName}_FilteredSocketBoneOffset + min(int(RandT0 * float({ParameterName}_NumFilteredSockets)), {ParameterName}_NumFilteredSockets - 1); // avoid % by using mul/min to Tri = MeshVertexCount
}
void RandomFilteredSocketOrBone_{ParameterName}(NiagaraRandInfo RandInfo, out int Bone)
{
float RandT0 = NiagaraRandomFloat(RandInfo);
int NumFilteredSocketsAndBones = {ParameterName}_NumFilteredBones + {ParameterName}_NumFilteredSockets;
int FilteredIndex = min(int(RandT0 * float(NumFilteredSocketsAndBones)), NumFilteredSocketsAndBones - 1);
if ( FilteredIndex < {ParameterName}_NumFilteredBones )
{
Bone = (int){ParameterName}_FilteredAndUnfilteredBones[FilteredIndex];
}
else
{
Bone = {ParameterName}_FilteredSocketBoneOffset + FilteredIndex - {ParameterName}_NumFilteredBones;
}
}
void GetFilteredSocketOrBoneCount_{ParameterName}(out int Count)
{
Count = {ParameterName}_NumFilteredBones + {ParameterName}_NumFilteredSockets;
}
void GetFilteredSocketOrBone_{ParameterName}(int FilteredIndex, out int Bone)
{
int NumFilteredSocketsAndBones = {ParameterName}_NumFilteredBones + {ParameterName}_NumFilteredSockets;
FilteredIndex = clamp(FilteredIndex, 0, NumFilteredSocketsAndBones - 1);
if ( FilteredIndex < {ParameterName}_NumFilteredBones )
{
Bone = (int){ParameterName}_FilteredAndUnfilteredBones[FilteredIndex];
}
else
{
Bone = {ParameterName}_FilteredSocketBoneOffset + FilteredIndex - {ParameterName}_NumFilteredBones;
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Connectivity
void GetAdjacentTriangleIndex_{ParameterName}(int VertexId, uint AdjacencyIndex, out int TriangleIndex)
{
TriangleIndex = -1;
if (AdjacencyIndex < {ParameterName}_ConnectivityMaxAdjacentPerVertex)
{
#if DISKELMESH_ADJ_INDEX_FORMAT == DISKELMESH_ADJ_INDEX_FORMAT_FULL
const uint ReadIndex = (VertexId * {ParameterName}_ConnectivityMaxAdjacentPerVertex + AdjacencyIndex);
if (ReadIndex < {ParameterName}_ConnectivityBufferLength)
{
TriangleIndex = {ParameterName}_ConnectivityBuffer[ReadIndex];
}
#elif DISKELMESH_ADJ_INDEX_FORMAT == DISKELMESH_ADJ_INDEX_FORMAT_HALF
const uint ReadIndex = ((VertexId * {ParameterName}_ConnectivityMaxAdjacentPerVertex + AdjacencyIndex) & ~0x1) >> 1;
if (ReadIndex < {ParameterName}_ConnectivityBufferLength)
{
uint PackedIndices = {ParameterName}_ConnectivityBuffer[ReadIndex];
uint UnpackedIndex = uint2(PackedIndices & 0xFFFF, PackedIndices >> 16)[AdjacencyIndex & 1];
TriangleIndex = UnpackedIndex == 0xFFFF ? -1 : int(UnpackedIndex);
}
#else
#error Unsupported index format for adjacency information
#endif
}
}
bool IsAdjacent_{ParameterName}(int VertexIndex, int TriangleIndex)
{
for (uint AdjIt = 0; AdjIt < {ParameterName}_ConnectivityMaxAdjacentPerVertex; ++AdjIt)
{
int AdjTriangleIndex = -1;
GetAdjacentTriangleIndex_{ParameterName}(VertexIndex, AdjIt, AdjTriangleIndex);
if (AdjTriangleIndex == -1)
{
break;
}
if (AdjTriangleIndex == TriangleIndex)
{
return true;
}
}
return false;
}
void GetTriangleNeighbor_{ParameterName}(int TriangleIndex, int EdgeIndex, out int NeighborTriangleIndex, out int NeighborEdgeIndex, out bool IsValid)
{
NeighborTriangleIndex = -1;
NeighborEdgeIndex = -1;
int3 SourceVertexIndices;
GetTriVertices_{ParameterName}(TriangleIndex, SourceVertexIndices.x, SourceVertexIndices.y, SourceVertexIndices.z);
int StartSourceIndex = SourceVertexIndices[(EdgeIndex + 1) % 3];
int EndSourceIndex = SourceVertexIndices[(EdgeIndex + 2) % 3];
for (uint SourceAdjIt = 0; SourceAdjIt < {ParameterName}_ConnectivityMaxAdjacentPerVertex; ++SourceAdjIt)
{
int SourceAdjTriangleIndex = -1;
GetAdjacentTriangleIndex_{ParameterName}(StartSourceIndex, SourceAdjIt, SourceAdjTriangleIndex);
if (SourceAdjTriangleIndex == TriangleIndex) // ignore self
{
continue;
}
if (SourceAdjTriangleIndex == -1) // stop looking
{
break;
}
if (IsAdjacent_{ParameterName}(EndSourceIndex, SourceAdjTriangleIndex))
{
NeighborTriangleIndex = SourceAdjTriangleIndex;
// now to find the edge index for the neighbor
int3 NeighborVertexIndices;
GetTriVertices_{ParameterName}(NeighborTriangleIndex, NeighborVertexIndices.x, NeighborVertexIndices.y, NeighborVertexIndices.z);
bool3 NeighborVertMatches = bool3(
IsAdjacent_{ParameterName}(NeighborVertexIndices.x, TriangleIndex),
IsAdjacent_{ParameterName}(NeighborVertexIndices.y, TriangleIndex),
IsAdjacent_{ParameterName}(NeighborVertexIndices.z, TriangleIndex));
if (all(NeighborVertMatches.xy))
{
NeighborEdgeIndex = 2;
}
else if (all(NeighborVertMatches.yz))
{
NeighborEdgeIndex = 0;
}
else if (all(NeighborVertMatches.zx))
{
NeighborEdgeIndex = 1;
}
break;
}
}
IsValid = NeighborTriangleIndex != -1;
}
void GetAdjacentTriangleIndex_{ParameterName}(in int VertexId, in int AdjacencyIndex, out int TriangleIndex, out bool IsValid)
{
GetAdjacentTriangleIndex_{ParameterName}(VertexId, max(0, AdjacencyIndex), TriangleIndex);
IsValid = TriangleIndex != -1;
}