// 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 FIXED_RAND_INT(h) AnotherHash(particleId ^ asuint(systemSeed) ^ h) #define VFXRAND Rand(attributes.seed) #define VFXRAND2 float2(VFXRAND,VFXRAND) #define VFXRAND3 float3(VFXRAND,VFXRAND,VFXRAND) #define VFXRAND4 float4(VFXRAND,VFXRAND,VFXRAND,VFXRAND) #define VFXFIXED_RAND(h) FixedRand(attributes.particleId ^ asuint(systemSeed) ^ h) #define VFXFIXED_RAND2(h) float2(VFXFIXED_RAND(h),VFXFIXED_RAND(h)) #define VFXFIXED_RAND3(h) float3(VFXFIXED_RAND(h),VFXFIXED_RAND(h),VFXFIXED_RAND(h)) #define VFXFIXED_RAND4(h) float4(VFXFIXED_RAND(h),VFXFIXED_RAND(h),VFXFIXED_RAND(h),VFXFIXED_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 #define VFX_INFINITY (1.0f/0.0f) #define VFX_NAN asfloat(~0u) #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 #define VFXGradient float3 #define VFXCurve float4 struct VFXSampler2D { Texture2D t; SamplerState s; }; struct VFXSampler2DArray { Texture2DArray t; SamplerState s; }; struct VFXSampler3D { Texture3D t; SamplerState s; }; struct VFXSamplerCube { TextureCube t; SamplerState s; }; //Warning: this define 'SHADER_AVAILABLE_CUBEARRAY' relies on '#pragma require cubearray' #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); } float3 TransformPreviousVFXPositionToWorld(float3 pos) { return 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); } float3 TransformPreviousVFXPositionToWorld(float3 pos) { return VFXTransformPreviousObjectToWorld(pos); } float3x3 GetVFXToViewRotMatrix() { return mul(VFXGetWorldToViewRotMatrix(), (float3x3)VFXGetObjectToWorldMatrix()); } float3 GetViewVFXPosition() { return mul(VFXGetWorldToObjectMatrix(), float4(VFXGetViewWorldPosition(), 1.0f)).xyz; } #endif 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; } float3 GetViewOrRayDirection(float3 position) { #if defined(SHADER_STAGE_RAY_TRACING) #if SHADERPASS != SHADERPASS_RAYTRACING_VISIBILITY //Is only really correct for mirror reflections float3 camPos = GetViewVFXPosition(); float camToOrigin = length(camPos - ObjectRayOrigin()); float3 virtualOrigin = ObjectRayOrigin() - camToOrigin * ObjectRayDirection(); return -normalize(position - virtualOrigin); #else return normalize(ObjectRayDirection()); #endif #else return GetVFXToViewRotMatrix()[2]; #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 SampleSDFDerivativesFastComplete(VFXSampler3D s, float3 coords, float3 uvStep, float dist) { float3 d; // 3 taps d.x = SampleSDF(s, coords + float3(uvStep.x, 0, 0)); d.y = SampleSDF(s, coords + float3(0, uvStep.y, 0)); d.z = SampleSDF(s, coords + float3(0, 0, uvStep.z)); return d - dist; } 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; } //Sample derivatives with a step size derived from the texture dimensions. float3 SampleSDFUnscaledDerivatives(VFXSampler3D s, float3 coords, float3 uvStep, float level = 0.0f) { float3 d; // 6 taps d.x = SampleSDF(s, coords + float3(uvStep.x, 0, 0)) - SampleSDF(s, coords - float3(uvStep.x, 0, 0)); d.y = SampleSDF(s, coords + float3(0, uvStep.y, 0)) - SampleSDF(s, coords - float3(0, uvStep.y, 0)); d.z = SampleSDF(s, coords + float3(0, 0, uvStep.z)) - SampleSDF(s, coords - float3(0, 0, uvStep.z)); 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 = VFXSafeNormalize(uvw - 0.5f); } else { // compute normal float3 dir = SampleSDFDerivatives(s, projUVW, level); if (dist < 0) dir = -dir; normal = VFXSafeNormalize(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(float3 gradientData, float u) { float2 uv = float2(HalfTexelOffset(saturate(u)), gradientData.x); if (gradientData.y > 0.5f) uv.x = SnapToTexel(uv.x); float4 gradientResult = SampleTexture(VFX_SAMPLER(bakedTexture), uv, 0); gradientResult.rgb *= gradientData.z; return gradientResult; } float4 SampleGradient(float2 gradientData, float u) { return SampleGradient(float3(gradientData, 1.0f), u); } float4 SampleGradient(float gradientData, float u) { return SampleGradient(float2(gradientData, 0.0f), u); } float SampleCurve(float4 curveData, float u) { float invScaleU = f16tof32(asuint(curveData.x)); float scaledStart = f16tof32(asuint(curveData.x) >> 16); float uNorm = (u * invScaleU) + scaledStart; #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 curveData.y * SampleTexture(VFX_SAMPLER(bakedTexture), float2(uNorm, curveData.z), 0)[asuint(curveData.w) & 0x3]; } float RemapCurve(float4 curveData, float u, float t) { float startInt, endInt; float startFrac = modf(u, startInt); float endFrac = modf(u + t, endInt); return SampleCurve(curveData, endFrac) - SampleCurve(curveData, startFrac) + endInt - startInt; } /////////// // 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); } float4 VFXGetColumnFromMatrix(float4x4 mat, int column) { return transpose(mat)[column]; } float4x4 VFXCreateMatrixFromRows(float4 i, float4 j, float4 k, float4 o) { return float4x4(i, j, k, o); } float4 VFXGetRowFromMatrix(float4x4 mat, int column) { return mat[column]; } // 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); const bool degenerate = (det * det) < 1e-25 ; //Condition consistent with C++ InvertMatrix4x4_General3D() output *= degenerate ? 0.0f : rcp(det) ; // Do the translation part output._m03_m13_m23 = -mul((float3x3)output, input._m03_m13_m23); output._m33 = degenerate ? 0.0f : 1.0f; return output; } float3x3 GetScaleMatrix(float3 scale) { return float3x3(scale.x, 0, 0, 0, scale.y, 0, 0, 0, scale.z); } float4x4 GetScaleMatrix44(float3 scale) { return float4x4(scale.x, 0, 0, 0, 0, scale.y, 0, 0, 0, 0, scale.z, 0, 0, 0, 0, 1); } 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)); } ///////////////////// // flipbooks utils // ///////////////////// struct VFXUVData { float4 uvs; float blend; float4 mvs; }; float4 SampleTexture(VFXSampler2D s, VFXUVData uvData) { #if USE_FLIPBOOK_INTERPOLATION 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); #else return SampleTexture(s, uvData.uvs.xy); #endif } 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, float texIndexBlend) // 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 + texIndexBlend, uv, flipBookSize, invFlipBookSize); data.blend = frameBlend; #endif return data; } VFXUVData GetUVData(float2 flipBookSize, float2 invFlipBookSize, float2 uv, float texIndex) { return GetUVData(flipBookSize, invFlipBookSize, uv, texIndex, 1.0f); } VFXUVData GetUVData(float flipBookSize, float2 uv, float texIndex, float texIndexBlend) // 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 = frameIndex + texIndexBlend; data.blend = frameBlend; #endif return data; } VFXUVData GetUVData(float flipBookSize, float2 uv, float texIndex) { return GetUVData(flipBookSize, uv, texIndex, 1.0f); } VFXUVData GetUVData(float2 flipBookSize, float2 uv, float texIndex, float texIndexBlend) { return GetUVData(flipBookSize, 1.0f / flipBookSize, uv, texIndex, texIndexBlend); } VFXUVData GetUVData(float2 flipBookSize, float2 uv, float texIndex) { return GetUVData(flipBookSize, uv, texIndex, 1.0f); } ////////////////// // Orient Utils // ////////////////// void GetCameraPlaneFacingAxes(float3x3 viewRot, inout float3 axisX, inout float3 axisY, inout float3 axisZ) { axisX = viewRot[0].xyz; axisY = viewRot[1].xyz; axisZ = -viewRot[2].xyz; } #if defined(SHADER_STAGE_RAY_TRACING) void GetRayFacingAxes(float3x3 viewRot, float3 position, float3 worldUp, inout float3 axisX, inout float3 axisY, inout float3 axisZ) { axisZ = -GetViewOrRayDirection(position); #if SHADERPASS != SHADERPASS_RAYTRACING_VISIBILITY axisX = VFXSafeNormalizedCross(worldUp, axisZ, float3(1,0,0)); #else axisX = VFXSafeNormalizedCross(viewRot[1].xyz, axisZ, float3(1,0,0)); #endif axisY = cross(axisZ,axisX); } #endif void GetCameraPlaneOrRayFacingAxes(float3x3 viewRot, float3 position, float3 worldUp, inout float3 axisX, inout float3 axisY, inout float3 axisZ) { #if defined(SHADER_STAGE_RAY_TRACING) GetRayFacingAxes(viewRot, position, worldUp, axisX, axisY, axisZ); #else GetCameraPlaneFacingAxes(viewRot, axisX, axisY, axisZ); #endif } void GetCameraPositionFacingAxes(float3x3 viewRot, float3 position, inout float3 axisX, inout float3 axisY, inout float3 axisZ) { axisZ = normalize(position - GetViewVFXPosition()); axisX = VFXSafeNormalizedCross(viewRot[1].xyz, axisZ, float3(1,0,0)); axisY = cross(axisZ,axisX); } void GetCameraPositionOrRayFacingAxes(float3x3 viewRot, float3 position, float3 worldUp, inout float3 axisX, inout float3 axisY, inout float3 axisZ) { #if defined(SHADER_STAGE_RAY_TRACING) GetRayFacingAxes(viewRot, position, worldUp, axisX, axisY, axisZ); #else GetCameraPositionFacingAxes(viewRot, position, axisX, axisY, axisZ); #endif } //////////////// // Prefix Sum // //////////////// //Binary search in Inclusive Prefix sum //Returns the index of the category between startIndex (included) and endIndex (excluded) where value lands. //If value exceeds the total capacity of the list, the function will return endIndex and remainder will be the amount exceeding //Optionally, it can return the remainder of the value compared to its category uint BinarySearchPrefixSum(uint value, StructuredBuffer prefixSum,uint startIndex, uint endIndex, out uint remainder) { uint left = startIndex; uint right = endIndex - 1; while (left < right) { uint center = (left + right) / 2; if (value < prefixSum[center]) { right = center; } else { left = center + 1; } } uint index = left; uint prevValue = 0; [branch] if (index > startIndex) { prevValue = prefixSum[index - 1]; } remainder = value - prevValue; return index; } uint BinarySearchPrefixSum(uint value, StructuredBuffer prefixSum, uint startIndex, uint endIndex) { uint remainder; return BinarySearchPrefixSum(value, prefixSum, startIndex, endIndex, remainder); } ///////////////////// // Thread indexing // ///////////////////// #ifdef NB_THREADS_PER_GROUP uint GetThreadId(uint3 groupId, uint3 groupThreadId, uint dispatchWidth) { return groupThreadId.x + groupId.x * NB_THREADS_PER_GROUP + groupId.y * dispatchWidth * NB_THREADS_PER_GROUP; } #endif /////////// // Noise // /////////// #include "VFXNoise.hlsl" ////////////////////// // Instancing Utils // ////////////////////// #include "VFXInstancing.hlsl" //////////// // Strips // //////////// #include "VFXParticleStripCommon.hlsl" //////////////////////////// // Bounds reduction utils // //////////////////////////// #include "VFXBoundsUtils.hlsl" /////////////////////////// // Shape Distances Utils // /////////////////////////// #include "VFXShapes.hlsl"