714 lines
21 KiB
HLSL

// Required for the correct use of cross platform abstractions.
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl"
//Helper to disable bounding box compute code
#define USE_DYNAMIC_AABB 1
// Special semantics for VFX blocks
#define RAND Rand(seed)
#define RAND2 float2(RAND,RAND)
#define RAND3 float3(RAND,RAND,RAND)
#define RAND4 float4(RAND,RAND,RAND,RAND)
#define FIXED_RAND(h) FixedRand(particleId ^ asuint(systemSeed) ^ h)
#define FIXED_RAND2(h) float2(FIXED_RAND(h),FIXED_RAND(h))
#define FIXED_RAND3(h) float3(FIXED_RAND(h),FIXED_RAND(h),FIXED_RAND(h))
#define FIXED_RAND4(h) float4(FIXED_RAND(h),FIXED_RAND(h),FIXED_RAND(h),FIXED_RAND(h))
#define KILL {kill = true;}
#define SAMPLE sampleSignal
#define SAMPLE_SPLINE_POSITION(v,u) sampleSpline(v.x,u)
#define SAMPLE_SPLINE_TANGENT(v,u) sampleSpline(v.y,u)
#define INVERSE(m) Inv##m
#define VFX_FLT_MIN 1.175494351e-38
#define VFX_EPSILON 1e-5
#pragma warning(disable : 3557) // disable warning for auto unrolling of single iteration loop
// Pi variables are redefined here as UnityCG.cginc, this include isn't mandatory anymore.
#ifndef UNITY_CG_INCLUDED
#define UNITY_PI 3.14159265359f
#define UNITY_TWO_PI 6.28318530718f
#define UNITY_FOUR_PI 12.56637061436f
#define UNITY_INV_PI 0.31830988618f
#define UNITY_INV_TWO_PI 0.15915494309f
#define UNITY_INV_FOUR_PI 0.07957747155f
#define UNITY_HALF_PI 1.57079632679f
#define UNITY_INV_HALF_PI 0.636619772367f
#endif
// SHADER_AVAILABLE_XXX defines are not yet passed to compute shader atm
// So we define it manually for compute atm.
// It won't compile for devices that don't have cubemap array support but this is acceptable by now
// TODO Remove this once SHADER_AVAILABLE_XXX are passed to compute shaders
#ifdef SHADER_STAGE_COMPUTE
#define SHADER_AVAILABLE_CUBEARRAY 1
#endif
struct VFXSampler2D
{
Texture2D t;
SamplerState s;
};
struct VFXSampler2DArray
{
Texture2DArray t;
SamplerState s;
};
struct VFXSampler3D
{
Texture3D t;
SamplerState s;
};
struct VFXSamplerCube
{
TextureCube t;
SamplerState s;
};
#if SHADER_AVAILABLE_CUBEARRAY
struct VFXSamplerCubeArray
{
TextureCubeArray t;
SamplerState s;
};
#endif
#if !VFX_WORLD_SPACE && !VFX_LOCAL_SPACE
#error VFXCommon.hlsl should be included after space defines
#endif
#if VFX_WORLD_SPACE && VFX_LOCAL_SPACE
#error VFX_WORLD_SPACE & VFX_LOCAL_SPACE are both enabled
#endif
#ifdef VFX_WORLD_SPACE
float3 TransformDirectionVFXToWorld(float3 dir) { return dir; }
float3 TransformPositionVFXToWorld(float3 pos) { return pos; }
float3 TransformNormalVFXToWorld(float3 n) { return n; }
float3 TransformPositionVFXToView(float3 pos) { return VFXTransformPositionWorldToView(pos); }
float4 TransformPositionVFXToClip(float3 pos) { return VFXTransformPositionWorldToClip(pos); }
float4 TransformPositionVFXToPreviousClip(float3 pos) { return VFXTransformPositionWorldToPreviousClip(pos); }
float4 TransformPositionVFXToNonJitteredClip(float3 pos) { return VFXTransformPositionWorldToNonJitteredClip(pos); }
float3x3 GetVFXToViewRotMatrix() { return VFXGetWorldToViewRotMatrix(); }
float3 GetViewVFXPosition() { return VFXGetViewWorldPosition(); }
#else
float3 TransformDirectionVFXToWorld(float3 dir) { return mul(VFXGetObjectToWorldMatrix(), float4(dir, 0.0f)).xyz; }
float3 TransformPositionVFXToWorld(float3 pos) { return mul(VFXGetObjectToWorldMatrix(), float4(pos, 1.0f)).xyz; }
float3 TransformNormalVFXToWorld(float3 n) { return mul(n, (float3x3)VFXGetWorldToObjectMatrix()); }
float3 TransformPositionVFXToView(float3 pos) { return VFXTransformPositionWorldToView(mul(VFXGetObjectToWorldMatrix(), float4(pos, 1.0f)).xyz); }
float4 TransformPositionVFXToClip(float3 pos) { return VFXTransformPositionObjectToClip(pos); }
float4 TransformPositionVFXToPreviousClip(float3 pos) { return VFXTransformPositionObjectToPreviousClip(pos); }
float4 TransformPositionVFXToNonJitteredClip(float3 pos) { return VFXTransformPositionObjectToNonJitteredClip(pos); }
float3x3 GetVFXToViewRotMatrix() { return mul(VFXGetWorldToViewRotMatrix(), (float3x3)VFXGetObjectToWorldMatrix()); }
float3 GetViewVFXPosition() { return mul(VFXGetWorldToObjectMatrix(), float4(VFXGetViewWorldPosition(), 1.0f)).xyz; }
#endif
#define VFX_SAMPLER(name) GetVFXSampler(name,sampler##name)
float4 SampleTexture(VFXSampler2D s, float2 coords)
{
return SAMPLE_TEXTURE2D(s.t, s.s, coords);
}
float4 SampleTexture(VFXSampler2DArray s, float2 coords, float slice)
{
return SAMPLE_TEXTURE2D_ARRAY(s.t, s.s, coords, slice);
}
float4 SampleTexture(VFXSampler3D s, float3 coords)
{
return SAMPLE_TEXTURE3D(s.t, s.s, coords);
}
float4 SampleTexture(VFXSamplerCube s, float3 coords)
{
return SAMPLE_TEXTURECUBE(s.t, s.s, coords);
}
#if SHADER_AVAILABLE_CUBEARRAY
float4 SampleTexture(VFXSamplerCubeArray s, float3 coords, float slice)
{
return SAMPLE_TEXTURECUBE_ARRAY(s.t, s.s, coords, slice);
}
#endif
float4 SampleTexture(VFXSampler2D s, float2 coords, float level)
{
return SAMPLE_TEXTURE2D_LOD(s.t, s.s, coords, level);
}
float4 SampleTexture(VFXSampler2DArray s, float2 coords, float slice, float level)
{
return SAMPLE_TEXTURE2D_ARRAY_LOD(s.t, s.s, coords, slice, level);
}
float4 SampleTexture(VFXSampler3D s, float3 coords, float level)
{
return SAMPLE_TEXTURE3D_LOD(s.t, s.s, coords, level);
}
float4 SampleTexture(VFXSamplerCube s, float3 coords, float level)
{
return SAMPLE_TEXTURECUBE_LOD(s.t, s.s, coords, level);
}
#if SHADER_AVAILABLE_CUBEARRAY
float4 SampleTexture(VFXSamplerCubeArray s, float3 coords, float slice, float level)
{
return SAMPLE_TEXTURECUBE_ARRAY_LOD(s.t, s.s, coords, slice, level);
}
#endif
float4 LoadTexture(VFXSampler2D s, int3 pixelCoords)
{
return s.t.Load(pixelCoords);
}
float4 LoadTexture(VFXSampler2DArray s, int4 pixelCoords)
{
return s.t.Load(pixelCoords);
}
float4 LoadTexture(VFXSampler3D s, int4 pixelCoords)
{
return s.t.Load(pixelCoords);
}
float SampleSDF(VFXSampler3D s, float3 coords, float level = 0.0f)
{
return SampleTexture(s, coords, level).x;
}
float3 SampleSDFDerivativesFast(VFXSampler3D s, float3 coords, float dist, float level = 0.0f)
{
float3 d;
// 3 taps
const float kStep = 0.01f;
d.x = SampleSDF(s, coords + float3(kStep, 0, 0));
d.y = SampleSDF(s, coords + float3(0, kStep, 0));
d.z = SampleSDF(s, coords + float3(0, 0, kStep));
return d - dist;
}
float3 SampleSDFDerivatives(VFXSampler3D s, float3 coords, float level = 0.0f)
{
float3 d;
// 6 taps
const float kStep = 0.01f;
d.x = SampleSDF(s, coords + float3(kStep, 0, 0)) - SampleSDF(s, coords - float3(kStep, 0, 0));
d.y = SampleSDF(s, coords + float3(0, kStep, 0)) - SampleSDF(s, coords - float3(0, kStep, 0));
d.z = SampleSDF(s, coords + float3(0, 0, kStep)) - SampleSDF(s, coords - float3(0, 0, kStep));
return d;
}
float GetDistanceFromSDF(VFXSampler3D s, float3 uvw, float3 extents, float level = 0.0f)
{
float3 projUVW = saturate(uvw);
float scalingFactor = max(extents.x, max(extents.y, extents.z));
float dist = SampleSDF(s, projUVW, level) * scalingFactor;
float3 absPos = abs(uvw - 0.5f);
float outsideDist = max(absPos.x, max(absPos.y, absPos.z));
if (outsideDist > 0.5f) // Check whether point is outside the box
{
float extraDist = length(extents * (uvw - projUVW) );
dist += extraDist;
}
return dist;
}
//Computes the normal of the SDF in the texture space.
float3 GetNormalFromSDF(VFXSampler3D s, float3 uvw, float level = 0.0f)
{
float3 projUVW = saturate(uvw);
float dist = SampleSDF(s, projUVW, level);
float3 absPos = abs(uvw - 0.5f);
float outsideDist = max(absPos.x, max(absPos.y, absPos.z));
float3 normal;
if (outsideDist > 0.5f) // Check whether point is outside the box
{
normal = normalize(uvw - 0.5f);
}
else
{
// compute normal
float3 dir = SampleSDFDerivatives(s, projUVW, level);
if (dist < 0)
dir = -dir;
normal = normalize(dir);
}
return normal;
}
VFXSampler2D GetVFXSampler(Texture2D t, SamplerState s)
{
VFXSampler2D vfxSampler;
vfxSampler.t = t;
vfxSampler.s = s;
return vfxSampler;
}
VFXSampler2DArray GetVFXSampler(Texture2DArray t, SamplerState s)
{
VFXSampler2DArray vfxSampler;
vfxSampler.t = t;
vfxSampler.s = s;
return vfxSampler;
}
VFXSampler3D GetVFXSampler(Texture3D t, SamplerState s)
{
VFXSampler3D vfxSampler;
vfxSampler.t = t;
vfxSampler.s = s;
return vfxSampler;
}
VFXSamplerCube GetVFXSampler(TextureCube t, SamplerState s)
{
VFXSamplerCube vfxSampler;
vfxSampler.t = t;
vfxSampler.s = s;
return vfxSampler;
}
#if SHADER_AVAILABLE_CUBEARRAY
VFXSamplerCubeArray GetVFXSampler(TextureCubeArray t, SamplerState s)
{
VFXSamplerCubeArray vfxSampler;
vfxSampler.t = t;
vfxSampler.s = s;
return vfxSampler;
}
#endif
uint ConvertFloatToSortableUint(float f)
{
int mask = (-(int)(asuint(f) >> 31)) | 0x80000000;
return asuint(f) ^ mask;
}
uint3 ConvertFloatToSortableUint(float3 f)
{
uint3 res;
res.x = ConvertFloatToSortableUint(f.x);
res.y = ConvertFloatToSortableUint(f.y);
res.z = ConvertFloatToSortableUint(f.z);
return res;
}
/////////////////////////////
// Random number generator //
/////////////////////////////
#define RAND_24BITS 0
uint VFXMul24(uint a, uint b)
{
#ifndef SHADER_API_PSSL
return (a & 0xffffff) * (b & 0xffffff); // Tmp to ensure correct inputs
#else
return Mul24(a, b);
#endif
}
uint WangHash(uint seed)
{
seed = (seed ^ 61) ^ (seed >> 16);
seed += (seed << 3);
seed = seed ^ (seed >> 4);
seed *= 0x27d4eb2d;
seed = seed ^ (seed >> 15);
return seed;
}
uint WangHash2(uint seed) // without mul on integers
{
seed += ~(seed << 15);
seed ^= (seed >> 10);
seed += (seed << 3);
seed ^= (seed >> 6);
seed += ~(seed << 11);
seed ^= (seed >> 16);
return seed;
}
// See https://stackoverflow.com/a/12996028
uint AnotherHash(uint seed)
{
#if RAND_24BITS
seed = VFXMul24((seed >> 16) ^ seed, 0x5d9f3b);
seed = VFXMul24((seed >> 16) ^ seed, 0x5d9f3b);
#else
seed = ((seed >> 16) ^ seed) * 0x45d9f3b;
seed = ((seed >> 16) ^ seed) * 0x45d9f3b;
#endif
seed = (seed >> 16) ^ seed;
return seed;
}
uint Lcg(uint seed)
{
const uint multiplier = 0x0019660d;
const uint increment = 0x3c6ef35f;
#if RAND_24BITS && defined(SHADER_API_PSSL)
return Mad24(multiplier, seed, increment);
#else
return multiplier * seed + increment;
#endif
}
float ToFloat01(uint u)
{
#if !RAND_24BITS
return asfloat((u >> 9) | 0x3f800000) - 1.0f;
#else //Using Mad24 keeping consitency between platform
return asfloat((u & 0x007fffff) | 0x3f800000) - 1.0f;
#endif
}
float Rand(inout uint seed)
{
seed = Lcg(seed);
return ToFloat01(seed);
}
float FixedRand(uint seed)
{
return ToFloat01(AnotherHash(seed));
}
///////////////////
// Mesh sampling //
///////////////////
#include "VFXMeshSampling.hlsl"
///////////////////////////
// Color transformations //
///////////////////////////
float3 HUEtoRGB(in float H)
{
float R = abs(H * 6 - 3) - 1;
float G = 2 - abs(H * 6 - 2);
float B = 2 - abs(H * 6 - 4);
return saturate(float3(R, G, B));
}
float3 RGBtoHCV(in float3 RGB)
{
float4 P = (RGB.g < RGB.b) ? float4(RGB.bg, -1.0, 2.0 / 3.0) : float4(RGB.gb, 0.0, -1.0 / 3.0);
float4 Q = (RGB.r < P.x) ? float4(P.xyw, RGB.r) : float4(RGB.r, P.yzx);
float C = Q.x - min(Q.w, Q.y);
float H = abs((Q.w - Q.y) / (6 * C + 1e-10) + Q.z);
return float3(H, C, Q.x);
}
float3 RGBtoHSV(in float3 RGB)
{
float3 HCV = RGBtoHCV(RGB);
float S = HCV.y / (HCV.z + 1e-10);
return float3(HCV.x, S, HCV.z);
}
float3 HSVtoRGB(in float3 HSV)
{
return ((HUEtoRGB(HSV.x) - 1) * HSV.y + 1) * HSV.z;
}
///////////////////
// Baked texture //
///////////////////
Texture2D bakedTexture;
SamplerState samplerbakedTexture;
float HalfTexelOffset(float f)
{
const uint kTextureWidth = 128;
float a = (kTextureWidth - 1.0f) / kTextureWidth;
float b = 0.5f / kTextureWidth;
return (a * f) + b;
}
float SnapToTexel(float f)
{
const float kInvTextureWidth = 1.0f / 128.0f;
return f - fmod(f, kInvTextureWidth) + 0.5f * kInvTextureWidth;
}
float4 SampleGradient(float2 gradientData, float u)
{
float2 uv = float2(HalfTexelOffset(saturate(u)), gradientData.x);
if (gradientData.y > 0.5f) uv.x = SnapToTexel(uv.x);
return SampleTexture(VFX_SAMPLER(bakedTexture), uv, 0);
}
float4 SampleGradient(float gradientData, float u)
{
return SampleGradient(float2(gradientData, 0.0f), u);
}
float SampleCurve(float4 curveData, float u)
{
float uNorm = (u * curveData.x) + curveData.y;
#if defined(SHADER_API_METAL)
// Workaround metal compiler crash that is caused by switch statement uint byte shift
switch (asint(curveData.w) >> 2)
#else
switch (asuint(curveData.w) >> 2)
#endif
{
case 1: uNorm = HalfTexelOffset(frac(min(1.0f - 1e-10f, uNorm))); break; // clamp end. Dont clamp at 1 or else the frac will make it 0...
case 2: uNorm = HalfTexelOffset(frac(max(0.0f, uNorm))); break; // clamp start
case 3: uNorm = HalfTexelOffset(saturate(uNorm)); break; // clamp both
}
return SampleTexture(VFX_SAMPLER(bakedTexture), float2(uNorm, curveData.z), 0)[asuint(curveData.w) & 0x3];
}
///////////
// Utils //
///////////
float4x4 VFXCreateMatrixFromColumns(float4 i, float4 j, float4 k, float4 o)
{
return float4x4(i.x, j.x, k.x, o.x,
i.y, j.y, k.y, o.y,
i.z, j.z, k.z, o.z,
i.w, j.w, k.w, o.w);
}
// Invert 3D transformation matrix (not perspective). Adapted from graphics gems 2.
// Inverts upper left by calculating its determinant and multiplying it to the symmetric
// adjust matrix of each element. Finally deals with the translation by transforming the
// original translation using by the calculated inverse.
//https://github.com/erich666/GraphicsGems/blob/master/gemsii/inverse.c
float4x4 VFXInverseTRSMatrix(float4x4 input)
{
float4x4 output = (float4x4)0;
//Fill output with cofactor
output._m00 = input._m11 * input._m22 - input._m21 * input._m12;
output._m01 = input._m21 * input._m02 - input._m01 * input._m22;
output._m02 = input._m01 * input._m12 - input._m11 * input._m02;
output._m10 = input._m20 * input._m12 - input._m10 * input._m22;
output._m11 = input._m00 * input._m22 - input._m20 * input._m02;
output._m12 = input._m10 * input._m02 - input._m00 * input._m12;
output._m20 = input._m10 * input._m21 - input._m20 * input._m11;
output._m21 = input._m20 * input._m01 - input._m00 * input._m21;
output._m22 = input._m00 * input._m11 - input._m10 * input._m01;
//Multiply by reciprocal determinant
float det = determinant((float3x3)input);
output *= rcp(det);
// Do the translation part
output._m03_m13_m23 = -mul((float3x3)output, input._m03_m13_m23);
output._m33 = 1.0f;
return output;
}
float3x3 GetScaleMatrix(float3 scale)
{
return float3x3(scale.x, 0, 0,
0, scale.y, 0,
0, 0, scale.z);
}
float3x3 GetRotationMatrix(float3 axis, float angle)
{
float2 sincosA;
sincos(angle, sincosA.x, sincosA.y);
const float c = sincosA.y;
const float s = sincosA.x;
const float t = 1.0 - c;
const float x = axis.x;
const float y = axis.y;
const float z = axis.z;
return float3x3(t * x * x + c, t * x * y - s * z, t * x * z + s * y,
t * x * y + s * z, t * y * y + c, t * y * z - s * x,
t * x * z - s * y, t * y * z + s * x, t * z * z + c);
}
float3x3 GetEulerMatrix(float3 angles)
{
float3 s, c;
sincos(angles, s, c);
return float3x3(c.y * c.z + s.x * s.y * s.z, c.z * s.x * s.y - c.y * s.z, c.x * s.y,
c.x * s.z, c.x * c.z, -s.x,
-c.z * s.y + c.y * s.x * s.z, c.y * c.z * s.x + s.y * s.z, c.x * c.y);
}
float4x4 GetTRSMatrix(float3 pos, float3 angles, float3 scale)
{
float3x3 rotAndScale = GetEulerMatrix(radians(angles));
rotAndScale = mul(rotAndScale, GetScaleMatrix(scale));
return float4x4(
float4(rotAndScale[0], pos.x),
float4(rotAndScale[1], pos.y),
float4(rotAndScale[2], pos.z),
float4(0, 0, 0, 1));
}
float4x4 GetElementToVFXMatrix(float3 axisX, float3 axisY, float3 axisZ, float3x3 rot, float3 pivot, float3 size, float3 pos)
{
float3x3 rotAndScale = GetScaleMatrix(size);
rotAndScale = mul(rot, rotAndScale);
rotAndScale = mul(transpose(float3x3(axisX, axisY, axisZ)), rotAndScale);
pos -= mul(rotAndScale, pivot);
return float4x4(
float4(rotAndScale[0], pos.x),
float4(rotAndScale[1], pos.y),
float4(rotAndScale[2], pos.z),
float4(0, 0, 0, 1));
}
float4x4 GetElementToVFXMatrix(float3 axisX, float3 axisY, float3 axisZ, float3 angles, float3 pivot, float3 size, float3 pos)
{
float3x3 rot = GetEulerMatrix(radians(angles));
return GetElementToVFXMatrix(axisX, axisY, axisZ, rot, pivot, size, pos);
}
// VFXToMatrix for normals (with invert size). TODO Should use inverse transpose but it only works for orthonormal basis atm
float3x3 GetElementToVFXMatrixNormal(float3 axisX, float3 axisY, float3 axisZ, float3 angles, float3 size)
{
return (float3x3)GetElementToVFXMatrix(axisX, axisY, axisZ, angles, float3(0, 0, 0), rcp(size), float3(0, 0, 0));
}
float4x4 GetVFXToElementMatrix(float3 axisX, float3 axisY, float3 axisZ, float3 angles, float3 pivot, float3 size, float3 pos)
{
float3x3 rotAndScale = float3x3(axisX, axisY, axisZ); // Works only for orthonormal basis
rotAndScale = mul(transpose(GetEulerMatrix(radians(angles))), rotAndScale);
rotAndScale = mul(GetScaleMatrix(rcp(size)), rotAndScale);
pos = pivot - mul(rotAndScale, pos);
return float4x4(
float4(rotAndScale[0], pos.x),
float4(rotAndScale[1], pos.y),
float4(rotAndScale[2], pos.z),
float4(0, 0, 0, 1));
}
float3 VFXSafeNormalize(float3 v)
{
float sqrLength = max(VFX_FLT_MIN, dot(v, v));
return v * rsqrt(sqrLength);
}
float3 VFXSafeNormalizedCross(float3 v1, float3 v2, float3 fallback)
{
float3 outVec = cross(v1, v2);
outVec = dot(outVec, outVec) < VFX_EPSILON ? fallback : normalize(outVec);
return outVec;
}
/////////////////////
// flipbooks utils //
/////////////////////
struct VFXUVData
{
float4 uvs;
float blend;
float4 mvs;
};
float4 SampleTexture(VFXSampler2D s, VFXUVData uvData)
{
float4 s0 = SampleTexture(s, uvData.uvs.xy + uvData.mvs.xy);
float4 s1 = SampleTexture(s, uvData.uvs.zw + uvData.mvs.zw);
return lerp(s0, s1, uvData.blend);
}
float4 SampleTexture(VFXSampler2DArray s, VFXUVData uvData) //For flipbook in array layout
{
float4 s0 = SampleTexture(s, uvData.uvs.xy + uvData.mvs.xy, uvData.uvs.z);
float4 s1 = SampleTexture(s, uvData.uvs.xy + uvData.mvs.zw, uvData.uvs.w);
return lerp(s0, s1, uvData.blend);
}
float3 SampleNormalMap(VFXSampler2D s, VFXUVData uvData)
{
float4 packedNormal = SampleTexture(s, uvData);
packedNormal.w *= packedNormal.x;
float3 normal;
normal.xy = packedNormal.wy * 2.0 - 1.0;
normal.z = sqrt(1.0 - saturate(dot(normal.xy, normal.xy)));
return normal;
}
float3 SampleNormalMap(VFXSampler2DArray s, VFXUVData uvData)
{
float4 packedNormal = SampleTexture(s, uvData);
packedNormal.w *= packedNormal.x;
float3 normal;
normal.xy = packedNormal.wy * 2.0 - 1.0;
normal.z = sqrt(1.0 - saturate(dot(normal.xy, normal.xy)));
return normal;
}
float2 GetSubUV(int flipBookIndex, float2 uv, float2 dim, float2 invDim)
{
float2 tile = float2(fmod(flipBookIndex, dim.x), dim.y - 1.0 - floor(flipBookIndex * invDim.x));
return (tile + uv) * invDim;
}
VFXUVData GetUVData(float2 uv) // no flipbooks
{
VFXUVData data = (VFXUVData)0;
data.uvs.xy = uv;
return data;
}
VFXUVData GetUVData(float2 flipBookSize, float2 invFlipBookSize, float2 uv, float texIndex) // with flipbooks
{
VFXUVData data = (VFXUVData)0;
float frameBlend = frac(texIndex);
float frameIndex = texIndex - frameBlend;
data.uvs.xy = GetSubUV(frameIndex, uv, flipBookSize, invFlipBookSize);
#if USE_FLIPBOOK_INTERPOLATION
data.uvs.zw = GetSubUV(frameIndex + 1, uv, flipBookSize, invFlipBookSize);
data.blend = frameBlend;
#endif
return data;
}
VFXUVData GetUVData(float flipBookSize, float2 uv, float texIndex) // with flipbooks array layout (flipBookSize is a single float)
{
VFXUVData data = (VFXUVData)0;
texIndex = fmod(texIndex, flipBookSize);
float frameBlend = frac(texIndex);
float frameIndex = texIndex - frameBlend;
data.uvs.xyz = float3(uv, frameIndex);
#if USE_FLIPBOOK_INTERPOLATION
data.uvs.w = fmod(frameIndex + 1, flipBookSize);
data.blend = frameBlend;
#endif
return data;
}
VFXUVData GetUVData(float2 flipBookSize, float2 uv, float texIndex)
{
return GetUVData(flipBookSize, 1.0f / flipBookSize, uv, texIndex);
}
///////////
// Noise //
///////////
#include "VFXNoise.hlsl"
////////////
// Strips //
////////////
#include "VFXParticleStripCommon.hlsl"